Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Pandoc fancy-lists #2418

Closed
SuibianP opened this issue Jul 18, 2024 · 21 comments · Fixed by #2455
Closed

Support Pandoc fancy-lists #2418

SuibianP opened this issue Jul 18, 2024 · 21 comments · Fixed by #2455
Labels
P: maybe Pending approval of low priority request. S: triage Issue needs triage. T: feature Feature.

Comments

@SuibianP
Copy link
Contributor

Description

Some aspects of Pandoc’s Markdown fancy lists are also accepted in org input, mimicking the option org-list-allow-alphabetical in Emacs. As in Org Mode, enabling this extension allows lowercase and uppercase alphabetical markers for ordered lists to be parsed in addition to arabic ones. Note that for Org, this does not include roman numerals or the # placeholder that are enabled by the extension in Pandoc’s Markdown.
The fancy_lists extension also allows ‘#’ to be used as an ordered list marker in place of a numeral:

#. one
#. two

Note: the ‘#’ ordered list marker doesn’t work with commonmark.

Benefits

This would allow using roman numerals and alphabets for ordered list bullets, without having to specify type or list-style-type, which is quite common for nested lists.

Solution Idea

Another extension to parse additional bullet types besides numbers.

@SuibianP SuibianP added the T: feature Feature. label Jul 18, 2024
@gir-bot gir-bot added the S: triage Issue needs triage. label Jul 18, 2024
@facelessuser
Copy link
Owner

While it is an interesting idea, it is not likely something I would use. Pydown Extensions is not meant to be a one-stop shop for all Python Markdown extensions, so I am often very selective about what I add. Generally, if I am to maintain an extension, it is usually one I am interested in personally using as well. In short, I need to be invested in the extension for me to take on supporting it.

Let me sit on this and think about it. It is possible already to wrap blocks in a div with a special class that can use CSS to target them and change the style, but I do get that you want a more convenient approach. I would just need to decide if this is something I'm willing to get behind and take on long term maintenance of.

@gir-bot add P: maybe

@gir-bot gir-bot added the P: maybe Pending approval of low priority request. label Jul 18, 2024
@facelessuser
Copy link
Owner

facelessuser commented Sep 17, 2024

I'm exploring the possibility via prototype, but I am not sure if I'm all in yet.

One thing to note, this behaves very Pandoc-like currently in that:

  • It supports lists of type #., 1., a., i., #), 1), a), i), (#), (1), (a), and (i). Also capitalized versions.
  • Each list type is treated as its own list type, both uppercase and lowercase are treated unique. If starting a new list type, a new list is created and not appended to the previous list.
  • The number (or symbol) indicating the start of the list is taken into account and the list will start at that value.
  • pymdownx.saneheaders is required to be enabled for # style lists to work as otherwise they will be identified as headers.
  • I'm not sure if I'm 100% sold on () style lists or # style lists, but implemented everything to understand how it would behave.
  • Alpha lists are currently contained to a and do not allow aa.
  • Obviously, there are rules to determine when some roman numerals are assumed roman numerals or alpha lists. Generally new lists are determined to be roman if they start with i or I or are wider than one character.
  • Roman numerals are checked for validity and are ignored if they are not valid.
  • NONE OF THIS IS STRICTLY TESTED CURRENTLY. I've made assertions above, but I have not extensively tested any of this.
  • Lastly, all of this is subject to change if/when I decide to support this.

Here is the prototype: https://gist.github.com/facelessuser/a6613237425b78e843c32268ef464e2e

@facelessuser
Copy link
Owner

Linking another recent discussion: #2454.

@facelessuser
Copy link
Owner

Updated prototype to drop (marker) format. I don't feel that complicating patterns to try and support this when even CommonMark doesn't support it. CommonMark only supports 1. and 1). Python Markdown is not a CommonMark parser, but if they don't even support that, and there is little to no added benefit in doing so except yet another list format, so I'm not going to bother.

I also updated the prototype to follow the Pandoc rule of requiring uppercase, single letter list markers to need at least two spaces after the marker. I would rather keep this rule (which I am sure was added for some reason) and possibly relax it in the future if sufficient testing deemed it unnecessary.

