From f514f7876f980d0b4f6aea270fb39d6e4e7cfe5e Mon Sep 17 00:00:00 2001 From: Evan Silberman Date: Tue, 9 Dec 2025 18:26:19 -0800 Subject: [PATCH] HTML writer: support parenthesis list delimeters Current browsers support defining custom @counter-styles to be used as list-style-type values for lists. This change adds rules to the default HTML styles, as needed, to support lists using the OneParen or TwoParens style. The type="1" (etc.) attribute is retained, which means the browser should do the next-best thing if the @counter-style rule goes missing in somebody's workflow. The custom @counter-styles will not be used in markup written without a template. ("Is there a template at all" doesn't actualy answer the question "will the styles.html partial emit the @counter-styles like we expect" but we resort to this sort of thing in other places.) This change unconditionally, and arguably redundantly, adds style="list-style-type: decimal" (or "lower-alpha", etc.) to
    elements where it didn't appear before, including in non-standalone output. --- data/templates/styles.html | 7 ++ src/Text/Pandoc/Writers/HTML.hs | 58 ++++++++++++----- test/command/10328.md | 4 +- test/command/11335.md | 109 ++++++++++++++++++++++++++++++++ test/command/5627.md | 6 +- test/command/9042.md | 2 +- test/command/tasklist.md | 2 +- test/writer.html4 | 23 +++++-- test/writer.html5 | 49 +++++++++----- 9 files changed, 215 insertions(+), 45 deletions(-) create mode 100644 test/command/11335.md diff --git a/data/templates/styles.html b/data/templates/styles.html index 800f63c7a6a5..9822213625f7 100644 --- a/data/templates/styles.html +++ b/data/templates/styles.html @@ -210,3 +210,10 @@ $if(csl-css)$ $styles.citations.html()$ $endif$ +$for(counter-styles)$ +@counter-style $it.name$ { + system: extends $it.extends$; + prefix: "$it.prefix$"; + suffix: "$it.suffix$"; +} +$endfor$ diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index 2b4cfc5aac38..9e78771d4691 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -39,7 +39,7 @@ import Data.List (intercalate, intersperse, partition, delete, (\\)) import qualified Data.List as L import Data.List.NonEmpty (NonEmpty((:|))) import Data.Containers.ListUtils (nubOrd) -import Data.Maybe (fromMaybe, isJust, isNothing) +import Data.Maybe (fromMaybe, isJust, isNothing, mapMaybe) import qualified Data.Set as Set import Data.Text (Text) import qualified Data.Text as T @@ -85,6 +85,8 @@ import Text.XML.Light (elChildren, unode, unqual) import qualified Text.XML.Light as XML import Text.XML.Light.Output import Data.String (fromString) +import Data.Map.Strict (Map) +import qualified Data.Map.Strict as Map data WriterState = WriterState { stNotes :: [Html] -- ^ List of notes @@ -102,6 +104,7 @@ data WriterState = WriterState , stCsl :: Bool -- ^ Has CSL references , stCslEntrySpacing :: Maybe Int -- ^ CSL entry spacing , stBlockLevel :: Int -- ^ Current block depth, excluding section divs + , stCounterStyles :: Set.Set (ListNumberStyle, ListNumberDelim) -- ^ List styles used in this document } defaultWriterState :: WriterState @@ -119,7 +122,8 @@ defaultWriterState = WriterState {stNotes= [], stCodeBlockNum = 0, stCsl = False, stCslEntrySpacing = Nothing, - stBlockLevel = 0} + stBlockLevel = 0, + stCounterStyles = Set.empty} -- Helpers to render HTML with the appropriate function. @@ -356,6 +360,16 @@ pandocToHtml opts (Pandoc meta blocks) = do _ -> mempty let mCss :: Maybe [Text] = lookupContext "css" metadata + let counterStyle :: ListNumberStyle -> ListNumberDelim -> Maybe (Map Text Text) + counterStyle _ DefaultDelim = Nothing + counterStyle _ Period = Nothing + counterStyle num del = Just $ Map.fromList [ + ("name", (counterStyleName num del)), + ("extends", (camelCaseToHyphenated $ tshow num)), + ("prefix", case del of + OneParen -> "" + TwoParens -> "("), + ("suffix", ")") ] let context :: Context Text context = (if stHighlighting st then case writerHighlightMethod opts of @@ -461,6 +475,7 @@ pandocToHtml opts (Pandoc meta blocks) = do defField "s5-url" ("s5/default" :: Doc Text) . defField "table-caption-below" (writerTableCaptionPosition opts == CaptionBelow) . + defField "counter-styles" (mapMaybe (uncurry counterStyle) (Set.toList $ stCounterStyles st)) . defField "html5" (stHtml5 st) $ metadata return (thebody, context) @@ -1025,26 +1040,28 @@ blockToHtmlInner opts (BulletList lst) = do contents <- mapM (listItemToHtml opts) lst (if isJust (mapM toTaskListItem lst) then (! A.class_ "task-list") else id) <$> unordList opts contents -blockToHtmlInner opts (OrderedList (startnum, numstyle, _) lst) = do +blockToHtmlInner opts (OrderedList (startnum, numstyle, delstyle) lst) = do contents <- mapM (listItemToHtml opts) lst html5 <- gets stHtml5 - let numstyle' = case numstyle of - Example -> "decimal" - _ -> camelCaseToHyphenated $ tshow numstyle + modify (\st -> st{stCounterStyles = Set.insert (numstyle, delstyle) (stCounterStyles st)}) + let counterStyle = case writerTemplate opts of + Nothing -> case numstyle of + Example -> "decimal" + _ -> camelCaseToHyphenated $ tshow numstyle + Just _ -> counterStyleName numstyle delstyle let attribs = [A.start $ toValue startnum | startnum /= 1] ++ [A.class_ "example" | numstyle == Example] ++ (if numstyle /= DefaultStyle - then if html5 - then [A.type_ $ - case numstyle of - Decimal -> "1" - LowerAlpha -> "a" - UpperAlpha -> "A" - LowerRoman -> "i" - UpperRoman -> "I" - _ -> "1"] - else [A.style $ toValue $ "list-style-type: " <> - numstyle'] + then [A.style $ toValue $ "list-style-type: " <> counterStyle] ++ + if html5 then [A.type_ $ + case numstyle of + Decimal -> "1" + LowerAlpha -> "a" + UpperAlpha -> "A" + LowerRoman -> "i" + UpperRoman -> "I" + _ -> "1"] + else [] else []) l <- ordList opts contents return $ L.foldl' (!) l attribs @@ -1713,6 +1730,12 @@ inDiv cls x = do isRef :: Text -> Bool isRef t = "\\ref{" `T.isPrefixOf` t || "\\eqref{" `T.isPrefixOf` t +counterStyleName :: ListNumberStyle -> ListNumberDelim -> Text +counterStyleName Example _ = "decimal" +counterStyleName num DefaultDelim = camelCaseToHyphenated $ tshow num +counterStyleName num Period = camelCaseToHyphenated $ tshow num +counterStyleName num del = mconcat [camelCaseToHyphenated $ tshow num, "-", camelCaseToHyphenated $ tshow del] + isMathEnvironment :: Text -> Bool isMathEnvironment s = "\\begin{" `T.isPrefixOf` s && envName `elem` mathmlenvs @@ -1795,3 +1818,4 @@ hasVariable var = checkVar checkVar (DT.Concat t1 t2) = checkVar t1 || checkVar t2 checkVar (DT.Literal _) = False checkVar DT.Empty = False + diff --git a/test/command/10328.md b/test/command/10328.md index cdd379701651..19e3abbaf503 100644 --- a/test/command/10328.md +++ b/test/command/10328.md @@ -20,7 +20,7 @@ Unwrap divs if they only have the `nonincremental` or `incremental` classes. ^D

    First slide

    -
      +
      1. Note 1
      2. Note 2
      3. Note 3
      4. @@ -28,7 +28,7 @@ Unwrap divs if they only have the `nonincremental` or `incremental` classes.

    Second Slide

    -
      +
      1. Note 1
      2. Note 2
      3. Note 3
      4. diff --git a/test/command/11335.md b/test/command/11335.md new file mode 100644 index 000000000000..883f2711cd2e --- /dev/null +++ b/test/command/11335.md @@ -0,0 +1,109 @@ +Without fancy_lists, we get the Default counter styles + +``` +% pandoc -t native -f markdown_strict +1. A +2. B + +(a) A +(b) B +^D +[ OrderedList + ( 1 , DefaultStyle , DefaultDelim ) + [ [ Plain [ Str "A" ] ] , [ Plain [ Str "B" ] ] ] +, Para + [ Str "(a)" + , Space + , Str "A" + , SoftBreak + , Str "(b)" + , Space + , Str "B" + ] +] +``` + +and thus as HTML we don't have `style` or `type` in the `
          `: + +``` +% pandoc -t html -f markdown_strict +1. A +2. B + +(a) A +(b) B +^D +
            +
          1. A
          2. +
          3. B
          4. +
          +

          (a) A (b) B

          +``` + +With fancy_lists, we get Decimal and Period instead of Default. + +``` +% pandoc -t native -f markdown_strict+fancy_lists +1. A +2. B + +(a) A +(b) B +^D +[ OrderedList + ( 1 , Decimal , Period ) + [ [ Plain [ Str "A" ] ] , [ Plain [ Str "B" ] ] ] +, OrderedList + ( 1 , LowerAlpha , TwoParens ) + [ [ Plain [ Str "A" ] ] , [ Plain [ Str "B" ] ] ] +] +``` + +With commonmark, we get Decimal and Period even without fancy_lists. + +``` +% pandoc -t native -f commonmark +1. A +2. B + +(a) A +(b) B +^D +[ OrderedList + ( 1 , Decimal , Period ) + [ [ Plain [ Str "A" ] ] , [ Plain [ Str "B" ] ] ] +, Para + [ Str "(a)" + , Space + , Str "A" + , SoftBreak + , Str "(b)" + , Space + , Str "B" + ] +] +``` + +With fancy_lists and parens in the markdown source, we don't try to use a +custom counter-style as the list-style-type in HTML output when no template is +used. + +``` +% pandoc -t html -f markdown +1. A +2. B + +(a) A +(b) B +^D +
            +
          1. A
          2. +
          3. B
          4. +
          +
            +
          1. A
          2. +
          3. B
          4. +
          +``` + +The `@counter-style` rules are demonstrated in the writer.html5 golden output. diff --git a/test/command/5627.md b/test/command/5627.md index fde15fe9ac9d..94e57cc1855d 100644 --- a/test/command/5627.md +++ b/test/command/5627.md @@ -15,7 +15,7 @@ Something ~~~ ^D

          Example

          -
            +
            1. One
            2. Two -->something<!--
            3. Three
            4. @@ -69,7 +69,7 @@ class="sourceCode html">Example 3 -
                +
                1. -->one<!--
                2. bye -->two <!--
                3. ` three, not in block
                4. @@ -81,7 +81,7 @@ class="sourceCode html">
                  +
                  1. forty-two, separate ordered list
                  ``` diff --git a/test/command/9042.md b/test/command/9042.md index a27fa8023138..23da1a640b3d 100644 --- a/test/command/9042.md +++ b/test/command/9042.md @@ -23,7 +23,7 @@ p. lower case P. Upper Case ^D

                  Testing

                  -
                    +
                    1. lower case

                    2. Upper Case

                    diff --git a/test/command/tasklist.md b/test/command/tasklist.md index 177845aac1ed..98fef9e61570 100644 --- a/test/command/tasklist.md +++ b/test/command/tasklist.md @@ -58,7 +58,7 @@ paragraph
                  1. paragraph

                    -
                      +
                      1. [] plain item
                      2. Fancy list markers

                        -
                          +
                          1. begins with 2

                          2. and now 3

                            with a continuation

                            1. sublist with roman numerals, starting with 4
                            2. more items -
                                +
                                1. a subsublist
                                2. a subsublist
                                @@ -377,9 +392,9 @@ back.

                              1. Upper Alpha
                                1. Upper Roman. -
                                    +
                                    1. Decimal start with 6 -
                                        +
                                        1. Lower alpha with paren
                                    2. diff --git a/test/writer.html5 b/test/writer.html5 index a9da62179754..108c924a3d50 100644 --- a/test/writer.html5 +++ b/test/writer.html5 @@ -172,6 +172,21 @@ vertical-align: middle; } .display.math{display: block; text-align: center; margin: 0.5rem auto;} + @counter-style decimal-two-parens { + system: extends decimal; + prefix: "("; + suffix: ")"; + } + @counter-style lower-alpha-one-paren { + system: extends lower-alpha; + prefix: ""; + suffix: ")"; + } + @counter-style upper-alpha-two-parens { + system: extends upper-alpha; + prefix: "("; + suffix: ")"; + } @@ -217,7 +232,7 @@ here.

                                      print "working"; }

                                      A list:

                                      -
                                        +
                                        1. item one
                                        2. item two
                                        @@ -286,31 +301,31 @@ These should not be escaped: \$ \\ \> \[ \{

                                        Ordered

                                        Tight:

                                        -
                                          +
                                          1. First
                                          2. Second
                                          3. Third

                                          and:

                                          -
                                            +
                                            1. One
                                            2. Two
                                            3. Three

                                            Loose using tabs:

                                            -
                                              +
                                              1. First

                                              2. Second

                                              3. Third

                                              and using spaces:

                                              -
                                                +
                                                1. One

                                                2. Two

                                                3. Three

                                                Multiple paragraphs:

                                                -
                                                  +
                                                  1. Item 1, graf one.

                                                    Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.

                                                  2. @@ -328,7 +343,7 @@ back.

                                                    Here’s another:

                                                    -
                                                      +
                                                      1. First
                                                      2. Second:
                                                          @@ -339,7 +354,7 @@ back.

                                                        • Third

                                                      Same thing but with paragraphs:

                                                      -
                                                        +
                                                        1. First

                                                        2. Second:

                                                            @@ -359,27 +374,27 @@ back.

                                                        3. Fancy list markers

                                                          -
                                                            +
                                                            1. begins with 2

                                                            2. and now 3

                                                              with a continuation

                                                              -
                                                                +
                                                                1. sublist with roman numerals, starting with 4
                                                                2. more items -
                                                                    +
                                                                    1. a subsublist
                                                                    2. a subsublist

                                                                Nesting:

                                                                -
                                                                  +
                                                                  1. Upper Alpha -
                                                                      +
                                                                      1. Upper Roman. -
                                                                          +
                                                                          1. Decimal start with 6 -
                                                                              +
                                                                              1. Lower alpha with paren
                                                                          2. @@ -505,7 +520,7 @@ bank
                                                                            orange

                                                                            orange fruit

                                                                            -
                                                                              +
                                                                              1. sublist
                                                                              2. sublist
                                                                              @@ -735,7 +750,7 @@ role="doc-noteref">3

                                                                              Notes can go in quotes.4

                                                                              -
                                                                                +
                                                                                1. And in list items.5