@facelessuser
Copy link
Owner

Also fixed some bugs

@facelessuser
Copy link
Owner

I should note that #. and #) are also unique formats, but I may keep them if I move forward with this. I can see the usefulness of generic, numerical list markers.

@facelessuser
Copy link
Owner

This is what I'm thinking so far. By default, FancyList would extend list formats such that 1. and 1) would work. These formats would be added with functionality similar to Sane Lists but with the added behavior that swapping list types 1. vs 1) would force a new list.

All other formats are probably not supported syntactically in many editors. It's possible not everyone wants such behavior, and might actually control this automatically with CSS when lists are nested, but that's okay. I think additional list formats would be opt-in. You could enable one or all of them if you desire.

Someone using MkDocs might do this to enable all formats; decimal cannot be toggled and is always enabled.

markdown_extensions:
  - pymdownx.fancylists:
      addtional_ordered_styles:
      - alpha
      - roman
      - generic

@facelessuser
Copy link
Owner

Okay, I ended up leaving all the list types enabled by default. Instead, people can opt out of certain list formats.

I have PR with testing available here: #2455

@facelessuser
Copy link
Owner

Okay, I think I may be at a point where I am ready to stop fiddling. There are two inherient conflicts that exist when both alphabetically ordered and Roman numeral ordered lists are enabled.

Alphabetical lists cannot start/restart a list with I (or with the lowercase) and Roman numeral lists cannot start/restart a list with M, D, C, L, X, and V (or the lowercase).

This issue also exists in Pandoc, but mitigation is fairly straight forward. We relax the Roman numerals a little and the use can use things like VIIIII for X etc. Browsers won't render the list with VIIIII, but will render it more strictly as X. I think this is a reasonable work around.

viiiii. item 10
xi. item 11
<ol start="10" type="i">
<li>item 10</li>
<li>item 11</li>
</ol>

Alphabetical lists don't have such clean mitigation, but if you have the HTML Block extension enabled, you can work around the I case pretty easily. You could use this approach for the above Roman numeral case as well and use the more proper numerals.

/// html | ol[start="9"][type="a"]
i. item i
j. item j
///
<ol start="9" type="a">
<li>item i</li>
<li>item j</li>
</ol>

While maybe not as clean as the the Roman numeral case, it works fine and this case won't likely occur all that often. Pandoc has the same issue, but I don't know if they have a workaround.

Some may assume you can do the following while using md_in_html, but it doesn't work so well based on how md_in_html handles the elements in the HTML tree. So this doesn't work:

<ol start="9" type="i" markdown>
i. item i
j. item j
</ol>

You get something more like this, which is not desirable:

<ol start="9" type="i">
<ol type="i">
<li>item i</li>
</ol>
<ol start="10" type="a">
<li>item j</li>
</ol>
</ol>

@facelessuser
Copy link
Owner

I think I'm now open to people willing to test the PR and give feedback: #2455.

@facelessuser
Copy link
Owner

Apparently, I implemented # lists wrong. It appears they should take on the style of whatever list they are nested under, and if they are in an ambiguous list, they assume normal numbers. I will have to adjust that behavior.

@facelessuser
Copy link
Owner

facelessuser commented Sep 19, 2024

# now behaves as expected.

@facelessuser
Copy link
Owner

Okay, I added a more targeted workaround to handle alpha vs Roman numeral conflicts. While the HTML Block approach seemed to work at first glance, more complex cases showed that the parser was confused a bit while trying to process child list items from inside an already existing ordered list element.

So now, if you have both alphabetic and Roman numeral lists enabled together, and you have to restart a list with a value that is ambiguous, such as I at the start of an alphabetic list, you can just wrap it like so and the first list time will force the creation of an alphabetic list.

/// fancylists | type=a
i. item i
j. item j
///

Of course, if you only have alphabetic or Roman enabled, there are no conflicts.

I believe all corner cases and mitigations have finally been solved.

@facelessuser
Copy link
Owner

facelessuser commented Sep 20, 2024

I've added an inject_style option. CSS is still lacking the case-sensitive flag for attribute selectors in many browsers which can make overriding some CSS that is already styling lists very difficult. inject_style will force the list-style-type into ol tags if enabled.

@joapuiib
Copy link
Contributor

joapuiib commented Sep 20, 2024

I'm having trouble with styling different list styles because of that reason.

Using a parenthesis instead of a dot in lower-alpha lists also affect upper-alpha.

.md-typeset ol[type="a"] li::marker {
    content: counter(list-item, lower-alpha) ") ";
}

Would inject_style help solve this issue?

I assume it would look something like:

.md-typeset ol[style="list-style-type: lower-alpha;"] li::marker {
    content: counter(list-item, lower-alpha) ") ";
}

In that case, wouldn't be easier to inject a class and then use it in CSS?

@facelessuser
Copy link
Owner

Using a parenthesis instead of a dot in lower-alpha lists also affect upper-alpha.

Yes, this occurs because only Firefox supports case-sensitive attribute selectorsol[type="a" s]. I have no idea why others haven't jumped on this yet.

Would inject_style help solve this issue?

No, all it does is this.

<ol style="list-style-type: lower-roman;" type="i">
<li>Item i</li>
</ol>

It works for ensuring the browser renders the lists with the default style for such lists, even when there is other CSS trying to set it to something else. Browsers understand the case sensitivity of the type parameter, and it works properly when there is no CSS mucking it up, but attribute selectors are just worthless for targeting them properly until all the browsers finish implementing the spec and add support for the s flag.

In that case, wouldn't be easier to inject a class and then use it in CSS?

The above is easier for the average user as no additional CSS is required from them. I can add an option to inject classes if that is what you desire. Your case is more of a niche case. Most people aren't trying to change the default styling for a list type, but I could certainly facilitate it due to the lack of useful selectors currently in browsers. If I do, I would simply add a class on the ol element that indicates the type, probably fancylists-decimal, fancylists-upper-alpha, fancylists-lower-alpha, etc.

@facelessuser
Copy link
Owner

I've also added an option to inject CSS classes. That should satisfy everyone. Those who just want the lists to work can inject styles if they aren't working. Those who want fine control over the lists can inject classes.

@joapuiib
Copy link
Contributor

joapuiib commented Sep 20, 2024

Would inject_style help solve this issue?

Sorry for my phrasing. I meant it would help to solve the issue of selecting each type of list, making it easier to override CSS.

hose who just want the lists to work can inject styles if they aren't working.

I haven't thought of the idea of browsers not rendering lists correctly.

I've also added an option to inject CSS classes. That should satisfy everyone. Those who just want the lists to work can inject styles if they aren't working. Those who want fine control over the lists can inject classes.

Thanks! In my particular case, it helps a lot! 😄

@facelessuser
Copy link
Owner

I haven't thought of the idea of browsers not rendering lists correctly.

I probably phrased this poorly, but as an example, what i mean is like with Mkdocs Material which has preset styles for tiers of lists. A user enabling this plugin just wants them to do what they think they should. As you've seen, just applying CSS to override can be difficult. So inject styles fixes the issue completely.

Injecting styles doesn't fix the problem of CSS targeting for more advance styling, but injecting classes does.

@joapuiib
Copy link
Contributor

inject-class option appends a semicolon ; at the end of the class:

3. List item number
4. List item number
    a. List item letter
    b. List item letter
        i. List item roman
        ii. List item roman

Will prodce:

<ol class="fancylists-decimal;" start="3" type="1">
  <li>List item number</li>
  <li>List item number
  <ol class="fancylists-lower-alpha;" type="a">
    <li>List item letter</li>
      <li>List item letter
          <ol class="fancylists-lower-roman;" type="i">
          <li>List item roman</li>
          <li>List item roma</li>
        </ol>
      </li>
    </ol>
  </li>
</ol>

@joapuiib
Copy link
Contributor

I opened a PR that removes the semicolon: #2464

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P: maybe Pending approval of low priority request. S: triage Issue needs triage. T: feature Feature.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants