From e7f187b6c1397b6e7ff4e11152617bf22314bc26 Mon Sep 17 00:00:00 2001 From: yanntrividic Date: Mon, 23 Jun 2025 18:31:21 +0200 Subject: [PATCH 01/54] Modifying return value for parseBlock, parseInline This commits adds a getRoleAttr function to get the value from the role attribute of a DocBook element. This value is then added to the returned Pandoc object by using addPandocAttributes. --- src/Text/Pandoc/Readers/DocBook.hs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs index a73e46ce0393..14b9bc9ecc93 100644 --- a/src/Text/Pandoc/Readers/DocBook.hs +++ b/src/Text/Pandoc/Readers/DocBook.hs @@ -46,7 +46,7 @@ import Text.Pandoc.Builder import Text.Pandoc.Class.PandocMonad (PandocMonad, report) import Text.Pandoc.Options import Text.Pandoc.Logging (LogMessage(..)) -import Text.Pandoc.Shared (safeRead, extractSpaces) +import Text.Pandoc.Shared (safeRead, extractSpaces, addPandocAttributes) import Text.Pandoc.Sources (ToSources(..), sourcesToText) import Text.Pandoc.Transforms (headerShift) import Text.TeXMath (readMathML, writeTeX) @@ -855,6 +855,10 @@ getBlocks :: PandocMonad m => Element -> DB m Blocks getBlocks e = mconcat <$> mapM parseBlock (elContent e) +getRoleAttr :: Element -> [(Text, Text)] -- extract role attribute and add it to the attribute list +getRoleAttr e = case attrValue "role" e of + "" -> [] + r -> [("role", r)] parseBlock :: PandocMonad m => Content -> DB m Blocks parseBlock (Text (CData CDataRaw _ _)) = return mempty -- DOCTYPE @@ -862,8 +866,8 @@ parseBlock (Text (CData _ s _)) = if T.all isSpace s then return mempty else return $ plain $ trimInlines $ text s parseBlock (CRef x) = return $ plain $ str $ T.toUpper x -parseBlock (Elem e) = - case qName (elName e) of +parseBlock (Elem e) = do + parsedBlock <- case qName (elName e) of "toc" -> skip -- skip TOC, since in pandoc it's autogenerated "index" -> skip -- skip index, since page numbers meaningless "para" -> parseMixed para (elContent e) @@ -975,6 +979,7 @@ parseBlock (Elem e) = "title" -> return mempty -- handled in parent element "subtitle" -> return mempty -- handled in parent element _ -> skip >> getBlocks e + return $ addPandocAttributes (getRoleAttr e) parsedBlock where skip = do let qn = qName $ elName e let name = if "pi-" `T.isPrefixOf` qn @@ -1226,8 +1231,8 @@ parseInline (Text (CData _ s _)) = do else return $ text s parseInline (CRef ref) = return $ text $ fromMaybe (T.toUpper ref) $ lookupEntity ref -parseInline (Elem e) = - case qName (elName e) of +parseInline (Elem e) = do + parsedInline <- case qName (elName e) of "anchor" -> do return $ spanWith (attrValue "id" e, [], []) mempty "phrase" -> do @@ -1349,6 +1354,9 @@ parseInline (Elem e) = -- to in handleInstructions, above. "pi-asciidoc-br" -> return linebreak _ -> skip >> innerInlines id + return $ case qName (elName e) of + "emphasis" -> parsedInline + _ -> addPandocAttributes (getRoleAttr e) parsedInline where skip = do let qn = qName $ elName e let name = if "pi-" `T.isPrefixOf` qn From 2c7d45d390e9bdf4bea94d9052c1680f2c40c27e Mon Sep 17 00:00:00 2001 From: yanntrividic Date: Mon, 23 Jun 2025 19:54:27 +0200 Subject: [PATCH 02/54] Adding roles to headers for sections with roles Sections have to be considered in a different way than regular blocks and inlines. In this case, we wrap the content in a Div element with a `section` class and a `level` attribute in addition to the `role` attribute. See this comment: https://github.com/jgm/pandoc/commit/d097c64c551fadcdda7e06b6f26457151c99980d --- src/Text/Pandoc/Readers/DocBook.hs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs index 14b9bc9ecc93..8d16fdd60f5e 100644 --- a/src/Text/Pandoc/Readers/DocBook.hs +++ b/src/Text/Pandoc/Readers/DocBook.hs @@ -1117,7 +1117,12 @@ parseBlock (Elem e) = do modify $ \st -> st{ dbSectionLevel = n } b <- getBlocks e modify $ \st -> st{ dbSectionLevel = n - 1 } - return $ headerWith (elId, classes, maybeToList titleabbrevElAsAttr++attrs) n' headerText <> b + let content = headerWith (elId, classes, maybeToList titleabbrevElAsAttr) + n' headerText <> b + return $ case attrValue "role" e of + "" -> content + _ -> divWith ("", ["section"], + ("level", T.pack $ show n') : attrs) content titleabbrevElAsAttr = case filterChild (named "titleabbrev") e `mplus` (filterChild (named "info") e >>= From b626d729ad62f1f6952f55a3ed53ff7a0868a1ce Mon Sep 17 00:00:00 2001 From: yanntrividic Date: Mon, 23 Jun 2025 20:04:46 +0200 Subject: [PATCH 03/54] Add roles to els parsed with withOptionalTitle Elements parsed with withOptionalTitle do not automatically get the role attributes transfered to them. This covers this problem. --- src/Text/Pandoc/Readers/DocBook.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs index 8d16fdd60f5e..904be0fa4a5c 100644 --- a/src/Text/Pandoc/Readers/DocBook.hs +++ b/src/Text/Pandoc/Readers/DocBook.hs @@ -1145,9 +1145,8 @@ parseBlock (Elem e) = do b <- p case mbt of Nothing -> return b - Just t -> return $ divWith (attrValue "id" e,[],[]) + Just t -> return $ divWith (attrValue "id" e, [], getRoleAttr e) (divWith ("", ["title"], []) (plain t) <> b) - -- Admonitions are parsed into a div. Following other Docbook tools that output HTML, -- we parse the optional title as a div with the @title@ class, and give the -- block itself a class corresponding to the admonition name. From 4b1bc982451188c3c2e06572a9e94dacfbe403e8 Mon Sep 17 00:00:00 2001 From: yanntrividic Date: Mon, 23 Jun 2025 20:06:16 +0200 Subject: [PATCH 04/54] Units tests for this PR and new role attributes --- test/docbook-reader.docbook | 42 ++++++++- test/docbook-reader.native | 181 +++++++++++++++++++++++++++++------- 2 files changed, 185 insertions(+), 38 deletions(-) diff --git a/test/docbook-reader.docbook b/test/docbook-reader.docbook index 5c3b527875c2..bd9fb8812c0e 100644 --- a/test/docbook-reader.docbook +++ b/test/docbook-reader.docbook @@ -27,9 +27,9 @@ This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite. - + Headers - + Level 2 with an <ulink url="/url">embedded link</ulink> Level 3 with <emphasis>emphasis</emphasis> @@ -74,6 +74,9 @@ Here’s a regular paragraph. + + And here’s a regular paragraph with a role. + In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like @@ -93,6 +96,11 @@ This is a block quote. It is pretty short. +
+ + This is a block quote with a role. + +
Code in a block quote: @@ -233,6 +241,26 @@ These should not be escaped: \$ \\ \> \[ \{ + + with role: + + + + + First + + + + + Second + + + + + Third + + + and tight: @@ -702,6 +730,12 @@ These should not be escaped: \$ \\ \> \[ \{ So is this word. + + So is this word with a role. + + + So is this phrase with a role. + This is code: >, $, \, \$, @@ -1408,7 +1442,7 @@ or here: <http://example.com/> Table with attributes - +
Attribute table caption @@ -1444,7 +1478,7 @@ or here: <http://example.com/> Table with attributes, without caption - +
diff --git a/test/docbook-reader.native b/test/docbook-reader.native index 13f5c49fcb7c..f46d60f4e4b9 100644 --- a/test/docbook-reader.native +++ b/test/docbook-reader.native @@ -62,39 +62,55 @@ Pandoc , Space , Str "suite." ] - , Header 1 ( "headers" , [] , [] ) [ Str "Headers" ] - , Header - 2 - ( "level-2-with-an-embedded-link" , [] , [] ) - [ Str "Level" - , Space - , Str "2" - , Space - , Str "with" - , Space - , Str "an" - , Space - , Link - ( "" , [] , [] ) - [ Str "embedded" , Space , Str "link" ] - ( "/url" , "" ) - ] - , Header - 3 - ( "level-3-with-emphasis" , [] , [] ) - [ Str "Level" - , Space - , Str "3" - , Space - , Str "with" - , Space - , Emph [ Str "emphasis" ] + , Div + ( "" + , [ "section" ] + , [ ( "role" , "sect1role" ) , ( "level" , "1" ) ] + ) + [ Header 1 ( "headers" , [] , [] ) [ Str "Headers" ] + , Div + ( "" + , [ "section" ] + , [ ( "role" , "sect2role" ) , ( "level" , "2" ) ] + ) + [ Header + 2 + ( "level-2-with-an-embedded-link" , [] , [] ) + [ Str "Level" + , Space + , Str "2" + , Space + , Str "with" + , Space + , Str "an" + , Space + , Link + ( "" , [] , [] ) + [ Str "embedded" , Space , Str "link" ] + ( "/url" , "" ) + ] + , Header + 3 + ( "level-3-with-emphasis" , [] , [] ) + [ Str "Level" + , Space + , Str "3" + , Space + , Str "with" + , Space + , Emph [ Str "emphasis" ] + ] + , Header + 4 + ( "level-4" , [] , [] ) + [ Str "Level" , Space , Str "4" ] + , Header + 5 + ( "level-5" , [] , [] ) + [ Str "Level" , Space , Str "5" ] + , Para [ Str "Hi." ] + ] ] - , Header - 4 ( "level-4" , [] , [] ) [ Str "Level" , Space , Str "4" ] - , Header - 5 ( "level-5" , [] , [] ) [ Str "Level" , Space , Str "5" ] - , Para [ Str "Hi." ] , Header 1 ( "level-1" , [] , [] ) [ Str "Level" , Space , Str "1" ] , Header @@ -151,6 +167,29 @@ Pandoc , Space , Str "paragraph." ] + , Div + ( "" + , [] + , [ ( "wrapper" , "1" ) , ( "role" , "pararole" ) ] + ) + [ Para + [ Str "And" + , Space + , Str "here\8217s" + , Space + , Str "a" + , Space + , Str "regular" + , Space + , Str "paragraph" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "role." + ] + ] , Para [ Str "In" , Space @@ -251,6 +290,31 @@ Pandoc , Str "short." ] ] + , Div + ( "" + , [] + , [ ( "wrapper" , "1" ) , ( "role" , "roleblockquote" ) ] + ) + [ BlockQuote + [ Para + [ Str "This" + , Space + , Str "is" + , Space + , Str "a" + , Space + , Str "block" + , Space + , Str "quote" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "role." + ] + ] + ] , BlockQuote [ Para [ Str "Code" @@ -348,6 +412,19 @@ Pandoc , [ Para [ Str "Second" ] ] , [ Para [ Str "Third" ] ] ] + , Para [ Str "with" , Space , Str "role:" ] + , Div + ( "" + , [] + , [ ( "wrapper" , "1" ) , ( "role" , "listrole" ) ] + ) + [ OrderedList + ( 1 , Decimal , DefaultDelim ) + [ [ Para [ Str "First" ] ] + , [ Para [ Str "Second" ] ] + , [ Para [ Str "Third" ] ] + ] + ] , Para [ Str "and" , Space , Str "tight:" ] , OrderedList ( 1 , Decimal , DefaultDelim ) @@ -931,6 +1008,38 @@ Pandoc , Space , Str "word." ] + , Para + [ Str "So" + , Space + , Str "is" + , Space + , Emph [ Emph [ Str "this" ] ] + , Space + , Str "word" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "role." + ] + , Para + [ Str "So" + , Space + , Str "is" + , Space + , Span + ( "" , [ "phraserole" ] , [ ( "role" , "phraserole" ) ] ) + [ Str "this" ] + , Space + , Str "phrase" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "role." + ] , Para [ Str "This" , Space @@ -2570,7 +2679,9 @@ Pandoc , Table ( "mytableid1" , [ "mytableclass1" , "mytableclass2" ] - , [ ( "custom-style" , "mytabstyle1" ) ] + , [ ( "role" , "tablerole1" ) + , ( "custom-style" , "mytabstyle1" ) + ] ) (Caption Nothing @@ -2636,7 +2747,9 @@ Pandoc , Table ( "mytableid2" , [ "mytableclass3" , "mytableclass4" ] - , [ ( "custom-style" , "mytabstyle2" ) ] + , [ ( "role" , "tablerole2" ) + , ( "custom-style" , "mytabstyle2" ) + ] ) (Caption Nothing []) [ ( AlignDefault , ColWidthDefault ) From 08dbdfa5da18d2820e723551e8fab2dd24115f32 Mon Sep 17 00:00:00 2001 From: yanntrividic Date: Mon, 23 Jun 2025 19:54:27 +0200 Subject: [PATCH 05/54] Adding roles to headers for sections with roles Sections have to be considered in a different way than regular blocks and inlines. In this case, we wrap the content in a Div element with a `section` class and a `level` attribute in addition to the `role` attribute. --- src/Text/Pandoc/Readers/DocBook.hs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs index 14b9bc9ecc93..8d16fdd60f5e 100644 --- a/src/Text/Pandoc/Readers/DocBook.hs +++ b/src/Text/Pandoc/Readers/DocBook.hs @@ -1117,7 +1117,12 @@ parseBlock (Elem e) = do modify $ \st -> st{ dbSectionLevel = n } b <- getBlocks e modify $ \st -> st{ dbSectionLevel = n - 1 } - return $ headerWith (elId, classes, maybeToList titleabbrevElAsAttr++attrs) n' headerText <> b + let content = headerWith (elId, classes, maybeToList titleabbrevElAsAttr) + n' headerText <> b + return $ case attrValue "role" e of + "" -> content + _ -> divWith ("", ["section"], + ("level", T.pack $ show n') : attrs) content titleabbrevElAsAttr = case filterChild (named "titleabbrev") e `mplus` (filterChild (named "info") e >>= From 5af69cb8682416d0852073003f7434a75f5deec7 Mon Sep 17 00:00:00 2001 From: yanntrividic Date: Mon, 23 Jun 2025 20:04:46 +0200 Subject: [PATCH 06/54] Add roles to els parsed with withOptionalTitle Elements parsed with withOptionalTitle do not automatically get the role attributes transfered to them. This covers this problem. --- src/Text/Pandoc/Readers/DocBook.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs index 8d16fdd60f5e..904be0fa4a5c 100644 --- a/src/Text/Pandoc/Readers/DocBook.hs +++ b/src/Text/Pandoc/Readers/DocBook.hs @@ -1145,9 +1145,8 @@ parseBlock (Elem e) = do b <- p case mbt of Nothing -> return b - Just t -> return $ divWith (attrValue "id" e,[],[]) + Just t -> return $ divWith (attrValue "id" e, [], getRoleAttr e) (divWith ("", ["title"], []) (plain t) <> b) - -- Admonitions are parsed into a div. Following other Docbook tools that output HTML, -- we parse the optional title as a div with the @title@ class, and give the -- block itself a class corresponding to the admonition name. From 71edd85f2aee7be0238e4966e900efea7baa262b Mon Sep 17 00:00:00 2001 From: yanntrividic Date: Mon, 23 Jun 2025 20:06:16 +0200 Subject: [PATCH 07/54] Units tests for this PR and new role attributes --- test/docbook-reader.docbook | 42 ++++++++- test/docbook-reader.native | 181 +++++++++++++++++++++++++++++------- 2 files changed, 185 insertions(+), 38 deletions(-) diff --git a/test/docbook-reader.docbook b/test/docbook-reader.docbook index 5c3b527875c2..bd9fb8812c0e 100644 --- a/test/docbook-reader.docbook +++ b/test/docbook-reader.docbook @@ -27,9 +27,9 @@ This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite. - + Headers - + Level 2 with an <ulink url="/url">embedded link</ulink> Level 3 with <emphasis>emphasis</emphasis> @@ -74,6 +74,9 @@ Here’s a regular paragraph. + + And here’s a regular paragraph with a role. + In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like @@ -93,6 +96,11 @@ This is a block quote. It is pretty short. +
+ + This is a block quote with a role. + +
Code in a block quote: @@ -233,6 +241,26 @@ These should not be escaped: \$ \\ \> \[ \{ + + with role: + + + + + First + + + + + Second + + + + + Third + + + and tight: @@ -702,6 +730,12 @@ These should not be escaped: \$ \\ \> \[ \{ So is this word. + + So is this word with a role. + + + So is this phrase with a role. + This is code: >, $, \, \$, @@ -1408,7 +1442,7 @@ or here: <http://example.com/> Table with attributes - +
Attribute table caption @@ -1444,7 +1478,7 @@ or here: <http://example.com/> Table with attributes, without caption - + + + + + + + + + + + + + + + + + + + + + + + + An Example Procedure diff --git a/test/docbook-reader.native b/test/docbook-reader.native index f46d60f4e4b9..362f15a9a6ca 100644 --- a/test/docbook-reader.native +++ b/test/docbook-reader.native @@ -3159,6 +3159,128 @@ Pandoc ] ] (TableFoot ( "" , [] , [] ) []) + , Para + [ Str "Multiline" + , Space + , Str "table" + , Space + , Str "with" + , Space + , Str "cells" + , Space + , Str "spanning" + , Space + , Str "multiple" + , Space + , Str "columns" + , Space + , Str "and" + , Space + , Str "rows" + , Space + , Str "without" + , Space + , Str "caption." + ] + , Table + ( "" , [] , [] ) + (Caption Nothing []) + [ ( AlignLeft , ColWidthDefault ) + , ( AlignLeft , ColWidthDefault ) + , ( AlignLeft , ColWidthDefault ) + ] + (TableHead + ( "" , [] , [] ) + [ Row + ( "" , [] , [] ) + [ Cell + ( "" , [] , [] ) + AlignDefault + (RowSpan 1) + (ColSpan 3) + [ Plain [ Str "Columns" ] ] + ] + , Row + ( "" , [] , [] ) + [ Cell + ( "" , [] , [] ) + AlignDefault + (RowSpan 1) + (ColSpan 1) + [ Plain [ Str "A" ] ] + , Cell + ( "" , [] , [] ) + AlignDefault + (RowSpan 1) + (ColSpan 1) + [ Plain [ Str "B" ] ] + , Cell + ( "" , [] , [] ) + AlignDefault + (RowSpan 1) + (ColSpan 1) + [ Plain [ Str "C" ] ] + ] + ]) + [ TableBody + ( "" , [] , [] ) + (RowHeadColumns 0) + [] + [ Row + ( "" , [] , [] ) + [ Cell + ( "" , [] , [] ) + AlignDefault + (RowSpan 1) + (ColSpan 2) + [ Plain + [ Str "A1" , Space , Str "+" , Space , Str "B1" ] + ] + , Cell + ( "" , [] , [] ) + AlignDefault + (RowSpan 2) + (ColSpan 1) + [ Plain + [ Str "C1" , Space , Str "+" , Space , Str "C2" ] + ] + ] + , Row + ( "" , [] , [] ) + [ Cell + ( "" , [] , [] ) + AlignDefault + (RowSpan 2) + (ColSpan 2) + [ Plain + [ Str "A2" + , Space + , Str "+" + , Space + , Str "B2" + , Space + , Str "+" + , Space + , Str "A3" + , Space + , Str "+" + , Space + , Str "B3" + ] + ] + ] + , Row + ( "" , [] , [] ) + [ Cell + ( "" , [] , [] ) + AlignDefault + (RowSpan 1) + (ColSpan 1) + [ Plain [ Str "C3" ] ] + ] + ] + ] + (TableFoot ( "" , [] , [] ) []) , OrderedList ( 1 , DefaultStyle , DefaultDelim ) [ [ Para [ Str "A" , Space , Str "Step" ] ] From 6070379ab5cbae5870183558c517a2c61a115531 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 24 Jul 2025 14:49:38 -0700 Subject: [PATCH 47/54] Revert a test case that changed due to a reverted citeproc change. --- test/command/biblatex-britannica.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/command/biblatex-britannica.md b/test/command/biblatex-britannica.md index cd04d1b4f263..37a3a0720d8d 100644 --- a/test/command/biblatex-britannica.md +++ b/test/command/biblatex-britannica.md @@ -76,8 +76,8 @@ references: number-of-volumes: 32 publisher: Encyclopædia Britannica publisher-place: Chicago, Ill. - title: The new encyclop[æ]{.nocase}dia Britannica - title-short: Encyclop[æ]{.nocase}dia Britannica + title: The new encyclopædia Britannica + title-short: Encyclopædia Britannica type: book --- From b11afcfab685586840151bebb4fc817a53fd0df2 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 24 Jul 2025 14:49:59 -0700 Subject: [PATCH 48/54] Use latest dev citeproc. This solves the problem of unwanted capitalization of names at the beginning of citations in footnotes. Closes #10983. --- cabal.project | 4 +++- stack.yaml | 2 +- test/command/10983.md | 22 ++++++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 test/command/10983.md diff --git a/cabal.project b/cabal.project index e3a3eb97f407..4b85b4978cbb 100644 --- a/cabal.project +++ b/cabal.project @@ -9,10 +9,12 @@ constraints: skylighting-format-blaze-html >= 0.1.1.3, -- for now (commercialhaskell/stackage#7545): data-default-class <= 0.2, data-default <= 0.8 + + source-repository-package type: git location: https://github.com/jgm/citeproc.git - tag: 723d22a112a15a8f287d4db68ba05e9083facfec + tag: b32c4c117795d8fef3fcc8996a62ee661904738e source-repository-package type: git diff --git a/stack.yaml b/stack.yaml index 40955fa00261..6487afcb0911 100644 --- a/stack.yaml +++ b/stack.yaml @@ -22,7 +22,7 @@ extra-deps: - typst-symbols-0.1.8.1 - typst-0.8.0.1 - git: https://github.com/jgm/citeproc.git - commit: 723d22a112a15a8f287d4db68ba05e9083facfec + commit: b32c4c117795d8fef3fcc8996a62ee661904738e - git: https://github.com/jgm/texmath.git commit: 77e20978ffcdec4ca50bbb809f061850c0998560 ghc-options: diff --git a/test/command/10983.md b/test/command/10983.md new file mode 100644 index 000000000000..d31baf281707 --- /dev/null +++ b/test/command/10983.md @@ -0,0 +1,22 @@ +``` +% pandoc --citeproc --csl command/chicago-fullnote-bibliography.csl -t plain +--- +references: +- id: test4 + type: blog-post + title: "Username as author" + author: + - brtw + container-title: "Reddit" + issued: + year: 2004 +suppress-bibliography: true +... + +[@test4] +^D +[1] + +[1] brtw, “Username as Author,” Reddit, 2004. + +``` From 7a30647e7f0859aa20a79804efee1144d55cac5c Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Fri, 25 Jul 2025 07:49:13 +0200 Subject: [PATCH 49/54] T.P.PDF: clean up `makePDF` --- src/Text/Pandoc/PDF.hs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs index 0e198b0bb14b..715be0e84f0d 100644 --- a/src/Text/Pandoc/PDF.hs +++ b/src/Text/Pandoc/PDF.hs @@ -94,14 +94,13 @@ makePDF program pdfargs writer opts doc = withTempDir (program == "typst") "medi disableExtension Ext_smart (writerExtensions opts) } doc' verbosity <- getVerbosity + let compileHTML mkOutArgs = liftIO $ + toPdfViaTempFile verbosity program pdfargs mkOutArgs ".html" source case takeBaseName program of "wkhtmltopdf" -> makeWithWkhtmltopdf program pdfargs writer opts doc - prog | prog `elem` ["pagedjs-cli" ,"weasyprint", "prince"] -> do - let mkOutArgs f = - if program `elem` ["pagedjs-cli", "prince"] - then ["-o", f] - else [f] - liftIO $ toPdfViaTempFile verbosity program pdfargs mkOutArgs ".html" source + "pagedjs-cli" -> compileHTML (\f -> ["-o", f]) + "prince" -> compileHTML (\f -> ["-o", f]) + "weasyprint" -> compileHTML (:[]) "typst" -> liftIO $ toPdfViaTempFile verbosity program ("compile":pdfargs) (:[]) ".typ" source "pdfroff" -> do @@ -130,13 +129,13 @@ makePDF program pdfargs writer opts doc = withTempDir (program == "typst") "medi ["-U" | ".PDFPIC" `T.isInfixOf` source] ++ paperargs ++ pdfargs generic2pdf program args source - baseProg -> - case baseProg of - "context" -> context2pdf program pdfargs tmpdir source - "tectonic" -> tectonic2pdf program pdfargs tmpdir source - prog | prog `elem` ["pdflatex", "lualatex", "xelatex", "latexmk"] - -> tex2pdf program pdfargs tmpdir source - _ -> return $ Left $ UTF8.fromStringLazy $ "Unknown program " ++ program + "context" -> context2pdf program pdfargs tmpdir source + "tectonic" -> tectonic2pdf program pdfargs tmpdir source + "latexmk" -> tex2pdf program pdfargs tmpdir source + "lualatex" -> tex2pdf program pdfargs tmpdir source + "pdflatex" -> tex2pdf program pdfargs tmpdir source + "xelatex" -> tex2pdf program pdfargs tmpdir source + _ -> return $ Left $ UTF8.fromStringLazy $ "Unknown program " ++ program -- latex has trouble with tildes in paths, which -- you find in Windows temp dir paths with longer From 6f61b8e2388d971f3c31ae2566a2d3c7677d1f3a Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Fri, 25 Jul 2025 07:54:13 +0200 Subject: [PATCH 50/54] PDF: allow `pdflatex-dev` and `lualatex-dev` as PDF engines These are the development versions of the LaTeX binaries; installable, e.g., with `tlmgr install latex-base-dev`. Closes: #10991 --- src/Text/Pandoc/App/CommandLineOptions.hs | 3 ++- src/Text/Pandoc/PDF.hs | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs index b8a4e2fc953e..7f5515ef869d 100644 --- a/src/Text/Pandoc/App/CommandLineOptions.hs +++ b/src/Text/Pandoc/App/CommandLineOptions.hs @@ -205,7 +205,8 @@ handleOptInfo engine info = E.handle (handleError . Left) $ do -- | Supported LaTeX engines; the first item is used as default engine -- when going through LaTeX. latexEngines :: [String] -latexEngines = ["pdflatex", "lualatex", "xelatex", "latexmk", "tectonic"] +latexEngines = [ "pdflatex", "lualatex", "xelatex", "latexmk", "tectonic" + , "pdflatex-dev", "lualatex-dev" ] -- | Supported HTML PDF engines; the first item is used as default -- engine when going through HTML. diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs index 715be0e84f0d..ef37b8cab8f8 100644 --- a/src/Text/Pandoc/PDF.hs +++ b/src/Text/Pandoc/PDF.hs @@ -133,7 +133,9 @@ makePDF program pdfargs writer opts doc = withTempDir (program == "typst") "medi "tectonic" -> tectonic2pdf program pdfargs tmpdir source "latexmk" -> tex2pdf program pdfargs tmpdir source "lualatex" -> tex2pdf program pdfargs tmpdir source + "lualatex-dev" -> tex2pdf program pdfargs tmpdir source "pdflatex" -> tex2pdf program pdfargs tmpdir source + "pdflatex-dev" -> tex2pdf program pdfargs tmpdir source "xelatex" -> tex2pdf program pdfargs tmpdir source _ -> return $ Left $ UTF8.fromStringLazy $ "Unknown program " ++ program From e7e1725ef6504ef14f33a3fe0fa8bc3412349c11 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Fri, 25 Jul 2025 08:17:20 +0200 Subject: [PATCH 51/54] PDF: Improve error readability when pdf-engine is not supported. Each supported engine is now printed on a line of its own. --- src/Text/Pandoc/App/CommandLineOptions.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs index 7f5515ef869d..56c855e5f854 100644 --- a/src/Text/Pandoc/App/CommandLineOptions.hs +++ b/src/Text/Pandoc/App/CommandLineOptions.hs @@ -598,8 +598,8 @@ options = then return opt { optPdfEngine = Just arg } else optError $ PandocOptionError $ T.pack $ - "Argument of --pdf-engine must be one of " - ++ intercalate ", " pdfEngines) + "Argument of --pdf-engine must be one of\n" + ++ concatMap (\e -> "\t" <> e <> "\n") pdfEngines) "PROGRAM") "" -- "Name of program to use in generating PDF" From 4c01975932f028c2e61577d19c83a2f45c43aa2b Mon Sep 17 00:00:00 2001 From: yanntrividic Date: Mon, 23 Jun 2025 19:54:27 +0200 Subject: [PATCH 52/54] Adding roles to headers for sections w/ roles Sections have to be considered in a different way than regular blocks and inlines. In this case, we wrap the content in a Div element with a `section` class and a `level` attribute in addition to the `role` attribute. --- src/Text/Pandoc/Readers/DocBook.hs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs index 14b9bc9ecc93..8d16fdd60f5e 100644 --- a/src/Text/Pandoc/Readers/DocBook.hs +++ b/src/Text/Pandoc/Readers/DocBook.hs @@ -1117,7 +1117,12 @@ parseBlock (Elem e) = do modify $ \st -> st{ dbSectionLevel = n } b <- getBlocks e modify $ \st -> st{ dbSectionLevel = n - 1 } - return $ headerWith (elId, classes, maybeToList titleabbrevElAsAttr++attrs) n' headerText <> b + let content = headerWith (elId, classes, maybeToList titleabbrevElAsAttr) + n' headerText <> b + return $ case attrValue "role" e of + "" -> content + _ -> divWith ("", ["section"], + ("level", T.pack $ show n') : attrs) content titleabbrevElAsAttr = case filterChild (named "titleabbrev") e `mplus` (filterChild (named "info") e >>= From eb8a92835e385a286f1b30a4d2c74188bb22a899 Mon Sep 17 00:00:00 2001 From: yanntrividic Date: Mon, 23 Jun 2025 20:04:46 +0200 Subject: [PATCH 53/54] Add roles to els parsed with withOptionalTitle Elements parsed with withOptionalTitle do not automatically get the role attributes transfered to them. This covers this problem. --- src/Text/Pandoc/Readers/DocBook.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs index 8d16fdd60f5e..904be0fa4a5c 100644 --- a/src/Text/Pandoc/Readers/DocBook.hs +++ b/src/Text/Pandoc/Readers/DocBook.hs @@ -1145,9 +1145,8 @@ parseBlock (Elem e) = do b <- p case mbt of Nothing -> return b - Just t -> return $ divWith (attrValue "id" e,[],[]) + Just t -> return $ divWith (attrValue "id" e, [], getRoleAttr e) (divWith ("", ["title"], []) (plain t) <> b) - -- Admonitions are parsed into a div. Following other Docbook tools that output HTML, -- we parse the optional title as a div with the @title@ class, and give the -- block itself a class corresponding to the admonition name. From ce651321454451f222416b73d29e6a218a801e27 Mon Sep 17 00:00:00 2001 From: yanntrividic Date: Mon, 23 Jun 2025 20:06:16 +0200 Subject: [PATCH 54/54] Units tests for this PR and new role attributes --- test/docbook-reader.docbook | 42 ++++++++- test/docbook-reader.native | 181 +++++++++++++++++++++++++++++------- 2 files changed, 185 insertions(+), 38 deletions(-) diff --git a/test/docbook-reader.docbook b/test/docbook-reader.docbook index 5c3b527875c2..bd9fb8812c0e 100644 --- a/test/docbook-reader.docbook +++ b/test/docbook-reader.docbook @@ -27,9 +27,9 @@ This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite. - + Headers - + Level 2 with an <ulink url="/url">embedded link</ulink> Level 3 with <emphasis>emphasis</emphasis> @@ -74,6 +74,9 @@ Here’s a regular paragraph. + + And here’s a regular paragraph with a role. + In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard-wrapped line in the middle of a paragraph looked like @@ -93,6 +96,11 @@ This is a block quote. It is pretty short. +
+ + This is a block quote with a role. + +
Code in a block quote: @@ -233,6 +241,26 @@ These should not be escaped: \$ \\ \> \[ \{ + + with role: + + + + + First + + + + + Second + + + + + Third + + + and tight: @@ -702,6 +730,12 @@ These should not be escaped: \$ \\ \> \[ \{ So is this word. + + So is this word with a role. + + + So is this phrase with a role. + This is code: >, $, \, \$, @@ -1408,7 +1442,7 @@ or here: <http://example.com/> Table with attributes -
diff --git a/test/docbook-reader.native b/test/docbook-reader.native index 13f5c49fcb7c..f46d60f4e4b9 100644 --- a/test/docbook-reader.native +++ b/test/docbook-reader.native @@ -62,39 +62,55 @@ Pandoc , Space , Str "suite." ] - , Header 1 ( "headers" , [] , [] ) [ Str "Headers" ] - , Header - 2 - ( "level-2-with-an-embedded-link" , [] , [] ) - [ Str "Level" - , Space - , Str "2" - , Space - , Str "with" - , Space - , Str "an" - , Space - , Link - ( "" , [] , [] ) - [ Str "embedded" , Space , Str "link" ] - ( "/url" , "" ) - ] - , Header - 3 - ( "level-3-with-emphasis" , [] , [] ) - [ Str "Level" - , Space - , Str "3" - , Space - , Str "with" - , Space - , Emph [ Str "emphasis" ] + , Div + ( "" + , [ "section" ] + , [ ( "role" , "sect1role" ) , ( "level" , "1" ) ] + ) + [ Header 1 ( "headers" , [] , [] ) [ Str "Headers" ] + , Div + ( "" + , [ "section" ] + , [ ( "role" , "sect2role" ) , ( "level" , "2" ) ] + ) + [ Header + 2 + ( "level-2-with-an-embedded-link" , [] , [] ) + [ Str "Level" + , Space + , Str "2" + , Space + , Str "with" + , Space + , Str "an" + , Space + , Link + ( "" , [] , [] ) + [ Str "embedded" , Space , Str "link" ] + ( "/url" , "" ) + ] + , Header + 3 + ( "level-3-with-emphasis" , [] , [] ) + [ Str "Level" + , Space + , Str "3" + , Space + , Str "with" + , Space + , Emph [ Str "emphasis" ] + ] + , Header + 4 + ( "level-4" , [] , [] ) + [ Str "Level" , Space , Str "4" ] + , Header + 5 + ( "level-5" , [] , [] ) + [ Str "Level" , Space , Str "5" ] + , Para [ Str "Hi." ] + ] ] - , Header - 4 ( "level-4" , [] , [] ) [ Str "Level" , Space , Str "4" ] - , Header - 5 ( "level-5" , [] , [] ) [ Str "Level" , Space , Str "5" ] - , Para [ Str "Hi." ] , Header 1 ( "level-1" , [] , [] ) [ Str "Level" , Space , Str "1" ] , Header @@ -151,6 +167,29 @@ Pandoc , Space , Str "paragraph." ] + , Div + ( "" + , [] + , [ ( "wrapper" , "1" ) , ( "role" , "pararole" ) ] + ) + [ Para + [ Str "And" + , Space + , Str "here\8217s" + , Space + , Str "a" + , Space + , Str "regular" + , Space + , Str "paragraph" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "role." + ] + ] , Para [ Str "In" , Space @@ -251,6 +290,31 @@ Pandoc , Str "short." ] ] + , Div + ( "" + , [] + , [ ( "wrapper" , "1" ) , ( "role" , "roleblockquote" ) ] + ) + [ BlockQuote + [ Para + [ Str "This" + , Space + , Str "is" + , Space + , Str "a" + , Space + , Str "block" + , Space + , Str "quote" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "role." + ] + ] + ] , BlockQuote [ Para [ Str "Code" @@ -348,6 +412,19 @@ Pandoc , [ Para [ Str "Second" ] ] , [ Para [ Str "Third" ] ] ] + , Para [ Str "with" , Space , Str "role:" ] + , Div + ( "" + , [] + , [ ( "wrapper" , "1" ) , ( "role" , "listrole" ) ] + ) + [ OrderedList + ( 1 , Decimal , DefaultDelim ) + [ [ Para [ Str "First" ] ] + , [ Para [ Str "Second" ] ] + , [ Para [ Str "Third" ] ] + ] + ] , Para [ Str "and" , Space , Str "tight:" ] , OrderedList ( 1 , Decimal , DefaultDelim ) @@ -931,6 +1008,38 @@ Pandoc , Space , Str "word." ] + , Para + [ Str "So" + , Space + , Str "is" + , Space + , Emph [ Emph [ Str "this" ] ] + , Space + , Str "word" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "role." + ] + , Para + [ Str "So" + , Space + , Str "is" + , Space + , Span + ( "" , [ "phraserole" ] , [ ( "role" , "phraserole" ) ] ) + [ Str "this" ] + , Space + , Str "phrase" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "role." + ] , Para [ Str "This" , Space @@ -2570,7 +2679,9 @@ Pandoc , Table ( "mytableid1" , [ "mytableclass1" , "mytableclass2" ] - , [ ( "custom-style" , "mytabstyle1" ) ] + , [ ( "role" , "tablerole1" ) + , ( "custom-style" , "mytabstyle1" ) + ] ) (Caption Nothing @@ -2636,7 +2747,9 @@ Pandoc , Table ( "mytableid2" , [ "mytableclass3" , "mytableclass4" ] - , [ ( "custom-style" , "mytabstyle2" ) ] + , [ ( "role" , "tablerole2" ) + , ( "custom-style" , "mytabstyle2" ) + ] ) (Caption Nothing []) [ ( AlignDefault , ColWidthDefault ) From 58f471cf1c6bd32438dc3ab3783b98d475478d21 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Wed, 25 Jun 2025 16:36:58 +0200 Subject: [PATCH 08/54] pandoc-lua-engine: Allow hslua-2.4.0 in the tests --- pandoc-lua-engine/pandoc-lua-engine.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandoc-lua-engine/pandoc-lua-engine.cabal b/pandoc-lua-engine/pandoc-lua-engine.cabal index f83afe0c1406..1ebfba37be6e 100644 --- a/pandoc-lua-engine/pandoc-lua-engine.cabal +++ b/pandoc-lua-engine/pandoc-lua-engine.cabal @@ -144,7 +144,7 @@ test-suite test-pandoc-lua-engine , data-default , exceptions >= 0.8 && < 0.11 , filepath - , hslua >= 2.3 && < 2.4 + , hslua >= 2.3 && < 2.5 , pandoc , pandoc-types >= 1.22 && < 1.24 , tasty From 9d10af709ad64581df10b5a1dee2fefe80d5f2b2 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Mon, 23 Jun 2025 12:38:49 +0200 Subject: [PATCH 09/54] Lua: add more UTF-8-aware file operations to `pandoc.system`. Functions that expect UTF-8-encoded filenames should make it easier to write platform-independent scripts, as the encoding of the actual filename depends on the system. Additionally, this also adds a generalized method to run commands, and functions to retrieve XDG directory names. The new functions are `command`, `copy`, `read_file`, `remove`, `rename`, `times`, `write_file`, `xdg`. --- doc/lua-filters.md | 174 ++++++++++++++++++ pandoc-lua-engine/pandoc-lua-engine.cabal | 2 +- .../src/Text/Pandoc/Lua/Module/System.hs | 14 +- stack.yaml | 1 + 4 files changed, 188 insertions(+), 3 deletions(-) diff --git a/doc/lua-filters.md b/doc/lua-filters.md index f728e5bdbec2..7bbef63fd526 100644 --- a/doc/lua-filters.md +++ b/doc/lua-filters.md @@ -5534,6 +5534,53 @@ Returns: *Since: 3.1.1* +### command {#pandoc.system.command} + +`command (command, args[, input[, opts]])` + +Executes a system command with the given arguments and `input` on +*stdin*. + +Parameters: + +`command` +: command to execute (string) + +`args` +: command arguments ({string,\...}) + +`input` +: input on stdin (string) + +`opts` +: process options (table) + +Returns: + +- exit code -- `false` on success, an integer otherwise + ([integer]{unknown-type="integer"}\|boolean) +- stdout (string) +- stderr (string) + +*Since: 3.7.1* + +### copy {#pandoc.system.copy} + +`copy (source, target)` + +Copy a file with its permissions. If the destination file already +exists, it is overwritten. + +Parameters: + +`source` +: source file (string) + +`target` +: target destination (string) + +*Since: 3.7.1* + ### environment {#pandoc.system.environment} `environment ()` @@ -5602,6 +5649,61 @@ Parameters: *Since: 2.19* +### read_file {#pandoc.system.read_file} + +`read_file (filepath)` + +Parameters: + +`filepath` +: File to read (string) + +Returns: + +- file contents (string) + +*Since: 3.7.1* + +### rename {#pandoc.system.rename} + +`rename (old, new)` + +Change the name of an existing path from `old` to `new`. + +If `old` is a directory and `new` is a directory that already +exists, then `new` is atomically replaced by the `old` directory. +On Win32 platforms, this function fails if `new` is an existing +directory. + +If `old` does not refer to a directory, then neither may `new`. + +Renaming may not work across file system boundaries or due to +other system-specific reasons. It's generally more robust to copy +the source path to its destination before deleting the source. + +Parameters: + +`old` +: original path (string) + +`new` +: new path (string) + +*Since: 3.7.1* + +### remove {#pandoc.system.remove} + +`remove (filename)` + +Removes the directory entry for an existing file. + +Parameters: + +`filename` +: file to remove (string) + +*Since: 3.7.1* + ### remove_directory {#pandoc.system.remove_directory} `remove_directory (dirname[, recursive])` @@ -5619,6 +5721,25 @@ Parameters: *Since: 2.19* +### times {#pandoc.system.times} + +`times (filepath)` + +Obtain the modification and access time of a file or directory. +The times are returned as strings using the ISO 8601 format. + +Parameters: + +`filepath` +: file or directory path (string) + +Returns: + +- time at which the file or directory was last modified (table) +- time at which the file or directory was last accessed (table) + +*Since: 3.7.1* + ### with_environment {#pandoc.system.with_environment} `with_environment (environment, callback)` @@ -5695,6 +5816,58 @@ The results of the call to `callback`. *Since: 2.7.3* +### write_file {#pandoc.system.write_file} + +`write_file (filepath, contents)` + +Writes a string to a file. + +Parameters: + +`filepath` +: path to target file (string) + +`contents` +: file contents (string) + +*Since: 3.7.1* + +### xdg {#pandoc.system.xdg} + +`xdg (xdg_directory_type[, filepath])` + +Access special directories and directory search paths. + +Special directories for storing user-specific application data, +configuration, and cache files, as specified by the [XDG Base +Directory Specification]. + +Parameters: + +`xdg_directory_type` + +: The type of the XDG directory or search path. Must be one of + `config`, `data`, `cache`, `state`, `datadirs`, or + `configdirs`. + + Matching is case-insensitive, and underscores and `XDG` + prefixes are ignored, so a value like `XDG_DATA_DIRS` is also + acceptable. + + The `state` directory might not be available, depending on the + version of the underlying Haskell library. (string) + +`filepath` +: relative path that is appended to the path; ignored if the + result is a list of search paths. (string) + +Returns: + +- Either a single file path, or a list of search paths. + (string\|{string,\...}) + +*Since: 3.7.1* + @@ -6982,6 +7155,7 @@ Returns: [null]: #pandoc.json.null [this blog post]: http://neilmitchell.blogspot.co.uk/2015/10/filepaths-are-subtle-symlinks-are-hard.html [ChunkedDoc]: #type-chunkeddoc + [XDG Base Directory Specification]: https://specifications.freedesktop.org/basedir-spec/latest/ [Doc]: #type-doc [Template]: #type-template [zip.Entry]: #type-pandoc.zip.Entry diff --git a/pandoc-lua-engine/pandoc-lua-engine.cabal b/pandoc-lua-engine/pandoc-lua-engine.cabal index 1ebfba37be6e..5cd6c570bf37 100644 --- a/pandoc-lua-engine/pandoc-lua-engine.cabal +++ b/pandoc-lua-engine/pandoc-lua-engine.cabal @@ -119,7 +119,7 @@ library , hslua >= 2.3 && < 2.5 , hslua-module-doclayout>= 1.2 && < 1.3 , hslua-module-path >= 1.1 && < 1.2 - , hslua-module-system >= 1.1 && < 1.2 + , hslua-module-system >= 1.2 && < 1.3 , hslua-module-text >= 1.1 && < 1.2 , hslua-module-version >= 1.1 && < 1.2 , hslua-module-zip >= 1.1.3 && < 1.2 diff --git a/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/System.hs b/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/System.hs index ef5c63d6ae9d..c6a124166293 100644 --- a/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/System.hs +++ b/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/System.hs @@ -18,8 +18,10 @@ module Text.Pandoc.Lua.Module.System import Data.Version (makeVersion) import HsLua import HsLua.Module.System - ( arch, cputime, env, getwd, ls, mkdir, os, rmdir - , with_env, with_tmpdir, with_wd) + ( arch, cmd, cp, cputime, env, getwd, ls, mkdir, os, read_file + , rename, rm, rmdir, times, with_env, with_tmpdir, with_wd + , write_file, xdg + ) import qualified HsLua.Module.System as MSys -- | Push the pandoc.system module on the Lua stack. @@ -33,14 +35,22 @@ documentedModule = Module ] , moduleFunctions = [ cputime `since` v[3,1,1] + , setName "command" cmd `since` v[3,7,1] + , setName "copy" cp `since` v[3,7,1] , setName "environment" env `since` v[2,7,3] , setName "get_working_directory" getwd `since` v[2,8] , setName "list_directory" ls `since` v[2,19] , setName "make_directory" mkdir `since` v[2,19] + , read_file `since` v[3,7,1] + , rename `since` v[3,7,1] + , setName "remove" rm `since` v[3,7,1] , setName "remove_directory" rmdir `since` v[2,19] + , times `since` v[3,7,1] , setName "with_environment" with_env `since` v[2,7,3] , setName "with_temporary_directory" with_tmpdir `since` v[2,8] , setName "with_working_directory" with_wd `since` v[2,7,3] + , write_file `since` v[3,7,1] + , xdg `since` v[3,7,1] ] , moduleOperations = [] , moduleTypeInitializers = [] diff --git a/stack.yaml b/stack.yaml index 547f20758ab0..2f8df84a06fb 100644 --- a/stack.yaml +++ b/stack.yaml @@ -11,6 +11,7 @@ packages: extra-deps: - hslua-2.4.0 - hslua-module-doclayout-1.2.0.1 +- hslua-module-system-1.2.0 - hslua-objectorientation-2.4.0 - hslua-packaging-2.3.2 - pandoc-lua-marshal-0.3.1 From 198eaa028c8479e864096a26e4b74bbbe3576c64 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 6 Jul 2025 16:37:21 -0400 Subject: [PATCH 10/54] CI: use windows-2022. windows-2019 is no longer provided. --- .github/workflows/ci.yml | 2 +- .github/workflows/nightly.yml | 2 +- .github/workflows/release-candidate.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35e5f5ecacb8..e31fa85d26b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -184,7 +184,7 @@ jobs: windows: - runs-on: windows-2019 + runs-on: windows-2022 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 41ff88abf36a..203134d647a5 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -41,7 +41,7 @@ jobs: windows: - runs-on: windows-2019 + runs-on: windows-2022 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/release-candidate.yml b/.github/workflows/release-candidate.yml index 584346f85095..e7b1ba4473cd 100644 --- a/.github/workflows/release-candidate.yml +++ b/.github/workflows/release-candidate.yml @@ -8,7 +8,7 @@ permissions: jobs: windows: - runs-on: windows-2019 + runs-on: windows-2022 strategy: fail-fast: true matrix: From dbcdb0ca326e7354a0d5a383b449e690461038f2 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 7 Jul 2025 20:27:24 -0400 Subject: [PATCH 11/54] PDF: make images from MediaBag available in tmp dir... for every PDF engine, not just LaTeX/ConTeXt. This is part of the fix for #10911. --- src/Text/Pandoc/PDF.hs | 60 ++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs index e3157ce96a22..22757f103a79 100644 --- a/src/Text/Pandoc/PDF.hs +++ b/src/Text/Pandoc/PDF.hs @@ -81,7 +81,19 @@ makePDF :: (PandocMonad m, MonadIO m, MonadMask m) -> WriterOptions -- ^ options -> Pandoc -- ^ document -> m (Either ByteString ByteString) -makePDF program pdfargs writer opts doc = +makePDF program pdfargs writer opts doc = withTempDir (program == "typst") "media" $ \mediaDir -> do +#ifdef _WINDOWS + -- note: we want / even on Windows, for TexLive + let tmpdir = changePathSeparators mediaDir +#else + let tmpdir = mediaDir +#endif + doc' <- handleImages opts tmpdir doc + source <- writer opts{ writerExtensions = -- disable use of quote + -- ligatures to avoid bad ligatures like ?` + disableExtension Ext_smart + (writerExtensions opts) } doc' + verbosity <- getVerbosity case takeBaseName program of "wkhtmltopdf" -> makeWithWkhtmltopdf program pdfargs writer opts doc prog | prog `elem` ["pagedjs-cli" ,"weasyprint", "prince"] -> do @@ -89,16 +101,10 @@ makePDF program pdfargs writer opts doc = if program `elem` ["pagedjs-cli", "prince"] then ["-o", f] else [f] - source <- writer opts doc - verbosity <- getVerbosity liftIO $ toPdfViaTempFile verbosity program pdfargs mkOutArgs ".html" source - "typst" -> do - source <- writer opts doc - verbosity <- getVerbosity - liftIO $ + "typst" -> liftIO $ toPdfViaTempFile verbosity program ("compile":pdfargs) (:[]) ".typ" source "pdfroff" -> do - source <- writer opts doc let paperargs = case lookupContext "papersize" (writerVariables opts) of Just s @@ -112,7 +118,6 @@ makePDF program pdfargs writer opts doc = paperargs ++ pdfargs generic2pdf program args source "groff" -> do - source <- writer opts doc let paperargs = case lookupContext "papersize" (writerVariables opts) of Just s @@ -125,33 +130,20 @@ makePDF program pdfargs writer opts doc = ["-U" | ".PDFPIC" `T.isInfixOf` source] ++ paperargs ++ pdfargs generic2pdf program args source - baseProg -> do - withTempDir "tex2pdf." $ \tmpdir' -> do -#ifdef _WINDOWS - -- note: we want / even on Windows, for TexLive - let tmpdir = changePathSeparators tmpdir' -#else - let tmpdir = tmpdir' -#endif - doc' <- handleImages opts tmpdir doc - source <- writer opts{ writerExtensions = -- disable use of quote - -- ligatures to avoid bad ligatures like ?` - disableExtension Ext_smart - (writerExtensions opts) } doc' - case baseProg of - "context" -> context2pdf program pdfargs tmpdir source - "tectonic" -> tectonic2pdf program pdfargs tmpdir source - prog | prog `elem` ["pdflatex", "lualatex", "xelatex", "latexmk"] - -> tex2pdf program pdfargs tmpdir source - _ -> return $ Left $ UTF8.fromStringLazy - $ "Unknown program " ++ program + baseProg -> + case baseProg of + "context" -> context2pdf program pdfargs tmpdir source + "tectonic" -> tectonic2pdf program pdfargs tmpdir source + prog | prog `elem` ["pdflatex", "lualatex", "xelatex", "latexmk"] + -> tex2pdf program pdfargs tmpdir source + _ -> return $ Left $ UTF8.fromStringLazy $ "Unknown program " ++ program -- latex has trouble with tildes in paths, which -- you find in Windows temp dir paths with longer -- user names (see #777) withTempDir :: (PandocMonad m, MonadMask m, MonadIO m) - => FilePath -> (FilePath -> m a) -> m a -withTempDir templ action = do + => Bool -> FilePath -> (FilePath -> m a) -> m a +withTempDir useWorkingDirectory templ action = do tmp <- liftIO getTemporaryDirectory uname <- liftIO $ E.catch (do (ec, sout, _) <- readProcessWithExitCode "uname" ["-o"] "" @@ -159,9 +151,9 @@ withTempDir templ action = do then return $ Just $ filter (not . isSpace) sout else return Nothing) (\(_ :: E.SomeException) -> return Nothing) - if '~' `elem` tmp || uname == Just "Cygwin" -- see #5451 - then withTempDirectory "." templ action - else withSystemTempDirectory templ action + if useWorkingDirectory || '~' `elem` tmp || uname == Just "Cygwin" -- see #5451 + then withTempDirectory "." templ action + else withSystemTempDirectory templ action makeWithWkhtmltopdf :: (PandocMonad m, MonadIO m) => String -- ^ wkhtmltopdf or path From 71743f96582118308949e3f42db8347fc9b119fc Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 9 Jul 2025 19:02:15 -0400 Subject: [PATCH 12/54] PDF: Use utf8ToText for LaTeX log messages. --- src/Text/Pandoc/PDF.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs index 22757f103a79..0e198b0bb14b 100644 --- a/src/Text/Pandoc/PDF.hs +++ b/src/Text/Pandoc/PDF.hs @@ -320,7 +320,7 @@ latexWarnings log' = foldM_ go Nothing (BC.lines log') go (Just msg) ln | ln == "" = do -- emit report and reset accumulator report $ MakePDFWarning $ render (Just 60) $ - hsep $ map literal $ T.words $ UTF8.toText $ BC.toStrict msg + hsep $ map literal $ T.words $ utf8ToText msg pure Nothing | otherwise = pure $ Just (msg <> ln) From 0d68b9147d248dbca74798f0a4d98ab1fe57c0d9 Mon Sep 17 00:00:00 2001 From: Sean Soon Date: Thu, 10 Jul 2025 08:46:07 +0100 Subject: [PATCH 13/54] doc/lua-filters.md: Add example on using pandoc.Table constructor. (#10956) --- doc/lua-filters.md | 129 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/doc/lua-filters.md b/doc/lua-filters.md index 7bbef63fd526..4725967eb75f 100644 --- a/doc/lua-filters.md +++ b/doc/lua-filters.md @@ -736,6 +736,133 @@ function Pandoc(el) end ``` +## Creating a table + +This filter creates a document that contains the following +table with 5 columns. It serves as a working example of how +to use the [`pandoc.Table`](#pandoc.Table) constructor. + ++--------+--------+--------+--------+---+ +| This | is my | table | header | | ++========+:=======+:======:+=======:+===+ +| Cell 1 | Cell 2 | Cell 3 | | | ++--------+--------+--------+--------+---+ +| Cell 4 | Cell 5 | Cell 6 | | | ++========+========+========+========+===+ +| This is my table footer. | | ++===================================+===+ + +: This is my table caption. + +Note that: + +- The number of columns in the resulting Table element is + equal to the number of entries in the `colspecs` parameter. + +- A [ColSpec] object must contain the cell alignment, but the + column width is optional. + +- A [TableBody] object is specified using a Lua table in the + `bodies` parameter because there is no `pandoc.TableBody` + constructor. + +```lua +function Pandoc () + local caption = pandoc.Caption( "This is my table caption." ) + local colspecs = { + { pandoc.AlignLeft }, + { pandoc.AlignDefault }, + { pandoc.AlignCenter }, + { pandoc.AlignRight }, + { pandoc.AlignDefault } + } + local head = pandoc.TableHead{ + pandoc.Row{ + pandoc.Cell( "This" ), + pandoc.Cell( "is my" ), + pandoc.Cell( "table" ), + pandoc.Cell( "header" ) + } + } + local bodies = { + { + attr={}, + body={ + pandoc.Row{ + pandoc.Cell( "Cell 1" ), + pandoc.Cell( "Cell 2" ), + pandoc.Cell( "Cell 3" ) + }, + pandoc.Row{ + pandoc.Cell( "Cell 4" ), + pandoc.Cell( "Cell 5" ), + pandoc.Cell( "Cell 6" ) + } + }, + head={}, + row_head_columns=0 + } + } + local foot = pandoc.TableFoot{ + pandoc.Row{ + pandoc.Cell( "This is my table footer.", pandoc.AlignDefault, 1, 4 ) + } + } + return pandoc.Pandoc { + pandoc.Table(caption, colspecs, head, bodies, foot) + } +end +``` + +## Extracting links from a document + +This filter creates a document containing a table that lists +the URLs the input document links to, together with the +number of links to each URL. + +```lua +links = {} + +function Link (el) + if links[el.target] then + links[el.target] = links[el.target] + 1 + else + links[el.target] = 1 + end + return el +end + +function Pandoc () + local caption = pandoc.Caption("Link count.") + local colspecs = { + { pandoc.AlignDefault, 0.8 }, + { pandoc.AlignLeft, 0.2 } + } + local head = pandoc.TableHead{ + pandoc.Row{ pandoc.Cell("Target"), pandoc.Cell("Count") } + } + local foot = pandoc.TableFoot() + local rows = {} + for link, count in pairs(links) do + rows[#rows + 1] = pandoc.Row{ + pandoc.Cell( link ), + pandoc.Cell( pandoc.utils.stringify(count) ) + } + end + local bodies = { + { + attr={}, + body=rows, + head={}, + row_head_columns=0 + } + } + return pandoc.Pandoc { + pandoc.Table(caption, colspecs, head, bodies, foot) + } +end +``` + ## Converting ABC code to music notation This filter replaces code blocks with class `abc` with images @@ -903,7 +1030,7 @@ Usage: Pandoc document Values of this type can be created with the -[`pandoc.Pandoc`](#pandoc.pandoc) constructor. Pandoc values are +[`pandoc.Pandoc`](#pandoc.Pandoc) constructor. Pandoc values are equal in Lua if and only if they are equal in Haskell. `blocks` From 10307e357449264b7f9d1828144b50653e02aa0f Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 13 Jul 2025 09:05:53 -0700 Subject: [PATCH 14/54] Update `--version` copyright dates. Closes #10961. --- src/Text/Pandoc/App/CommandLineOptions.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs index a4fec880dcb5..22a6bafa9a34 100644 --- a/src/Text/Pandoc/App/CommandLineOptions.hs +++ b/src/Text/Pandoc/App/CommandLineOptions.hs @@ -1172,7 +1172,7 @@ usageMessage programName = usageInfo (programName ++ " [OPTIONS] [FILES]") copyrightMessage :: String copyrightMessage = intercalate "\n" [ - "Copyright (C) 2006-2024 John MacFarlane. Web: https://pandoc.org", + "Copyright (C) 2006-2025 John MacFarlane. Web: https://pandoc.org", "This is free software; see the source for copying conditions. There is no", "warranty, not even for merchantability or fitness for a particular purpose." ] From a493340ee2e2da132e1cf84dfb3038998432921b Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 13 Jul 2025 12:23:56 -0700 Subject: [PATCH 15/54] Use hardcoded string "pandoc" for program name in `--version`. Per GNU guidelines: https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html --- pandoc-cli/src/pandoc.hs | 3 +-- src/Text/Pandoc/App/CommandLineOptions.hs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pandoc-cli/src/pandoc.hs b/pandoc-cli/src/pandoc.hs index 019d0adedb15..9e82d02bcc99 100644 --- a/pandoc-cli/src/pandoc.hs +++ b/pandoc-cli/src/pandoc.hs @@ -91,11 +91,10 @@ flagSettings = "Features: " ++ versionInfo :: IO () versionInfo = do - progname <- getProgName defaultDatadir <- defaultUserDataDir scriptingEngine <- getEngine UTF8.putStr $ T.unlines $ map T.pack - [ progname ++ " " ++ showVersion pandocVersion ++ versionSuffix + [ "pandoc " ++ showVersion pandocVersion ++ versionSuffix , flagSettings , "Scripting engine: " ++ T.unpack (engineName scriptingEngine) , "User data directory: " ++ defaultDatadir diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs index 22a6bafa9a34..db7d5a1ac8dc 100644 --- a/src/Text/Pandoc/App/CommandLineOptions.hs +++ b/src/Text/Pandoc/App/CommandLineOptions.hs @@ -194,11 +194,10 @@ handleOptInfo engine info = E.handle (handleError . Left) $ do ,confNumFormat = Generic ,confTrailingNewline = True} sty VersionInfo -> do - prg <- getProgName defaultDatadir <- defaultUserDataDir UTF8.hPutStrLn stdout $ T.pack - $ prg ++ " " ++ T.unpack pandocVersionText ++ + $ "pandoc " ++ T.unpack pandocVersionText ++ "\nUser data directory: " ++ defaultDatadir ++ ('\n':copyrightMessage) Help -> do From b718f9eb1420fa3ccb564be94e16eec28b7797af Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 13 Jul 2025 12:33:12 -0700 Subject: [PATCH 16/54] Export `copyrightMessage` from Text.Pandoc.App module. Export `copyrightMessage` from the unexported module Text.Pandoc.App.CommandLineOptions and reexport from Text.Pandoc.App [API change]. This avoids the need for a duplicated version in pandoc-cli, which can now depend on the library's exported version. --- pandoc-cli/src/pandoc.hs | 9 +-------- src/Text/Pandoc/App.hs | 3 ++- src/Text/Pandoc/App/CommandLineOptions.hs | 1 + 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/pandoc-cli/src/pandoc.hs b/pandoc-cli/src/pandoc.hs index 9e82d02bcc99..dd172696a3d6 100644 --- a/pandoc-cli/src/pandoc.hs +++ b/pandoc-cli/src/pandoc.hs @@ -16,7 +16,7 @@ module Main where import qualified Control.Exception as E import System.Environment (getArgs, getProgName) import Text.Pandoc.App ( convertWithOpts, defaultOpts, options - , parseOptionsFromArgs, handleOptInfo ) + , parseOptionsFromArgs, handleOptInfo, copyrightMessage ) import Text.Pandoc.Error (handleError) import System.Exit (exitSuccess) import Data.Monoid (Any(..)) @@ -67,13 +67,6 @@ main = E.handle (handleError . Left) $ do Left e -> handleOptInfo engine e Right opts -> convertWithOpts engine opts -copyrightMessage :: String -copyrightMessage = - "Copyright (C) 2006-2024 John MacFarlane. Web: https://pandoc.org\n" - ++ - "This is free software; see the source for copying conditions. There is no\n" - ++ - "warranty, not even for merchantability or fitness for a particular purpose." flagSettings :: String flagSettings = "Features: " ++ diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index 8585fc55565a..7b1b7ec107ee 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -26,6 +26,7 @@ module Text.Pandoc.App ( , parseOptionsFromArgs , options , applyFilters + , copyrightMessage ) where import qualified Control.Exception as E import Control.Monad ( (>=>), when, forM, forM_ ) @@ -55,7 +56,7 @@ import Text.Pandoc.Image (svgToPng) import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), defaultOpts, IpynbOutput (..), OptInfo(..)) import Text.Pandoc.App.CommandLineOptions (parseOptions, parseOptionsFromArgs, - options, handleOptInfo) + options, handleOptInfo, copyrightMessage) import Text.Pandoc.App.Input (InputParameters (..), readInput) import Text.Pandoc.App.OutputSettings (OutputSettings (..), optToOutputSettings, sandbox') diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs index db7d5a1ac8dc..383ab04a7d53 100644 --- a/src/Text/Pandoc/App/CommandLineOptions.hs +++ b/src/Text/Pandoc/App/CommandLineOptions.hs @@ -21,6 +21,7 @@ module Text.Pandoc.App.CommandLineOptions ( , options , engines , setVariable + , copyrightMessage ) where import Control.Monad.Trans import Control.Monad.State.Strict From 8f66ada0cec8e4c516a3c480ce9b3589b7d74806 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 13 Jul 2025 22:46:10 -0700 Subject: [PATCH 17/54] Revert "Export `copyrightMessage` from Text.Pandoc.App module." This reverts commit 2cf9b55421d7026dac8c45730b8538f13e4bbb78. --- pandoc-cli/src/pandoc.hs | 9 ++++++++- src/Text/Pandoc/App.hs | 3 +-- src/Text/Pandoc/App/CommandLineOptions.hs | 1 - 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pandoc-cli/src/pandoc.hs b/pandoc-cli/src/pandoc.hs index dd172696a3d6..9e82d02bcc99 100644 --- a/pandoc-cli/src/pandoc.hs +++ b/pandoc-cli/src/pandoc.hs @@ -16,7 +16,7 @@ module Main where import qualified Control.Exception as E import System.Environment (getArgs, getProgName) import Text.Pandoc.App ( convertWithOpts, defaultOpts, options - , parseOptionsFromArgs, handleOptInfo, copyrightMessage ) + , parseOptionsFromArgs, handleOptInfo ) import Text.Pandoc.Error (handleError) import System.Exit (exitSuccess) import Data.Monoid (Any(..)) @@ -67,6 +67,13 @@ main = E.handle (handleError . Left) $ do Left e -> handleOptInfo engine e Right opts -> convertWithOpts engine opts +copyrightMessage :: String +copyrightMessage = + "Copyright (C) 2006-2024 John MacFarlane. Web: https://pandoc.org\n" + ++ + "This is free software; see the source for copying conditions. There is no\n" + ++ + "warranty, not even for merchantability or fitness for a particular purpose." flagSettings :: String flagSettings = "Features: " ++ diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index 7b1b7ec107ee..8585fc55565a 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -26,7 +26,6 @@ module Text.Pandoc.App ( , parseOptionsFromArgs , options , applyFilters - , copyrightMessage ) where import qualified Control.Exception as E import Control.Monad ( (>=>), when, forM, forM_ ) @@ -56,7 +55,7 @@ import Text.Pandoc.Image (svgToPng) import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), defaultOpts, IpynbOutput (..), OptInfo(..)) import Text.Pandoc.App.CommandLineOptions (parseOptions, parseOptionsFromArgs, - options, handleOptInfo, copyrightMessage) + options, handleOptInfo) import Text.Pandoc.App.Input (InputParameters (..), readInput) import Text.Pandoc.App.OutputSettings (OutputSettings (..), optToOutputSettings, sandbox') diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs index 383ab04a7d53..db7d5a1ac8dc 100644 --- a/src/Text/Pandoc/App/CommandLineOptions.hs +++ b/src/Text/Pandoc/App/CommandLineOptions.hs @@ -21,7 +21,6 @@ module Text.Pandoc.App.CommandLineOptions ( , options , engines , setVariable - , copyrightMessage ) where import Control.Monad.Trans import Control.Monad.State.Strict From 27b29263012e7a8b26469970ddf233281d184dc0 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 13 Jul 2025 22:47:11 -0700 Subject: [PATCH 18/54] Remove code duplication around version info. Text.Pandoc.App.CommandLineOptions and pandoc-cli/src/pandoc.hs had similar code for generating version information. To avoid duplication, we now export `versionInfo` from Text.Pandoc.App [API change]. (The function is reexported from the non-public module Text.Pandoc.App.CommandLineOptions.) This function has three parameters that can be filled in when it is called by pandoc-cli. This change will make it simpler to revise version information. --- pandoc-cli/src/pandoc.hs | 39 +++++++---------------- src/Text/Pandoc/App.hs | 3 +- src/Text/Pandoc/App/CommandLineOptions.hs | 28 ++++++++++++---- 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/pandoc-cli/src/pandoc.hs b/pandoc-cli/src/pandoc.hs index 9e82d02bcc99..d110c6f622fb 100644 --- a/pandoc-cli/src/pandoc.hs +++ b/pandoc-cli/src/pandoc.hs @@ -16,17 +16,12 @@ module Main where import qualified Control.Exception as E import System.Environment (getArgs, getProgName) import Text.Pandoc.App ( convertWithOpts, defaultOpts, options - , parseOptionsFromArgs, handleOptInfo ) + , parseOptionsFromArgs, handleOptInfo, versionInfo ) import Text.Pandoc.Error (handleError) -import System.Exit (exitSuccess) import Data.Monoid (Any(..)) import PandocCLI.Lua import PandocCLI.Server -import qualified Text.Pandoc.UTF8 as UTF8 -import Text.Pandoc.Version (pandocVersion) -import Text.Pandoc.Data (defaultUserDataDir) import Text.Pandoc.Scripting (ScriptingEngine(..)) -import Data.Version (showVersion) import qualified Data.Text as T #ifdef NIGHTLY @@ -51,7 +46,7 @@ main = E.handle (handleError . Left) $ do let hasVersion = getAny $ foldMap (\s -> Any (s == "-v" || s == "--version")) (takeWhile (/= "--") rawArgs) - let versionOr action = if hasVersion then versionInfo else action + let versionOr action = if hasVersion then versionInfoCLI else action case prg of "pandoc-server.cgi" -> versionOr runCGI "pandoc-server" -> versionOr $ runServer rawArgs @@ -67,37 +62,25 @@ main = E.handle (handleError . Left) $ do Left e -> handleOptInfo engine e Right opts -> convertWithOpts engine opts -copyrightMessage :: String -copyrightMessage = - "Copyright (C) 2006-2024 John MacFarlane. Web: https://pandoc.org\n" - ++ - "This is free software; see the source for copying conditions. There is no\n" - ++ - "warranty, not even for merchantability or fitness for a particular purpose." -flagSettings :: String -flagSettings = "Features: " ++ +getFeatures :: [String] +getFeatures = [ #ifdef VERSION_pandoc_server "+server" #else "-server" #endif - ++ " " ++ + , #ifdef VERSION_hslua_cli "+lua" #else "-lua" #endif + ] -versionInfo :: IO () -versionInfo = do - defaultDatadir <- defaultUserDataDir +versionInfoCLI :: IO () +versionInfoCLI = do scriptingEngine <- getEngine - UTF8.putStr $ T.unlines $ map T.pack - [ "pandoc " ++ showVersion pandocVersion ++ versionSuffix - , flagSettings - , "Scripting engine: " ++ T.unpack (engineName scriptingEngine) - , "User data directory: " ++ defaultDatadir - , copyrightMessage - ] - exitSuccess + versionInfo getFeatures + (Just $ T.unpack (engineName scriptingEngine)) + versionSuffix diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index 8585fc55565a..a5a117c0466a 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -26,6 +26,7 @@ module Text.Pandoc.App ( , parseOptionsFromArgs , options , applyFilters + , versionInfo ) where import qualified Control.Exception as E import Control.Monad ( (>=>), when, forM, forM_ ) @@ -55,7 +56,7 @@ import Text.Pandoc.Image (svgToPng) import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), defaultOpts, IpynbOutput (..), OptInfo(..)) import Text.Pandoc.App.CommandLineOptions (parseOptions, parseOptionsFromArgs, - options, handleOptInfo) + options, handleOptInfo, versionInfo) import Text.Pandoc.App.Input (InputParameters (..), readInput) import Text.Pandoc.App.OutputSettings (OutputSettings (..), optToOutputSettings, sandbox') diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs index db7d5a1ac8dc..b8a4e2fc953e 100644 --- a/src/Text/Pandoc/App/CommandLineOptions.hs +++ b/src/Text/Pandoc/App/CommandLineOptions.hs @@ -21,6 +21,7 @@ module Text.Pandoc.App.CommandLineOptions ( , options , engines , setVariable + , versionInfo ) where import Control.Monad.Trans import Control.Monad.State.Strict @@ -46,6 +47,7 @@ import System.IO (stdout) import Text.DocTemplates (Context (..), ToContext (toVal), Val (..)) import Text.Pandoc import Text.Pandoc.Builder (setMeta) +import Data.Version (showVersion) import Text.Pandoc.App.Opt (Opt (..), LineEnding (..), IpynbOutput (..), DefaultsState (..), applyDefaults, fullDefaultsPath, OptInfo(..)) @@ -193,13 +195,7 @@ handleOptInfo engine info = E.handle (handleError . Left) $ do ,"text-styles"]) ,confNumFormat = Generic ,confTrailingNewline = True} sty - VersionInfo -> do - defaultDatadir <- defaultUserDataDir - UTF8.hPutStrLn stdout - $ T.pack - $ "pandoc " ++ T.unpack pandocVersionText ++ - "\nUser data directory: " ++ defaultDatadir ++ - ('\n':copyrightMessage) + VersionInfo -> versionInfo [] Nothing "" Help -> do prg <- getProgName UTF8.hPutStr stdout (T.pack $ usageMessage prg options) @@ -1269,3 +1265,21 @@ normalizePath fp = #else normalizePath = id #endif + +-- | Print version information with customizable features and scripting engine +versionInfo :: [String] -> Maybe String -> String -> IO () +versionInfo features mbScriptingEngineName suffix = do + defaultDatadir <- defaultUserDataDir + let featuresLine = if null features + then [] + else ["Features: " ++ unwords features] + let scriptingLine = case mbScriptingEngineName of + Nothing -> [] + Just name -> ["Scripting engine: " ++ name] + UTF8.putStr $ T.unlines $ map T.pack $ + ["pandoc " ++ showVersion pandocVersion ++ suffix] ++ + featuresLine ++ + scriptingLine ++ + ["User data directory: " ++ defaultDatadir, + copyrightMessage] + exitSuccess From f0fc5fdd7d822f3815406152eba4c8b142f935af Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 14 Jul 2025 11:52:22 -0700 Subject: [PATCH 19/54] Typst writer: set lang attribute in Divs. Closes #10965. --- src/Text/Pandoc/Writers/Typst.hs | 10 ++++++- test/command/10965.md | 47 ++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 test/command/10965.md diff --git a/src/Text/Pandoc/Writers/Typst.hs b/src/Text/Pandoc/Writers/Typst.hs index 775522ff2be0..90409cbbf52e 100644 --- a/src/Text/Pandoc/Writers/Typst.hs +++ b/src/Text/Pandoc/Writers/Typst.hs @@ -342,9 +342,17 @@ blockToTypst block = Div (ident,_,kvs) blocks -> do let lab = toLabel FreestandingLabel ident let (typstAttrs,typstTextAttrs) = pickTypstAttrs kvs + -- Handle lang attribute for Div elements + let langAttrs = case lookup "lang" kvs of + Nothing -> [] + Just lang -> case parseLang lang of + Left _ -> [] + Right l -> [("lang", + tshow (langLanguage l))] + let allTypstTextAttrs = typstTextAttrs ++ langAttrs contents <- blocksToTypst blocks return $ "#block" <> toTypstPropsListParens typstAttrs <> "[" - $$ toTypstPoundSetText typstTextAttrs <> contents + $$ toTypstPoundSetText allTypstTextAttrs <> contents $$ ("]" <+> lab) defListItemToTypst :: PandocMonad m => ([Inline], [[Block]]) -> TW m (Doc Text) diff --git a/test/command/10965.md b/test/command/10965.md new file mode 100644 index 000000000000..565723278a2b --- /dev/null +++ b/test/command/10965.md @@ -0,0 +1,47 @@ +``` +% pandoc -f markdown -t typst +::: {lang="en"} +This text should be in English. +::: +^D +#block[ +#set text(lang: "en"); This text should be in English. + +] +``` + +``` +% pandoc -f markdown -t typst +::: {lang="fr"} +Ce texte devrait être en français. +::: +^D +#block[ +#set text(lang: "fr"); Ce texte devrait être en français. + +] +``` + +``` +% pandoc -f markdown -t typst +::: {lang="de-DE"} +Dieser Text sollte auf Deutsch sein. +::: +^D +#block[ +#set text(lang: "de"); Dieser Text sollte auf Deutsch sein. + +] +``` + +``` +% pandoc -f markdown -t typst +::: {lang=""} +This should not have lang set. +::: +^D +#block[ +This should not have lang set. + +] +``` From 965c74af8fbb73b0a94f2fa36127019fbf6b2301 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Sat, 19 Jul 2025 15:33:21 +0200 Subject: [PATCH 20/54] Lua: add `normalize` function to *Pandoc* objects This function performs a normalization of Pandoc documents. E.g., multiple successive spaces are collapsed, and tables are normalized such that all rows and columns contain the same number of cells. Closes: #10356 --- doc/lua-filters.md | 18 ++++++++++++++++++ pandoc-lua-engine/test/lua/module/pandoc.lua | 7 +++++++ 2 files changed, 25 insertions(+) diff --git a/doc/lua-filters.md b/doc/lua-filters.md index 4725967eb75f..1f5998fb52aa 100644 --- a/doc/lua-filters.md +++ b/doc/lua-filters.md @@ -1039,6 +1039,24 @@ equal in Lua if and only if they are equal in Haskell. `meta` : document meta information ([Meta] object) +### Methods {#type-pandoc-methods} + +#### normalize + +`normalize(self)` + +Perform a normalization of Pandoc documents. E.g., multiple +successive spaces are collapsed, and tables are normalized, so +that all rows and columns contain the same number of cells. + +Parameters: + +`self` +: the element ([Pandoc][]) + +Results: + +- cloned and normalized document. ([Pandoc][]) ### walk {#type-pandoc:walk} diff --git a/pandoc-lua-engine/test/lua/module/pandoc.lua b/pandoc-lua-engine/test/lua/module/pandoc.lua index 18b3c64a956c..3d745b42861f 100644 --- a/pandoc-lua-engine/test/lua/module/pandoc.lua +++ b/pandoc-lua-engine/test/lua/module/pandoc.lua @@ -164,6 +164,13 @@ return { assert.are_same(meta.test, {pandoc.Plain{pandoc.Str 'check'}}) end), }, + group 'Pandoc' { + test('normalize', function () + local doc = pandoc.Pandoc({{'a', pandoc.Space(), pandoc.Space(), 'b'}}) + local normalized = pandoc.Pandoc({{'a', pandoc.Space(), 'b'}}) + assert.are_equal(normalized, doc:normalize()) + end), + }, group 'Other types' { group 'ReaderOptions' { test('returns a userdata value', function () From 356a50748de7970a69a472d16628812ec11ebd73 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 20 Jul 2025 00:11:34 -0700 Subject: [PATCH 21/54] Use latest dev citeproc and update the default CSL... from the latest chicago-author-date.csl. (Note that this goes from the 17th to the 18th edition.) Update tests. --- cabal.project | 4 +- data/default.csl | 4279 +++++++++++++++-- src/Text/Pandoc/Citeproc.hs | 6 +- src/Text/Pandoc/Readers/EndNote.hs | 2 + test/command/10185.md | 2 +- test/command/6783.md | 2 +- test/command/6890.md | 22 +- test/command/6951.md | 2 +- test/command/7219.md | 2 +- test/command/7329.md | 4 +- test/command/8354.md | 2 +- test/command/9017.md | 3 +- test/command/9904.md | 4 +- test/command/citeproc-87.md | 4 +- test/command/pandoc-citeproc-118.md | 5 +- test/command/pandoc-citeproc-136.md | 2 +- test/command/pandoc-citeproc-14.md | 22 +- test/command/pandoc-citeproc-175.md | 4 +- test/command/pandoc-citeproc-25.md | 4 +- test/command/pandoc-citeproc-250.md | 4 +- test/command/pandoc-citeproc-301.md | 10 +- test/command/pandoc-citeproc-307.md | 2 +- test/command/pandoc-citeproc-320a.md | 14 +- test/command/pandoc-citeproc-325.md | 8 +- test/command/pandoc-citeproc-327.md | 2 +- test/command/pandoc-citeproc-371.md | 4 +- test/command/pandoc-citeproc-38.md | 6 +- test/command/pandoc-citeproc-401.md | 10 +- test/command/pandoc-citeproc-408.md | 6 +- test/command/pandoc-citeproc-416.md | 8 +- test/command/pandoc-citeproc-47.md | 8 +- test/command/pandoc-citeproc-51.md | 2 +- test/command/pandoc-citeproc-64.md | 8 +- test/command/pandoc-citeproc-65.md | 5 +- test/command/pandoc-citeproc-7.md | 4 +- test/command/pandoc-citeproc-70.md | 8 +- test/command/pandoc-citeproc-76.md | 10 +- test/command/pandoc-citeproc-87.md | 38 +- .../pandoc-citeproc-chicago-author-date.md | 8 +- test/command/pandoc-citeproc-no-author.md | 14 +- .../pandoc-citeproc-number-of-volumes.md | 4 +- 41 files changed, 3923 insertions(+), 635 deletions(-) diff --git a/cabal.project b/cabal.project index 708f2a847328..c17d2bf0d73a 100644 --- a/cabal.project +++ b/cabal.project @@ -11,7 +11,7 @@ constraints: skylighting-format-blaze-html >= 0.1.1.3, source-repository-package type: git - location: https://github.com/jgm/citeproc.git - tag: 157c7815f06e4e6771740a4eb8df97568626a8fe + location: file:///Users/jgm/src/citeproc + tag: ca4affae538dc4c104bb2411eae8c3167ab3da24 -- TODO: release new skylighting-core, skylighting diff --git a/data/default.csl b/data/default.csl index ec19900821bb..8b344d44a594 100644 --- a/data/default.csl +++ b/data/default.csl @@ -1,679 +1,3974 @@ - diff --git a/src/Text/Pandoc/Citeproc.hs b/src/Text/Pandoc/Citeproc.hs index a290a8bdfdd4..5ab245e1697a 100644 --- a/src/Text/Pandoc/Citeproc.hs +++ b/src/Text/Pandoc/Citeproc.hs @@ -299,6 +299,8 @@ getCitations locale otherIdsMap = Foldable.toList . query getCitation where getCitation (Cite cs _fallback) = Seq.singleton $ Citeproc.Citation { Citeproc.citationId = Nothing + , Citeproc.citationPrefix = Nothing + , Citeproc.citationSuffix = Nothing , Citeproc.citationNoteNumber = case cs of [] -> Nothing @@ -318,7 +320,7 @@ fromPandocCitations locale otherIdsMap = concatMap go where locmap = toLocatorMap locale go c = - let (mblocinfo, suffix) = parseLocator locmap (citationSuffix c) + let (mblocinfo, suffix) = parseLocator locmap (Pandoc.citationSuffix c) cit = CitationItem { citationItemId = fromMaybe (ItemId $ Pandoc.citationId c) @@ -326,7 +328,7 @@ fromPandocCitations locale otherIdsMap = concatMap go , citationItemLabel = locatorLabel <$> mblocinfo , citationItemLocator = locatorLoc <$> mblocinfo , citationItemType = NormalCite - , citationItemPrefix = case citationPrefix c of + , citationItemPrefix = case Pandoc.citationPrefix c of [] -> Nothing ils -> Just $ B.fromList ils <> B.space diff --git a/src/Text/Pandoc/Readers/EndNote.hs b/src/Text/Pandoc/Readers/EndNote.hs index b4958113195a..f0f22338da5e 100644 --- a/src/Text/Pandoc/Readers/EndNote.hs +++ b/src/Text/Pandoc/Readers/EndNote.hs @@ -81,6 +81,8 @@ readEndNoteXMLCitation xml = do let items = map toCitationItem $ filterElementsName (name "Cite") tree return $ Citeproc.Citation{ Citeproc.citationId = Nothing + , Citeproc.citationPrefix = Nothing + , Citeproc.citationSuffix = Nothing , Citeproc.citationNoteNumber = Nothing , Citeproc.citationItems = items } diff --git a/test/command/10185.md b/test/command/10185.md index e41fdf480c68..9c57469377ce 100644 --- a/test/command/10185.md +++ b/test/command/10185.md @@ -36,7 +36,7 @@ Lorem ipsum (John Doe, n.d.). \section{References}\label{references} \protect\phantomsection\label{refs} -\begin{CSLReferences}{1}{0} +\begin{CSLReferences}{1}{1} \bibitem[\citeproctext]{ref-foo} John Doe. n.d. \emph{The Title}. diff --git a/test/command/6783.md b/test/command/6783.md index bbb98ce18092..64e085dbdc34 100644 --- a/test/command/6783.md +++ b/test/command/6783.md @@ -20,7 +20,7 @@ This is a test[@ref-1]. This is a test(Jupyter 2018). Jupyter, Project. 2018. “Binder 2.0 - Reproducible, Interactive, -Sharable Environments for Science at Scale.” In Proceedings of the 17th +Sharable Environments for Science at Scale.” Proceedings of the 17th Python in Science Conference. ``` diff --git a/test/command/6890.md b/test/command/6890.md index 3404a7ee3d8a..267694488fa7 100644 --- a/test/command/6890.md +++ b/test/command/6890.md @@ -38,13 +38,11 @@ Some text.[^1] , citationHash = 0 } ] - [ Str "Fr\252chtel," + [ Str "Fr\252chtel" , Space - , Str "Budde," + , Str "et" , Space - , Str "and" - , Space - , Str "Cyprian" + , Str "al." , Space , Str "(2013)" ] @@ -65,13 +63,11 @@ Some text.[^1] , citationHash = 0 } ] - [ Str "Fr\252chtel," - , Space - , Str "Budde," + [ Str "Fr\252chtel" , Space - , Str "and" + , Str "et" , Space - , Str "Cyprian" + , Str "al." , Space , Str "(2013)" ] @@ -81,7 +77,7 @@ Some text.[^1] , Div ( "refs" , [ "references" , "csl-bib-body" , "hanging-indent" ] - , [ ( "entry-spacing" , "0" ) ] + , [] ) [ Div ( "ref-fruchtel-sozialer-2013a" , [ "csl-entry" ] , [] ) @@ -127,10 +123,6 @@ Some text.[^1] , Space , Str "ed." , Space - , Str "Wiesbaden," - , Space - , Str "Germany:" - , Space , Str "Springer" , Space , Str "VS." diff --git a/test/command/6951.md b/test/command/6951.md index 4a6301d80b7e..69815f8ed0b3 100644 --- a/test/command/6951.md +++ b/test/command/6951.md @@ -14,5 +14,5 @@ references: Crazy. n.d. -Doe, John. 2005. First Book. Cambridge: Cambridge University Press. +Doe, John. 2005. First Book. Cambridge University Press. ``` diff --git a/test/command/7219.md b/test/command/7219.md index 34b9341ef75d..9f5bc30e98ab 100644 --- a/test/command/7219.md +++ b/test/command/7219.md @@ -20,6 +20,6 @@ and also in -@reese and also in (1958) Reese, Trevor R. 1958. “Georgia in Anglo-Spanish Diplomacy, 1736-1739.” -William and Mary Quarterly, 3rd series, 15: 168–90. +William and Mary Quarterly, 3rd series, vol. 15: 168–90. ``` diff --git a/test/command/7329.md b/test/command/7329.md index 623ee812657e..cb3403288a70 100644 --- a/test/command/7329.md +++ b/test/command/7329.md @@ -32,7 +32,7 @@ <> <> -Doe, John. 2005. /First Book/. Cambridge: Cambridge University Press. +Doe, John. 2005. /First Book/. Cambridge University Press. ``` @@ -45,7 +45,7 @@ Doe, John. 2005. /First Book/. Cambridge: Cambridge University Press. <> <> -Doe, John. 2005. /First Book/. Cambridge: Cambridge University Press. +Doe, John. 2005. /First Book/. Cambridge University Press. ``` ``` diff --git a/test/command/8354.md b/test/command/8354.md index 6089556c9f1c..96e3d6801885 100644 --- a/test/command/8354.md +++ b/test/command/8354.md @@ -26,7 +26,7 @@ references: ^D

References

+role="list">
Fekete, Jean-Daniel, and Juliana Freire. 2020. “Exploring diff --git a/test/command/9017.md b/test/command/9017.md index dd4fd6c517b3..4faa153b83bb 100644 --- a/test/command/9017.md +++ b/test/command/9017.md @@ -45,7 +45,8 @@ title: Doc example with single reference - DeGroot. 2002. “Probability.” + DeGroot. 2002. + Probability. diff --git a/test/command/9904.md b/test/command/9904.md index c03b1d95c2fb..8a5048651864 100644 --- a/test/command/9904.md +++ b/test/command/9904.md @@ -153,7 +153,7 @@ Axioms were introduced :cite:p:`{see}item1{p. 1166}`. , Div ( "refs" , [ "references" , "csl-bib-body" , "hanging-indent" ] - , [ ( "entry-spacing" , "0" ) ] + , [] ) [ Div ( "ref-item1" , [ "csl-entry" ] , [] ) @@ -167,8 +167,6 @@ Axioms were introduced :cite:p:`{see}item1{p. 1166}`. , Emph [ Str "First" , Space , Str "Book" ] , Str "." , Space - , Str "Cambridge:" - , Space , Str "Cambridge" , Space , Str "University" diff --git a/test/command/citeproc-87.md b/test/command/citeproc-87.md index dd9287e78abf..5ff5131f0a6d 100644 --- a/test/command/citeproc-87.md +++ b/test/command/citeproc-87.md @@ -32,7 +32,7 @@ Foo [@a 50]. ^D Foo (Aristotele, n.d., 50). -Aristotele. n.d. “Metafisica Et ‘Physica’.” +Aristotele. n.d. Metafisica Et “Physica”. ``` ``` @@ -50,6 +50,6 @@ Foo [@a 50]. ^D Foo (Aristotele, s.d., 50). -Aristotele. s.d. «Metafisica et “Physica”». +Aristotele. s.d. Metafisica et «Physica». ``` diff --git a/test/command/pandoc-citeproc-118.md b/test/command/pandoc-citeproc-118.md index 1559bbfcce7a..5aa727ec3ab5 100644 --- a/test/command/pandoc-citeproc-118.md +++ b/test/command/pandoc-citeproc-118.md @@ -19,10 +19,9 @@ references: ^D (Hitchcock 1959) is a spy thriller film. -:::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-nbn .csl-entry} -Hitchcock, Alfred, dir. 1959. *North by Northwest*. USA: -Metro-Goldwyn-Mayer. +Hitchcock, Alfred, dir. 1959. *North by Northwest*. Metro-Goldwyn-Mayer. ::: :::: ``` diff --git a/test/command/pandoc-citeproc-136.md b/test/command/pandoc-citeproc-136.md index 86a952617cdf..3657900a8582 100644 --- a/test/command/pandoc-citeproc-136.md +++ b/test/command/pandoc-citeproc-136.md @@ -15,7 +15,7 @@ references: ^D *Stanze in lode della donna brutta* (1547) is an anoynymous work. -:::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-stanze .csl-entry} *Stanze in lode della donna brutta*. 1547. Florence. ::: diff --git a/test/command/pandoc-citeproc-14.md b/test/command/pandoc-citeproc-14.md index fd51e496def2..99b4f89bce34 100644 --- a/test/command/pandoc-citeproc-14.md +++ b/test/command/pandoc-citeproc-14.md @@ -51,27 +51,27 @@ Foo [@CT, 1:12]. Bar [@CTv1, 12]. Baz [@CTv1c2, 12]. References {#references .unnumbered} ========== ^D -Foo (Pelikan 1971b, 1:12). Bar (Pelikan 1971c, 1:12). Baz (Pelikan -1971a, 12). +Foo (Pelikan 1971b, 1:12). Bar (Pelikan 1971c, 12). Baz (Pelikan 1971a, +12). # References {#references .unnumbered} -:::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-CTv1c2 .csl-entry} -Pelikan, Jaroslav. 1971a. "Chapter Two." In *The Christian Tradition: A -History of the Development of Doctrine*, 1:34--56. Chicago: University -of Chicago Press. +Pelikan, Jaroslav. 1971a. "Chapter Two." In *The Emergence of the +Catholic Tradition (100--600)*, vol. 1 of *The Christian Tradition: A +History of the Development of Doctrine*. University of Chicago Press. ::: ::: {#ref-CT .csl-entry} ----------. 1971b. *The Christian Tradition: A History of the Development -of Doctrine*. Chicago: University of Chicago Press. +Pelikan, Jaroslav. 1971b. *The Christian Tradition: A History of the +Development of Doctrine*. University of Chicago Press. ::: ::: {#ref-CTv1 .csl-entry} ----------. 1971c. *The Emergence of the Catholic Tradition (100--600)*. -*The Christian Tradition: A History of the Development of Doctrine*. -Vol. 1. Chicago: University of Chicago Press. +Pelikan, Jaroslav. 1971c. *The Emergence of the Catholic Tradition +(100--600)*. In *The Christian Tradition: A History of the Development +of Doctrine*, vol. 1, 1. University of Chicago Press. ::: :::::: ``` diff --git a/test/command/pandoc-citeproc-175.md b/test/command/pandoc-citeproc-175.md index 9af990290b7a..552d24c0cbe1 100644 --- a/test/command/pandoc-citeproc-175.md +++ b/test/command/pandoc-citeproc-175.md @@ -35,9 +35,9 @@ Foo (Doe 2011). > Doe, Jane. 2011. "A Title." *A Magazine*, January--February. -:::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-item1 .csl-entry} -Doe, Jane. 2011. "A Title." *A Magazine*, January--February 2011. +Doe, Jane. 2011. "A Title." *A Magazine*, January--February, 33--44. ::: :::: ``` diff --git a/test/command/pandoc-citeproc-25.md b/test/command/pandoc-citeproc-25.md index c1971de27de7..1e49f4f603cf 100644 --- a/test/command/pandoc-citeproc-25.md +++ b/test/command/pandoc-citeproc-25.md @@ -22,9 +22,9 @@ Foo (Author 1998). # References {#references .unnumbered} -:::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-item1 .csl-entry} -Author, Al. 1998. "Foo Bar Baz: Bazbaz Foo." +Author, Al. 1998. *Foo Bar Baz: Bazbaz Foo*. ::: :::: ``` diff --git a/test/command/pandoc-citeproc-250.md b/test/command/pandoc-citeproc-250.md index cfbf754e3d1b..77dc335c52ba 100644 --- a/test/command/pandoc-citeproc-250.md +++ b/test/command/pandoc-citeproc-250.md @@ -13,9 +13,9 @@ references: ^D ([Doe, n.d.](#ref-doe)) -:::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-doe .csl-entry} -Doe. n.d. "Title." +Doe. n.d. *Title*. ::: :::: ``` diff --git a/test/command/pandoc-citeproc-301.md b/test/command/pandoc-citeproc-301.md index 9eafc22fc1bd..128431f404ef 100644 --- a/test/command/pandoc-citeproc-301.md +++ b/test/command/pandoc-citeproc-301.md @@ -10,16 +10,16 @@ references: @test; @test2 ^D -"Essays Presented to N.R. Ker (On Art)" (n.d.); "*Test:* An Experiment: -An Abridgement" (n.d.) +*Essays Presented to N.R. Ker (On Art)* (n.d.); **Test:* An Experiment: +An Abridgement* (n.d.) -::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-test .csl-entry} -"Essays Presented to N.R. Ker (On Art)." n.d. +*Essays Presented to N.R. Ker (On Art)*. n.d. ::: ::: {#ref-test2 .csl-entry} -"*Test:* An Experiment: An Abridgement." n.d. +**Test:* An Experiment: An Abridgement*. n.d. ::: ::::: ``` diff --git a/test/command/pandoc-citeproc-307.md b/test/command/pandoc-citeproc-307.md index 30246552dc34..de595a23e4ba 100644 --- a/test/command/pandoc-citeproc-307.md +++ b/test/command/pandoc-citeproc-307.md @@ -22,7 +22,7 @@ Bonjour[@bazin_cybernetique_1954] ! ^D Bonjour(Bazin 1954) ! -:::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-bazin_cybernetique_1954 .csl-entry} Bazin, André. 1954. « La Cybernétique d'André Cayatte ». *Cahiers du cinéma*, nᵒ 36 (juin): 22‑27. diff --git a/test/command/pandoc-citeproc-320a.md b/test/command/pandoc-citeproc-320a.md index a5348adb9b91..95378ea098fb 100644 --- a/test/command/pandoc-citeproc-320a.md +++ b/test/command/pandoc-citeproc-320a.md @@ -61,17 +61,17 @@ Foo (al-ʾUdhrī 2000; al-ʿUdhrī 2000; al-’Udhrī 2000b, 2000a; al-‘Udhrī Uch, Ann. 2000. -‘Udhrī, Jamīl al-. 2000. “Inverted Curly Apostrophe = Opening Single -Curly Quote (for Ayn).” +‘Udhrī, Jamīl al-. 2000. Inverted Curly Apostrophe = Opening Single +Curly Quote (for Ayn). -ʿUdhrī, Jamīl al-. 2000. “Ayn.” +ʿUdhrī, Jamīl al-. 2000. Ayn. -’Udhrī, Jamīl al-. 2000a. “Curly Apostrophe = Closing Single Curly Quote -(for Hamza).” +’Udhrī, Jamīl al-. 2000a. Curly Apostrophe = Closing Single Curly Quote +(for Hamza). -ʾUdhrī, Jamīl al-. 2000. “Hamza.” +ʾUdhrī, Jamīl al-. 2000. Hamza. -’Udhrī, Jamīl al-. 2000b. “Straight Apostrophe.” +’Udhrī, Jamīl al-. 2000b. Straight Apostrophe. Uebel, Joe. 2000. diff --git a/test/command/pandoc-citeproc-325.md b/test/command/pandoc-citeproc-325.md index 0b5dbdd24314..1516298bd44c 100644 --- a/test/command/pandoc-citeproc-325.md +++ b/test/command/pandoc-citeproc-325.md @@ -16,15 +16,15 @@ references: [@item1; @item2] ^D -(Smith, n.d.a, n.d.b) +(Smith, n.d.-a, n.d.-b) -::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-item1 .csl-entry} -Smith, John. n.d.a. +Smith, John. n.d.-a. ::: ::: {#ref-item2 .csl-entry} ----------. n.d.b. +Smith, John. n.d.-b. ::: ::::: ``` diff --git a/test/command/pandoc-citeproc-327.md b/test/command/pandoc-citeproc-327.md index 5918a0efa825..6678a16f27a3 100644 --- a/test/command/pandoc-citeproc-327.md +++ b/test/command/pandoc-citeproc-327.md @@ -45,7 +45,7 @@ I referenced something here^\[1\]^ ::: {#ref-LiLiaoDongWanHaiYuDiQiDongWuCiJiShengChanLiYanJiuJiShengJingGuaYiXingPingJie2017 .csl-entry} [\[1\] ]{.csl-left-margin}[李轶平, 于旭光, 孙明, 等. [辽东湾海域底栖动物次级生产力研究及生境适宜性评价](http://kns.cnki.net/kns/detail/detail.aspx?QueryID=4&CurRec=4&recid=&FileName=CHAN201706006&DbName=CJFDLAST2018&DbCode=CJFQ&yx=Y&pr=&URLID=21.1110.S.20171129.1725.006)\[J\]. -水产科学, 2017(6): 728--734.]{.csl-right-inline} +水产科学, 2017(6): 728~734.]{.csl-right-inline} ::: :::: ``` diff --git a/test/command/pandoc-citeproc-371.md b/test/command/pandoc-citeproc-371.md index 6d67414fe7e4..0c8a2829e070 100644 --- a/test/command/pandoc-citeproc-371.md +++ b/test/command/pandoc-citeproc-371.md @@ -28,13 +28,13 @@ Foo (Doe 2018, in press). # References {#references .unnumbered} -::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-item2 .csl-entry} Doe, Jane. 2018. *Title Two*. ::: ::: {#ref-item1 .csl-entry} ----------. In press. *Title One*. +Doe, Jane. In press. *Title One*. ::: ::::: ``` diff --git a/test/command/pandoc-citeproc-38.md b/test/command/pandoc-citeproc-38.md index 3c01bd51d80b..1c5a77310864 100644 --- a/test/command/pandoc-citeproc-38.md +++ b/test/command/pandoc-citeproc-38.md @@ -19,11 +19,11 @@ references: @a ^D -Doe, Doe, and Roe (2007) +Doe et al. (2007) -:::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-a .csl-entry} -Doe, Ann, Ben Doe, and Ron Roe. 2007. "Title." +Doe, Ann, Ben Doe, and Ron Roe. 2007. *Title*. ::: :::: ``` diff --git a/test/command/pandoc-citeproc-401.md b/test/command/pandoc-citeproc-401.md index 7bbcd59d15f6..256aaaa0dc30 100644 --- a/test/command/pandoc-citeproc-401.md +++ b/test/command/pandoc-citeproc-401.md @@ -43,17 +43,17 @@ Haslanger [-@haslanger2012SocialConstructionDebunking; @haslanger2012FeminismMet ^D Haslanger (\[2003\] 2012, \[2000\] 2012) says... -::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-haslanger2012FeminismMetaphysicsNegotiating .csl-entry} Haslanger, Sally. (2000) 2012. "Feminism in Metaphysics: Negotiating the Natural." In *Resisting Reality: Social Construction and Social -Critique*, 139--57. Oxford: Oxford University Press. +Critique*. Oxford University Press. ::: ::: {#ref-haslanger2012SocialConstructionDebunking .csl-entry} ----------. (2003) 2012. "Social Construction: The 'Debunking' Project." -In *Resisting Reality: Social Construction and Social Critique*, -113--38. Oxford: Oxford University Press. +Haslanger, Sally. (2003) 2012. "Social Construction: The 'Debunking' +Project." In *Resisting Reality: Social Construction and Social +Critique*. Oxford University Press. ::: ::::: ``` diff --git a/test/command/pandoc-citeproc-408.md b/test/command/pandoc-citeproc-408.md index f7e1dca46306..bdf1e1c070e4 100644 --- a/test/command/pandoc-citeproc-408.md +++ b/test/command/pandoc-citeproc-408.md @@ -27,13 +27,13 @@ references: ^D (Smith and Smith 2019; Smith 2019) -::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-smith1 .csl-entry} -Smith, Mary. 2019. "Foo." +Smith, Mary. 2019. *Foo*. ::: ::: {#ref-smithsmith .csl-entry} -Smith, Mary, and John Smith. 2019. "Foo Bar." +Smith, Mary, and John Smith. 2019. *Foo Bar*. ::: ::::: ``` diff --git a/test/command/pandoc-citeproc-416.md b/test/command/pandoc-citeproc-416.md index 9a4fb5b2b81f..9cbf7555e85d 100644 --- a/test/command/pandoc-citeproc-416.md +++ b/test/command/pandoc-citeproc-416.md @@ -44,17 +44,17 @@ Blah blah (Doe 2010, 2007, 2008). # References {#references .unnumbered} -:::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-item2 .csl-entry} -Doe, J. 2007. "The Title," December 12--13, 2007. +Doe, J. 2007. *The Title*. December 12--13. ::: ::: {#ref-item3 .csl-entry} ----------. 2008. "The Title," 2008. +Doe, J. 2008. *The Title*. ::: ::: {#ref-item1 .csl-entry} ----------. 2010. "The Title," December 13, 2010. +Doe, J. 2010. *The Title*. December 13. ::: :::::: ``` diff --git a/test/command/pandoc-citeproc-47.md b/test/command/pandoc-citeproc-47.md index 36947df8068d..f5d9eb116a18 100644 --- a/test/command/pandoc-citeproc-47.md +++ b/test/command/pandoc-citeproc-47.md @@ -69,8 +69,8 @@ chronological order is maintained, regardless of the added abbreviation. References {#references .unnumbered} ========== ^D -Foo (Doe 2000a). Bar (Doe and Poe 2000). Foo (Doe 2000b). Bar (Doe, Loe, -and Toe 2000). +Foo (Doe 2000a). Bar (Doe and Poe 2000). Foo (Doe 2000b). Bar (Doe et +al. 2000). Expected output: @@ -92,13 +92,13 @@ chronological order is maintained, regardless of the added abbreviation. # References {#references .unnumbered} -::::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +::::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-doe .csl-entry} Doe, A. 2000a. *Title*. ::: ::: {#ref-doe-ed .csl-entry} ----------, ed. 2000b. *Title*. +Doe, A., ed. 2000b. *Title*. ::: ::: {#ref-doeloetoe .csl-entry} diff --git a/test/command/pandoc-citeproc-51.md b/test/command/pandoc-citeproc-51.md index 22cfac4b0469..61cff71a24fb 100644 --- a/test/command/pandoc-citeproc-51.md +++ b/test/command/pandoc-citeproc-51.md @@ -33,7 +33,7 @@ references: ^D Doe (1987--1988); Roe (1987) -::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-item1 .csl-entry} Doe, John. 1987--1988. "The Title." *Journal of Something* 3: 12--34. ::: diff --git a/test/command/pandoc-citeproc-64.md b/test/command/pandoc-citeproc-64.md index 660892a9ff8b..a0860236338a 100644 --- a/test/command/pandoc-citeproc-64.md +++ b/test/command/pandoc-citeproc-64.md @@ -7,18 +7,18 @@ nocite: '[@*]' --- ^D -:::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-item1 .csl-entry} -Doe, John. 2005. *First Book*. Cambridge: Cambridge University Press. +Doe, John. 2005. *First Book*. Cambridge University Press. ::: ::: {#ref-item2 .csl-entry} ----------. 2006. "Article." *Journal of Generic Studies* 6: 33--34. +Doe, John. 2006. "Article." *Journal of Generic Studies* 6: 33--34. ::: ::: {#ref-пункт3 .csl-entry} Doe, John, and Jenny Roe. 2007. "Why Water Is Wet." In *Third Book*, -edited by Sam Smith. Oxford: Oxford University Press. +edited by Sam Smith. Oxford University Press. ::: :::::: ``` diff --git a/test/command/pandoc-citeproc-65.md b/test/command/pandoc-citeproc-65.md index d0a8e7acba2c..7fc178d353d6 100644 --- a/test/command/pandoc-citeproc-65.md +++ b/test/command/pandoc-citeproc-65.md @@ -28,11 +28,10 @@ references: ^D (Stotz 1996--2004) -:::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-stotz:1996handbuch .csl-entry} Stotz, Peter. 1996--2004. *Handbuch zur lateinischen Sprache des -Mittelalters*. 5 vols. Handbuch der Altertumswissenschaft 2.5. Munich: -Beck. +Mittelalters*. 5 vols. Handbuch der Altertumswissenschaft 2.5. Beck. ::: :::: ``` diff --git a/test/command/pandoc-citeproc-7.md b/test/command/pandoc-citeproc-7.md index 8fb275d482b8..bf1e39e6b3a3 100644 --- a/test/command/pandoc-citeproc-7.md +++ b/test/command/pandoc-citeproc-7.md @@ -23,9 +23,9 @@ references: ^D Author (2011) -:::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-item1 .csl-entry} -Author, Ann. 2011. "Title." *Journal*, September 24--26, 2011. +Author, Ann. 2011. "Title." *Journal*, September 24--26. ::: :::: ``` diff --git a/test/command/pandoc-citeproc-70.md b/test/command/pandoc-citeproc-70.md index 00bb0313be18..f08b62030f97 100644 --- a/test/command/pandoc-citeproc-70.md +++ b/test/command/pandoc-citeproc-70.md @@ -56,14 +56,14 @@ references: ^D (Thorndike 1955; Dinkova-Bruun 2009) -::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-bruun:2009samuel .csl-entry} Dinkova-Bruun, Greti. 2009. "Samuel Presbyter and the Glosses to His Versification of Psalm 1: An Anti-Church Invective?" In *Florilegium mediaevale: Études offertes à Jacqueline Hamesse à l'occasion de son -éméritat*, edited by José Francisco Meirinhos and Olga Weijers, 155--74. -Textes et études du moyen âge 50. Louvain-la-Neuve: Fédération -Internationale des Instituts d'Études Médiévales. +éméritat*, edited by José Francisco Meirinhos and Olga Weijers. Textes +et études du moyen âge 50. Fédération Internationale des Instituts +d'Études Médiévales. ::: ::: {#ref-thorndike:1955unde .csl-entry} diff --git a/test/command/pandoc-citeproc-76.md b/test/command/pandoc-citeproc-76.md index 70140294442a..5240c090590a 100644 --- a/test/command/pandoc-citeproc-76.md +++ b/test/command/pandoc-citeproc-76.md @@ -44,21 +44,21 @@ references: ^D Author (1998c), Author (1998d), Author (1998a), Author (1998b) -::::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +::::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-item3 .csl-entry} -Author, Al. 1998a. "Foo Bar Baz: A Bazbaz Bar Foo." +Author, Al. 1998a. *Foo Bar Baz: A Bazbaz Bar Foo*. ::: ::: {#ref-item4 .csl-entry} ----------. 1998b. "Foo Bar Baz: An Abazbaz Bar Foo." +Author, Al. 1998b. *Foo Bar Baz: An Abazbaz Bar Foo*. ::: ::: {#ref-item1 .csl-entry} ----------. 1998c. "Foo Bar Baz: Bazbaz Bar Foo." +Author, Al. 1998c. *Foo Bar Baz: Bazbaz Bar Foo*. ::: ::: {#ref-item2 .csl-entry} ----------. 1998d. "Foo Bar Baz: The Bazbaz Bar Foo." +Author, Al. 1998d. *Foo Bar Baz: The Bazbaz Bar Foo*. ::: ::::::: ``` diff --git a/test/command/pandoc-citeproc-87.md b/test/command/pandoc-citeproc-87.md index 109f4362a93a..e54edba42573 100644 --- a/test/command/pandoc-citeproc-87.md +++ b/test/command/pandoc-citeproc-87.md @@ -108,49 +108,49 @@ references: References ========== ^D -Doe (2006c) -- webpage, date +Doe (2006a) -- webpage, date -Doe (2006d) -- webpage, date range +Doe (2006b) -- webpage, date range -Doe (2006a) -- webpage, date range YM +Doe (2006d) -- webpage, date range YM Doe (2006--2007) -- webpage, date range across years -Doe (2006e) -- article-newspaper +Doe (2006c) -- article-newspaper -Doe (2006b) -- article-newspaper YM +Doe (2006e) -- article-newspaper YM # References {#references .unnumbered} -::::::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} -::: {#ref-item2a .csl-entry} -Doe, John. 2006a. "Title." The Web Site. October--November 2006. +::::::::: {#refs .references .csl-bib-body .hanging-indent} +::: {#ref-item1 .csl-entry} +Doe, John. 2006a. "Title." The Web Site, October 26. . ::: -::: {#ref-item3b .csl-entry} ----------. 2006b. "Title." *The Newspaper*, October--November 2006. +::: {#ref-item2 .csl-entry} +Doe, John. 2006b. "Title." The Web Site, October 26--November 27. . ::: -::: {#ref-item1 .csl-entry} ----------. 2006c. "Title." The Web Site. October 26, 2006. +::: {#ref-item3 .csl-entry} +Doe, John. 2006c. "Title." *The Newspaper*, October 26--November 27. . ::: -::: {#ref-item2 .csl-entry} ----------. 2006d. "Title." The Web Site. October 26--November 27, 2006. +::: {#ref-item2a .csl-entry} +Doe, John. 2006d. "Title." The Web Site, October--November. . ::: -::: {#ref-item3 .csl-entry} ----------. 2006e. "Title." *The Newspaper*, October 26--November 27, -2006. . +::: {#ref-item3b .csl-entry} +Doe, John. 2006e. "Title." *The Newspaper*, October--November. +. ::: ::: {#ref-item2b .csl-entry} ----------. 2006--2007. "Title." The Web Site. December 31, 2006--January -1, 2007. . +Doe, John. 2006--2007. "Title." The Web Site, December 31--January 1. +. ::: ::::::::: ``` diff --git a/test/command/pandoc-citeproc-chicago-author-date.md b/test/command/pandoc-citeproc-chicago-author-date.md index 2614b9d97d87..f88578d84a95 100644 --- a/test/command/pandoc-citeproc-chicago-author-date.md +++ b/test/command/pandoc-citeproc-chicago-author-date.md @@ -83,18 +83,18 @@ With some markup (*see* [Doe 2005, 32](#ref-item1)). # References {#references .unnumbered} -:::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-item1 .csl-entry} -Doe, John. 2005. *First Book*. Cambridge: Cambridge University Press. +Doe, John. 2005. *First Book*. Cambridge University Press. ::: ::: {#ref-item2 .csl-entry} ----------. 2006. "Article." *Journal of Generic Studies* 6: 33--34. +Doe, John. 2006. "Article." *Journal of Generic Studies* 6: 33--34. ::: ::: {#ref-пункт3 .csl-entry} Doe, John, and Jenny Roe. 2007. "Why Water Is Wet." In *Third Book*, -edited by Sam Smith. Oxford: Oxford University Press. +edited by Sam Smith. Oxford University Press. ::: :::::: diff --git a/test/command/pandoc-citeproc-no-author.md b/test/command/pandoc-citeproc-no-author.md index 549e4a364ca6..ae1ce98036ec 100644 --- a/test/command/pandoc-citeproc-no-author.md +++ b/test/command/pandoc-citeproc-no-author.md @@ -45,29 +45,29 @@ references: *Magazine* (2012a, 3), *Magazine* (2012b), *Magazine* (2012c), *Magazine* (2012d), *Newspaper* (2012a), *Newspaper* (2012b) -::::::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +::::::::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-item1 .csl-entry} -*Magazine*. 2012a. "Title A," 2012. +*Magazine*. 2012a. "Title A." ::: ::: {#ref-item2 .csl-entry} ----------. 2012b. "Title B," 2012. +*Magazine*. 2012b. "Title B." ::: ::: {#ref-item3 .csl-entry} ----------. 2012c. "Title C," 2012. +*Magazine*. 2012c. "Title C." ::: ::: {#ref-item4 .csl-entry} ----------. 2012d. "Title D," 2012. +*Magazine*. 2012d. "Title D." ::: ::: {#ref-item5 .csl-entry} -*Newspaper*. 2012a. "Title E," 2012. +*Newspaper*. 2012a. "Title E." ::: ::: {#ref-item6 .csl-entry} ----------. 2012b. "Title F," 2012. +*Newspaper*. 2012b. "Title F." ::: ::::::::: ``` diff --git a/test/command/pandoc-citeproc-number-of-volumes.md b/test/command/pandoc-citeproc-number-of-volumes.md index ba83497f86e0..b098b468028f 100644 --- a/test/command/pandoc-citeproc-number-of-volumes.md +++ b/test/command/pandoc-citeproc-number-of-volumes.md @@ -21,9 +21,9 @@ references: ^D Author (2013) -:::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +:::: {#refs .references .csl-bib-body .hanging-indent} ::: {#ref-item1 .csl-entry} -Author, Al. 2013. *Title*. 2 vols. Location: Publisher. +Author, Al. 2013. *Title*. 2 vols. Publisher. ::: :::: ``` From 2de4cdaa799a083e759e575f208346263f087fe1 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 20 Jul 2025 15:07:51 -0700 Subject: [PATCH 22/54] Fix citeproc-87 test. When we updated to the latest chicago-author-date.csl, this test no longer tested what it was supposed to; so we use a different csl. --- test/command/citeproc-87.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/test/command/citeproc-87.md b/test/command/citeproc-87.md index 5ff5131f0a6d..2c6f7a73b4cf 100644 --- a/test/command/citeproc-87.md +++ b/test/command/citeproc-87.md @@ -18,7 +18,7 @@ Foo (Aristotele, s.d., 50: «Disse: "bar"»). «Disse: "baz"» The Quoted is passed to citeproc as a Span ("",["csl-quoted"],[]) so that flipflopping and localization occur. ``` -% pandoc -C -t plain -Mlang=en +% pandoc -C -t plain -Mlang=en --csl command/le-tapuscrit-note.csl --- references: - id: a @@ -30,13 +30,15 @@ references: Foo [@a 50]. ^D -Foo (Aristotele, n.d., 50). +Foo.[1] -Aristotele. n.d. Metafisica Et “Physica”. +ARISTOTELE, “Metafisica et ‘Physica’.” + +[1] Aristotele, “Metafisica et ‘Physica’,” p. 50. ``` ``` -% pandoc -C -t plain -Mlang=it +% pandoc -C -t plain -Mlang=it --csl command/le-tapuscrit-note.csl --- references: - id: a @@ -48,8 +50,10 @@ references: Foo [@a 50]. ^D -Foo (Aristotele, s.d., 50). +Foo.[1] + +ARISTOTELE, «Metafisica et “Physica”». -Aristotele. s.d. Metafisica et «Physica». +[1] Aristotele, «Metafisica et “Physica”», p. 50. ``` From eb2f3d4a652f5bdd90ba58145cd667176be9d86f Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 20 Jul 2025 15:30:14 -0700 Subject: [PATCH 23/54] Fix pandoc-citeproc-64 test. It was meant to test subsequent author substitution, but the new chicago-author-date doesn't do this. So we use a different CSL. --- test/command/pandoc-citeproc-64.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/command/pandoc-citeproc-64.md b/test/command/pandoc-citeproc-64.md index a0860236338a..199679a2ef41 100644 --- a/test/command/pandoc-citeproc-64.md +++ b/test/command/pandoc-citeproc-64.md @@ -1,5 +1,5 @@ ``` -% pandoc --citeproc -t markdown-citations +% pandoc --citeproc -t markdown-citations --csl command/chicago-fullnote-bibliography.csl --- bibliography: - command/biblio.bib @@ -7,18 +7,18 @@ nocite: '[@*]' --- ^D -:::::: {#refs .references .csl-bib-body .hanging-indent} -::: {#ref-item1 .csl-entry} -Doe, John. 2005. *First Book*. Cambridge University Press. +:::::: {#refs .references .csl-bib-body .hanging-indent entry-spacing="0"} +::: {#ref-item2 .csl-entry} +Doe, John. "Article." *Journal of Generic Studies* 6 (2006): 33--34. ::: -::: {#ref-item2 .csl-entry} -Doe, John. 2006. "Article." *Journal of Generic Studies* 6: 33--34. +::: {#ref-item1 .csl-entry} +---------. *First Book*. Cambridge: Cambridge University Press, 2005. ::: ::: {#ref-пункт3 .csl-entry} -Doe, John, and Jenny Roe. 2007. "Why Water Is Wet." In *Third Book*, -edited by Sam Smith. Oxford University Press. +Doe, John, and Jenny Roe. "Why Water Is Wet." In *Third Book*, edited by +Sam Smith. Oxford: Oxford University Press, 2007. ::: :::::: ``` From 1d8218e5a7ef7524122330a91b07bbcbf87a1e8d Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 20 Jul 2025 16:24:26 -0700 Subject: [PATCH 24/54] Use latest dev citeproc. --- cabal.project | 2 +- stack.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cabal.project b/cabal.project index c17d2bf0d73a..94bd4763014b 100644 --- a/cabal.project +++ b/cabal.project @@ -12,6 +12,6 @@ constraints: skylighting-format-blaze-html >= 0.1.1.3, source-repository-package type: git location: file:///Users/jgm/src/citeproc - tag: ca4affae538dc4c104bb2411eae8c3167ab3da24 + tag: 8cb87866967674049a8d1c933dc1effbfe80e8ef -- TODO: release new skylighting-core, skylighting diff --git a/stack.yaml b/stack.yaml index 2f8df84a06fb..ea4ffe54f019 100644 --- a/stack.yaml +++ b/stack.yaml @@ -23,7 +23,7 @@ extra-deps: - texmath-0.12.10.3 - typst-0.8.0.1 - git: https://github.com/jgm/citeproc.git - commit: 157c7815f06e4e6771740a4eb8df97568626a8fe + commit: 8cb87866967674049a8d1c933dc1effbfe80e8ef ghc-options: "$locals": -fhide-source-paths -Wno-missing-home-modules resolver: lts-23.22 From 55cbd96277b0e2a24559c7cc7b51075d67d75fc7 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 20 Jul 2025 17:50:41 -0700 Subject: [PATCH 25/54] Fix a test. --- test/command/pandoc-citeproc-14.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/command/pandoc-citeproc-14.md b/test/command/pandoc-citeproc-14.md index 99b4f89bce34..41370805acde 100644 --- a/test/command/pandoc-citeproc-14.md +++ b/test/command/pandoc-citeproc-14.md @@ -71,7 +71,7 @@ Development of Doctrine*. University of Chicago Press. ::: {#ref-CTv1 .csl-entry} Pelikan, Jaroslav. 1971c. *The Emergence of the Catholic Tradition (100--600)*. In *The Christian Tradition: A History of the Development -of Doctrine*, vol. 1, 1. University of Chicago Press. +of Doctrine*, vol. 1. University of Chicago Press. ::: :::::: ``` From fd2c684d030b7103e8b30112f133eab9613ea7a9 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 20 Jul 2025 19:19:15 -0700 Subject: [PATCH 26/54] Fixed cabal.project stanza for citeproc. --- cabal.project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cabal.project b/cabal.project index 94bd4763014b..281f67395b6e 100644 --- a/cabal.project +++ b/cabal.project @@ -11,7 +11,7 @@ constraints: skylighting-format-blaze-html >= 0.1.1.3, source-repository-package type: git - location: file:///Users/jgm/src/citeproc + location: https://github.com/jgm/citeproc.git tag: 8cb87866967674049a8d1c933dc1effbfe80e8ef -- TODO: release new skylighting-core, skylighting From 3cd261ef89ff99c2fa10f0dbfbb4c180b3d2ba5e Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Mon, 21 Jul 2025 10:40:24 +0200 Subject: [PATCH 27/54] Typst: add support for custom and/or translated "Abstract" titles Closes: #9724 --- data/templates/template.typst | 2 +- src/Text/Pandoc/Writers/Typst.hs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/data/templates/template.typst b/data/templates/template.typst index 1889bef6fa53..24b1320fb910 100644 --- a/data/templates/template.typst +++ b/data/templates/template.typst @@ -80,7 +80,7 @@ #if abstract != none { block(inset: 2em)[ - #text(weight: "semibold")[Abstract] #h(1em) #abstract + #text(weight: "semibold")[$if(abstract-title)$${abstract-title}$else$Abstract$endif$] #h(1em) #abstract ] } ] diff --git a/src/Text/Pandoc/Writers/Typst.hs b/src/Text/Pandoc/Writers/Typst.hs index 90409cbbf52e..9e71ea51388c 100644 --- a/src/Text/Pandoc/Writers/Typst.hs +++ b/src/Text/Pandoc/Writers/Typst.hs @@ -29,8 +29,9 @@ import Network.URI (unEscapeString) import qualified Data.Text as T import Control.Monad.State ( StateT, evalStateT, gets, modify ) import Text.Pandoc.Writers.Shared ( metaToContext, defField, resetField, - lookupMetaString ) + setupTranslations, lookupMetaString ) import Text.Pandoc.Shared (isTightList, orderedListMarkers, tshow) +import Text.Pandoc.Translations (Term(Abstract), translateTerm) import Text.Pandoc.Writers.Math (convertMath) import qualified Text.TeXMath as TM import Text.DocLayout @@ -64,11 +65,13 @@ pandocToTypst options (Pandoc meta blocks) = do let colwidth = if writerWrapText options == WrapAuto then Just $ writerColumns options else Nothing + setupTranslations meta metadata <- metaToContext options blocksToTypst (fmap chomp . inlinesToTypst) meta main <- blocksToTypst blocks + abstractTitle <- translateTerm Abstract let toPosition :: CaptionPosition -> Text toPosition CaptionAbove = "top" toPosition CaptionBelow = "bottom" @@ -87,6 +90,7 @@ pandocToTypst options (Pandoc meta blocks) = do maybe id (resetField "region") (langRegion l)) $ defField "csl" (lookupMetaString "citation-style" meta) -- #10661 $ defField "smart" (isEnabled Ext_smart options) + $ defField "abstract-title" abstractTitle $ defField "toc-depth" (tshow $ writerTOCDepth options) $ defField "figure-caption-position" (toPosition $ writerFigureCaptionPosition options) From 957add2b082b6eca9b4c0bd716928c7477ef6fbc Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Tue, 22 Jul 2025 18:42:31 +0200 Subject: [PATCH 28/54] Markdown writer: match indents in definition items Previously, the first line of a definition details item always used a colon and three spaces instead of respecting the tab-stop setting, which could lead to round-tripping issues. Likewise, the indentation of continuation paragraphs in definition lists now matches the two-characters leader of the first line for Markua output. Fixes: #10890 --- src/Text/Pandoc/Writers/Markdown.hs | 15 ++++++++------- test/command/10890.md | 15 +++++++++++++++ test/writer.markua | 14 +++++++------- 3 files changed, 30 insertions(+), 14 deletions(-) create mode 100644 test/command/10890.md diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 39abed8fa609..cd3e4ab9165b 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -857,17 +857,18 @@ definitionListItemToMarkdown opts (label, defs) = do let tabStop = writerTabStop opts variant <- asks envVariant let leader = case variant of - PlainText -> " " - Markua -> ":" - _ -> ": " - let sps = case writerTabStop opts - 3 of - n | n > 0 -> literal $ T.replicate n " " - _ -> literal " " + PlainText -> " " + _ -> ":" + let leadingChars = case tabStop of + -- Always use two leading characters for Markua + n | n >= 2 && variant /= Markua -> n + _ -> 2 + let sps = literal $ T.replicate (leadingChars - 1) " " let isTight = case defs of ((Plain _ : _): _) -> True _ -> False let contents = (if isTight then vcat else vsep) $ map - (\d -> hang tabStop (leader <> sps) $ vcat d) + (\d -> hang leadingChars (leader <> sps) $ vcat d) defs' return $ blankline <> nowrap labelText $$ (if isTight then empty else blankline) <> contents <> blankline diff --git a/test/command/10890.md b/test/command/10890.md new file mode 100644 index 000000000000..508a9a3d2ded --- /dev/null +++ b/test/command/10890.md @@ -0,0 +1,15 @@ +``` +% pandoc --tab-stop=2 --from=native --to=markdown +[ DefinitionList + [ ( [ Str "apple" ] + , [ [ Para [ Str "pomaceous" ] , Para [ Str "fruit" ] ] ] + ) + ] +] +^D +apple + +: pomaceous + + fruit +``` diff --git a/test/writer.markua b/test/writer.markua index a7032dc27177..c1ca713d90c2 100644 --- a/test/writer.markua +++ b/test/writer.markua @@ -317,17 +317,17 @@ Multiple blocks with italics: : red fruit - contains seeds, crisp, pleasant to taste + contains seeds, crisp, pleasant to taste *orange* : orange fruit - ``` - { orange code block } - ``` + ``` + { orange code block } + ``` - > orange block quote + > orange block quote Multiple definitions, tight: @@ -365,8 +365,8 @@ orange : orange fruit - 1. sublist - 2. sublist + 1. sublist + 2. sublist {id: html-blocks} # HTML Blocks From 02ce2efe67b1c1e0aba736739fc558fcb7f41cc2 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 22 Jul 2025 20:43:48 -0700 Subject: [PATCH 29/54] Djot writer: fix duplicate attributes before section headings. Closes #10984. --- src/Text/Pandoc/Writers/Djot.hs | 9 ++++++--- test/command/10984.md | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 test/command/10984.md diff --git a/src/Text/Pandoc/Writers/Djot.hs b/src/Text/Pandoc/Writers/Djot.hs index 45ea729eb7c7..c7e846735734 100644 --- a/src/Text/Pandoc/Writers/Djot.hs +++ b/src/Text/Pandoc/Writers/Djot.hs @@ -100,7 +100,8 @@ blockToDjot (BlockQuote bls) = D.blockQuote <$> blocksToDjot bls blockToDjot (Header lev attr ils) = fmap (D.addAttr (toDjotAttr attr)) . D.heading lev <$> inlinesToDjot ils blockToDjot HorizontalRule = pure D.thematicBreak -blockToDjot (Div (ident,"section":cls,kvs) bls@(Header _ _ ils : _)) = do +blockToDjot (Div (ident,"section":cls,kvs) + (Header lev (_,hcls,hkvs) ils : bls)) = do ilsBs <- D.inlinesToByteString <$> inlinesToDjot ils let ident' = toIdentifier ilsBs let label = D.normalizeLabel ilsBs @@ -112,8 +113,10 @@ blockToDjot (Div (ident,"section":cls,kvs) bls@(Header _ _ ils : _)) = do fmap (D.addAttr (toDjotAttr (if autoid then "" else ident, filter (/= "section") cls, - filter (\(k,_) -> k /= "wrapper") kvs))) . D.section - <$> blocksToDjot bls + filter (\(k,_) -> k /= "wrapper") kvs) <> + toDjotAttr ("", [c | c <- hcls, c `notElem` cls], hkvs))) + . D.section + <$> blocksToDjot (Header lev mempty ils : bls) blockToDjot (Div attr@(ident,cls,kvs) bls) | Just "1" <- lookup "wrapper" kvs = fmap (D.addAttr diff --git a/test/command/10984.md b/test/command/10984.md new file mode 100644 index 000000000000..b718d959db53 --- /dev/null +++ b/test/command/10984.md @@ -0,0 +1,16 @@ + ``` + % pandoc -f html -t djot +

Hi +^D +{#foo .a .b} +# Hi +``` + +In this one the id is suppressed by the djot writer because +the same one would be automatically generated by the djot reader: +``` +% pandoc -f html -t djot +

Introduction

+^D +## Introduction +``` From 7cd02897babbdd1a0576a35a68e1482f9ff86581 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 22 Jul 2025 22:26:20 -0700 Subject: [PATCH 30/54] T.P.ImageSize: support avif images. [API change] New Avif constructor on ImageType. Closes #10979. --- src/Text/Pandoc/ImageSize.hs | 176 ++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 2 deletions(-) diff --git a/src/Text/Pandoc/ImageSize.hs b/src/Text/Pandoc/ImageSize.hs index 6e0558f8fbc4..b957b49bdee0 100644 --- a/src/Text/Pandoc/ImageSize.hs +++ b/src/Text/Pandoc/ImageSize.hs @@ -38,7 +38,7 @@ import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy as BL import Data.Binary.Get import Data.Bits ((.&.), shiftR, shiftL) -import Data.Word (bitReverse32) +import Data.Word (bitReverse32, Word32) import Data.Maybe (isJust, fromJust) import Data.Char (isDigit) import Control.Monad @@ -61,7 +61,7 @@ import Codec.Picture (decodeImageWithMetadata) -- quick and dirty functions to get image sizes -- algorithms borrowed from wwwis.pl -data ImageType = Png | Gif | Jpeg | Svg | Pdf | Eps | Emf | Tiff | Webp +data ImageType = Png | Gif | Jpeg | Svg | Pdf | Eps | Emf | Tiff | Webp | Avif deriving Show data Direction = Width | Height instance Show Direction where @@ -131,6 +131,7 @@ imageType img = case B.take 4 img of "RIFF" | B.take 4 (B.drop 8 img) == "WEBP" -> return Webp + _ | B.take 4 (B.drop 4 img) == "ftyp" -> return Avif _ -> mzero findSvgTag :: ByteString -> Bool @@ -148,6 +149,7 @@ imageSize opts img = checkDpi <$> Just Pdf -> mbToEither "could not determine PDF size" $ pdfSize img Just Emf -> mbToEither "could not determine EMF size" $ emfSize img Just Webp -> mbToEither "could not determine WebP size" $ webpSize opts img + Just Avif -> mbToEither "could not determine AVIF size" $ avifSize opts img Nothing -> Left "could not determine image type" where mbToEither msg Nothing = Left msg mbToEither _ (Just x) = Right x @@ -451,3 +453,173 @@ webpSize opts img = case AW.parseOnly pWebpSize img of Left _ -> Nothing Right sz -> Just sz { dpiX = fromIntegral $ writerDpi opts, dpiY = fromIntegral $ writerDpi opts} + +avifSize :: WriterOptions -> ByteString -> Maybe ImageSize +avifSize _opts img = + case runGetOrFail (verifyFtyp >> findAvifDimensions) (BL.fromStrict img) of + Left (_, _, _err) -> Nothing + Right (_, _, (width, height)) -> + Just $ ImageSize { pxX = fromIntegral width + , pxY = fromIntegral height + , dpiX = 72 + , dpiY = 72 } + +---- AVIF parsing: + +verifyFtyp :: Get () +verifyFtyp = do + ftypSize <- getWord32be + when (ftypSize < 16) $ fail "Invalid ftyp size" + + ftyp <- getByteString 4 + unless (ftyp == "ftyp") $ fail "ftyp signature not found" + + brand <- getByteString 4 + unless (brand == "avif" || brand == "avis") $ fail "Not an AVIF file" + + -- Skip minor version and compatible brands + -- (we've read 12 bytes: size+type+brand) + let remaining_ftyp = fromIntegral ftypSize - 12 + when (remaining_ftyp > 0) $ skip remaining_ftyp + +findAvifDimensions :: Get (Word32, Word32) +findAvifDimensions = searchAvifBoxes [] + +searchAvifBoxes :: [B.ByteString] -> Get (Word32, Word32) +searchAvifBoxes path = do + isempty <- isEmpty + if isempty + then fail $ "No dimensions found. Searched: " ++ show (reverse path) + else do + boxSize <- getWord32be + boxType <- getByteString 4 + + let contentSize = fromIntegral boxSize - 8 + let newPath = boxType : path + + -- If it's a container box, search inside it + if isContainerBox boxType + then searchInsideBox contentSize newPath + else do + -- Try to parse dimensions from this box + result <- tryParseDimensions boxType contentSize + case result of + Just dims -> return dims + Nothing -> do + -- Skip this box and continue + when (contentSize > 0 && contentSize < 10000000) $ + skip contentSize + searchAvifBoxes path + +tryParseDimensions :: B.ByteString -> Int -> Get (Maybe (Word32, Word32)) +tryParseDimensions boxType size = do + pos <- bytesRead + result <- case boxType of + "ispe" -> parseIspeBox + "tkhd" -> parseTkhdBox + "stsd" -> parseStsdBox + "av01" -> parseAv01Box + _ -> return Nothing + + -- Reset position if we didn't find dimensions + case result of + Nothing -> do + newPos <- bytesRead + let consumed = fromIntegral (newPos - pos) + case size - consumed of + n | n > 0 -> skip n + _ -> return () + Just _ -> return () + + return result + +parseIspeBox :: Get (Maybe (Word32, Word32)) +parseIspeBox = do + skip 4 -- version/flags + width <- getWord32be + height <- getWord32be + return $ Just (width, height) + +parseTkhdBox :: Get (Maybe (Word32, Word32)) +parseTkhdBox = do + version <- getWord8 + skip 3 -- flags + + -- Skip to width/height based on version + let skipBytes = if version == 1 then 76 else 64 + skip skipBytes + + width <- getWord32be + height <- getWord32be + -- Convert from 16.16 fixed point + return $ Just (width `shiftR` 16, height `shiftR` 16) + +parseStsdBox :: Get (Maybe (Word32, Word32)) +parseStsdBox = do + skip 8 -- version, flags, entry count + findAv01Entry + +findAv01Entry :: Get (Maybe (Word32, Word32)) +findAv01Entry = do + entrySize <- getWord32be + codec <- getByteString 4 + + if codec == "av01" + then do + skip 6 -- reserved + skip 2 -- data reference index + skip 16 -- pre-defined + reserved + width <- getWord16be + height <- getWord16be + return $ Just (fromIntegral width, fromIntegral height) + else do + let skipSize = fromIntegral entrySize - 8 + when (skipSize > 0) $ skip skipSize + findAv01Entry + +parseAv01Box :: Get (Maybe (Word32, Word32)) +parseAv01Box = do + skip 6 -- reserved + skip 2 -- data reference index + skip 16 -- predefined/reserved + width <- getWord16be + height <- getWord16be + return $ Just (fromIntegral width, fromIntegral height) + +searchInsideBox :: Int -> [B.ByteString] -> Get (Word32, Word32) +searchInsideBox size path = do + -- For meta boxes, skip version/flags + let isMeta = case path of + "meta":_ -> True + _ -> False + when isMeta $ skip 4 + + let searchSize = if isMeta then size - 4 else size + searchAvifBoxesInRange searchSize path + +searchAvifBoxesInRange :: Int -> [B.ByteString] -> Get (Word32, Word32) +searchAvifBoxesInRange remaining' path + | remaining' < 8 = searchAvifBoxes path + | otherwise = do + boxSize <- getWord32be + boxType <- getByteString 4 + + let contentSize = fromIntegral boxSize - 8 + let newPath = boxType : path + + when (contentSize < 0 || fromIntegral boxSize > remaining') $ do + fail $ "Malformed box at path: " ++ show (reverse newPath) + + if isContainerBox boxType + then searchInsideBox contentSize newPath + else do + result <- tryParseDimensions boxType contentSize + case result of + Just dims -> return dims + Nothing -> do + -- Don't skip here - tryParseDimensions already handled it + searchAvifBoxesInRange (remaining' - fromIntegral boxSize) path + +isContainerBox :: B.ByteString -> Bool +isContainerBox boxType = boxType `elem` + ["moov", "trak", "mdia", "minf", "stbl", "meta", "dinf", "ipco", "iprp"] From 23d480da63084020af2c955339d0e1a736d54ada Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 23 Jul 2025 08:51:49 -0700 Subject: [PATCH 31/54] Fix incomplete pattern matches from new ImageType constructor. --- src/Text/Pandoc/Writers/Docx/OpenXML.hs | 1 + src/Text/Pandoc/Writers/Powerpoint/Output.hs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Text/Pandoc/Writers/Docx/OpenXML.hs b/src/Text/Pandoc/Writers/Docx/OpenXML.hs index a6f6ad4d16df..0b76153f4b1c 100644 --- a/src/Text/Pandoc/Writers/Docx/OpenXML.hs +++ b/src/Text/Pandoc/Writers/Docx/OpenXML.hs @@ -1041,6 +1041,7 @@ inlineToOpenXML' opts (Image attr@(imgident, _, _) alt (src, title)) = do Just Emf -> ".emf" Just Tiff -> ".tiff" Just Webp -> ".webp" + Just Avif -> ".avif" Nothing -> "" imgpath = "media/" <> ident <> imgext mbMimeType = mt <|> getMimeType (T.unpack imgpath) diff --git a/src/Text/Pandoc/Writers/Powerpoint/Output.hs b/src/Text/Pandoc/Writers/Powerpoint/Output.hs index 2e51e64972e5..01a47141cee3 100644 --- a/src/Text/Pandoc/Writers/Powerpoint/Output.hs +++ b/src/Text/Pandoc/Writers/Powerpoint/Output.hs @@ -915,6 +915,7 @@ registerMedia fp caption = do Just Emf -> Just ".emf" Just Tiff -> Just ".tiff" Just Webp -> Just ".webp" + Just Avif -> Just ".avif" Nothing -> Nothing let newGlobalId = fromMaybe (maxGlobalId + 1) (M.lookup fp globalIds) From a52d8cb24e1b50135ed3b7a49b3c779392677481 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 23 Jul 2025 08:54:52 -0700 Subject: [PATCH 32/54] Fix CI so that -Wall -Werror works again! We were only getting the return status for the tests, apparently, from `cabal test`. So now we run `cabal build` separately. --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e31fa85d26b8..c156e49670e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,7 +120,8 @@ jobs: - name: Build and test run: | - cabal test ${{ matrix.versions.cabalopts }} --enable-tests --disable-optimization --ghc-options="${{ matrix.verisons.ghcopts }}" all + cabal build ${{ matrix.versions.cabalopts }} --enable-tests --disable-optimization --ghc-options="${{ matrix.verisons.ghcopts }}" all + cabal test ${{ matrix.versions.cabalopts }} --disable-optimization --ghc-options="${{ matrix.verisons.ghcopts }}" all linux-stack: From 3d1be4e0a7631a4f162f86184b7a146951a45a46 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 23 Jul 2025 09:09:50 -0700 Subject: [PATCH 33/54] Makefile: add -Wall to ghc options. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7c6b2bc17937..eac9d82ebd54 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ BASELINECMD= else BASELINECMD=--baseline $(BASELINE) endif -GHCOPTS=-fwrite-ide-info -fdiagnostics-color=always -j +RTS -A8m -RTS +GHCOPTS=-fwrite-ide-info -fdiagnostics-color=always -Wall -j +RTS -A8m -RTS CABALOPTS?=--disable-optimization -f-export-dynamic WEBSITE=../../web/pandoc.org REVISION?=1 From 8dfb2fa614a7391bf4f4d71a06d474096c3d3a11 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Wed, 23 Jul 2025 18:57:21 +0200 Subject: [PATCH 34/54] Lua: add function `pandoc.path.exists`. The functions allows to check the existence of file-system objects. --- doc/lua-filters.md | 26 ++++++++++ pandoc-lua-engine/pandoc-lua-engine.cabal | 3 +- .../src/Text/Pandoc/Lua/Module.hs | 5 +- .../src/Text/Pandoc/Lua/Module/Path.hs | 50 +++++++++++++++++++ stack.yaml | 2 +- 5 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 pandoc-lua-engine/src/Text/Pandoc/Lua/Module/Path.hs diff --git a/doc/lua-filters.md b/doc/lua-filters.md index 1f5998fb52aa..53d162a34315 100644 --- a/doc/lua-filters.md +++ b/doc/lua-filters.md @@ -5314,6 +5314,32 @@ Returns: *Since: 2.12* +### exists {#pandoc.path.exists} + +`exists (path[, type])` + +Check whether there exists a filesystem object at the given path. +If `type` is given and either *directory* or *file*, then the +function returns `true` if and only if the file system object has +the given type, or if it's a symlink pointing to an object of that +type. Passing *symlink* as type requires the path itself to be a +symlink. Types other than those will cause an error. + +Parameters: + +`path` +: file path to check (string) + +`type` +: the required type of the filesystem object (string) + +Returns: + +- whether a filesystem object of type `type` exists at `path`. + (boolean) + +*Since: 3.7.1* + ### filename {#pandoc.path.filename} `filename (filepath)` diff --git a/pandoc-lua-engine/pandoc-lua-engine.cabal b/pandoc-lua-engine/pandoc-lua-engine.cabal index 5cd6c570bf37..59b9140d07ea 100644 --- a/pandoc-lua-engine/pandoc-lua-engine.cabal +++ b/pandoc-lua-engine/pandoc-lua-engine.cabal @@ -93,6 +93,7 @@ library , Text.Pandoc.Lua.Module.Log , Text.Pandoc.Lua.Module.MediaBag , Text.Pandoc.Lua.Module.Pandoc + , Text.Pandoc.Lua.Module.Path , Text.Pandoc.Lua.Module.Scaffolding , Text.Pandoc.Lua.Module.Structure , Text.Pandoc.Lua.Module.System @@ -119,7 +120,7 @@ library , hslua >= 2.3 && < 2.5 , hslua-module-doclayout>= 1.2 && < 1.3 , hslua-module-path >= 1.1 && < 1.2 - , hslua-module-system >= 1.2 && < 1.3 + , hslua-module-system >= 1.2.1 && < 1.3 , hslua-module-text >= 1.1 && < 1.2 , hslua-module-version >= 1.1 && < 1.2 , hslua-module-zip >= 1.1.3 && < 1.2 diff --git a/pandoc-lua-engine/src/Text/Pandoc/Lua/Module.hs b/pandoc-lua-engine/src/Text/Pandoc/Lua/Module.hs index 5d2e1040a45e..9966c4a45529 100644 --- a/pandoc-lua-engine/src/Text/Pandoc/Lua/Module.hs +++ b/pandoc-lua-engine/src/Text/Pandoc/Lua/Module.hs @@ -23,7 +23,6 @@ import qualified Data.ByteString.Char8 as Char8 import qualified Lua.LPeg as LPeg import qualified HsLua.Aeson import qualified HsLua.Module.DocLayout as Module.Layout -import qualified HsLua.Module.Path as Module.Path import qualified HsLua.Module.Zip as Module.Zip import qualified Text.Pandoc.Lua.Module.CLI as Pandoc.CLI import qualified Text.Pandoc.Lua.Module.Format as Pandoc.Format @@ -32,6 +31,7 @@ import qualified Text.Pandoc.Lua.Module.JSON as Pandoc.JSON import qualified Text.Pandoc.Lua.Module.Log as Pandoc.Log import qualified Text.Pandoc.Lua.Module.MediaBag as Pandoc.MediaBag import qualified Text.Pandoc.Lua.Module.Pandoc as Module.Pandoc +import qualified Text.Pandoc.Lua.Module.Path as Pandoc.Path import qualified Text.Pandoc.Lua.Module.Scaffolding as Pandoc.Scaffolding import qualified Text.Pandoc.Lua.Module.Structure as Pandoc.Structure import qualified Text.Pandoc.Lua.Module.System as Pandoc.System @@ -84,6 +84,7 @@ submodules = , Pandoc.JSON.documentedModule , Pandoc.Log.documentedModule , Pandoc.MediaBag.documentedModule + , Pandoc.Path.documentedModule , Pandoc.Scaffolding.documentedModule , Pandoc.Structure.documentedModule , Pandoc.System.documentedModule @@ -95,8 +96,6 @@ submodules = `allSince` [2,18]) `functionsSince` ["bold", "italic", "underlined", "strikeout", "fg", "bg"]) [3, 4, 1] - , Module.Path.documentedModule { moduleName = "pandoc.path" } - `allSince` [2,12] , Module.Zip.documentedModule { moduleName = "pandoc.zip" } `allSince` [3,0] ] diff --git a/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/Path.hs b/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/Path.hs new file mode 100644 index 000000000000..1d2169976079 --- /dev/null +++ b/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/Path.hs @@ -0,0 +1,50 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{- | + Module : Text.Pandoc.Lua.Module.Path + Copyright : © 2019-2024 Albert Krewinkel + License : GNU GPL, version 2 or above + + Maintainer : Albert Krewinkel + Stability : alpha + +Pandoc's system Lua module. +-} +module Text.Pandoc.Lua.Module.Path + ( documentedModule + ) where + +import Data.Version (makeVersion) +import HsLua +import qualified HsLua.Module.Path as MPath +import qualified HsLua.Module.System as MSystem + +-- | Push the pandoc.system module on the Lua stack. +documentedModule :: forall e. LuaError e => Module e +documentedModule = Module + { moduleName = "pandoc.path" + , moduleDescription = moduleDescription @e MPath.documentedModule + , moduleFields = + [ MPath.separator + , MPath.search_path_separator + ] + , moduleFunctions = + [ MPath.directory `since` v[2,12] + , MSystem.exists `since` v[3,7,1] + , MPath.filename `since` v[2,12] + , MPath.is_absolute `since` v[2,12] + , MPath.is_relative `since` v[2,12] + , MPath.join `since` v[2,12] + , MPath.make_relative `since` v[2,12] + , MPath.normalize `since` v[2,12] + , MPath.split `since` v[2,12] + , MPath.split_extension `since` v[2,12] + , MPath.split_search_path `since` v[2,12] + , MPath.treat_strings_as_paths `since` v[2,12] + ] + , moduleOperations = [] + , moduleTypeInitializers = [] + } + where + v = makeVersion diff --git a/stack.yaml b/stack.yaml index ea4ffe54f019..7d0550bc1c11 100644 --- a/stack.yaml +++ b/stack.yaml @@ -11,7 +11,7 @@ packages: extra-deps: - hslua-2.4.0 - hslua-module-doclayout-1.2.0.1 -- hslua-module-system-1.2.0 +- hslua-module-system-1.2.1 - hslua-objectorientation-2.4.0 - hslua-packaging-2.3.2 - pandoc-lua-marshal-0.3.1 From addfa97db7790a82780dc1bbae7fef91b8d2d301 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 23 Jul 2025 14:08:14 -0700 Subject: [PATCH 35/54] Use latest dev citeproc. Closes #10983 by allowing `nocase` spans to be used to suppress capitalization of initial word in a footnote. --- cabal.project | 2 +- stack.yaml | 2 +- test/command/biblatex-britannica.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cabal.project b/cabal.project index 281f67395b6e..00875409ccb3 100644 --- a/cabal.project +++ b/cabal.project @@ -12,6 +12,6 @@ constraints: skylighting-format-blaze-html >= 0.1.1.3, source-repository-package type: git location: https://github.com/jgm/citeproc.git - tag: 8cb87866967674049a8d1c933dc1effbfe80e8ef + tag: 120d0914adf90908ae0eca972a061e9edd6e65a1 -- TODO: release new skylighting-core, skylighting diff --git a/stack.yaml b/stack.yaml index 7d0550bc1c11..07aa047e21b8 100644 --- a/stack.yaml +++ b/stack.yaml @@ -23,7 +23,7 @@ extra-deps: - texmath-0.12.10.3 - typst-0.8.0.1 - git: https://github.com/jgm/citeproc.git - commit: 8cb87866967674049a8d1c933dc1effbfe80e8ef + commit: 120d0914adf90908ae0eca972a061e9edd6e65a1 ghc-options: "$locals": -fhide-source-paths -Wno-missing-home-modules resolver: lts-23.22 diff --git a/test/command/biblatex-britannica.md b/test/command/biblatex-britannica.md index 37a3a0720d8d..cd04d1b4f263 100644 --- a/test/command/biblatex-britannica.md +++ b/test/command/biblatex-britannica.md @@ -76,8 +76,8 @@ references: number-of-volumes: 32 publisher: Encyclopædia Britannica publisher-place: Chicago, Ill. - title: The new encyclopædia Britannica - title-short: Encyclopædia Britannica + title: The new encyclop[æ]{.nocase}dia Britannica + title-short: Encyclop[æ]{.nocase}dia Britannica type: book --- From a42a84c67d8e8840163afb5019dbe71bf32334be Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 23 Jul 2025 14:09:34 -0700 Subject: [PATCH 36/54] Revise Makefile and CI treatment of `--ghc-options`. Previously we set `--ghc-options` in Makefile and CI; but this overrides the ghc-options set in the pandoc.cabal file. Better to add options one-by-one using `--ghc-option`. We no longer use GHC_OPTIONS and just put these extra options in CABAL_OPTIONS. --- .github/workflows/ci.yml | 28 ++++++++++------------------ Makefile | 14 ++++---------- pandoc.cabal | 2 +- 3 files changed, 15 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c156e49670e8..00135c94d9ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,36 +50,28 @@ jobs: versions: - ghc: '8.10' cabal: 'latest' - cabalopts: '' - ghcopts: '-Werror' + cabalopts: '--ghc-option=-Werror' - ghc: '9.0' cabal: 'latest' - cabalopts: '' - ghcopts: '-Werror' + cabalopts: '--ghc-option=-Werror' - ghc: '9.2' cabal: 'latest' - cabalopts: '' - ghcopts: '-Werror' + cabalopts: '--ghc-option=-Werror' - ghc: '9.4' cabal: 'latest' - cabalopts: '' - ghcopts: '-Werror' + cabalopts: '--ghc-option=-Werror' - ghc: '9.6' cabal: 'latest' - cabalopts: '' - ghcopts: '-Werror' + cabalopts: '--ghc-option=-Werror' - ghc: '9.8' cabal: 'latest' - cabalopts: '' - ghcopts: '-Werror' + cabalopts: '--ghc-option=-Werror' - ghc: '9.10' cabal: 'latest' - cabalopts: '' - ghcopts: '' + cabalopts: '--ghc-option=-Werror' - ghc: '9.12' cabal: 'latest' - cabalopts: '--allow-newer' - ghcopts: '' + cabalopts: '--allow-newer --ghc-option=-Werror' steps: - uses: actions/checkout@v4 @@ -120,8 +112,8 @@ jobs: - name: Build and test run: | - cabal build ${{ matrix.versions.cabalopts }} --enable-tests --disable-optimization --ghc-options="${{ matrix.verisons.ghcopts }}" all - cabal test ${{ matrix.versions.cabalopts }} --disable-optimization --ghc-options="${{ matrix.verisons.ghcopts }}" all + cabal build ${{ matrix.versions.cabalopts }} --enable-tests --disable-optimization all + cabal test ${{ matrix.versions.cabalopts }} --disable-optimization all linux-stack: diff --git a/Makefile b/Makefile index eac9d82ebd54..fd007cd5bbe4 100644 --- a/Makefile +++ b/Makefile @@ -12,8 +12,7 @@ BASELINECMD= else BASELINECMD=--baseline $(BASELINE) endif -GHCOPTS=-fwrite-ide-info -fdiagnostics-color=always -Wall -j +RTS -A8m -RTS -CABALOPTS?=--disable-optimization -f-export-dynamic +CABALOPTS?=--disable-optimization -f-export-dynamic --ghc-option=-fwrite-ide-info --ghc-option=-fdiagnostics-color=always --ghc-option=-j WEBSITE=../../web/pandoc.org REVISION?=1 BENCHARGS?=--csv bench_$(TIMESTAMP).csv $(BASELINECMD) --timeout=6 +RTS -T --nonmoving-gc -RTS $(if $(PATTERN),--pattern "$(PATTERN)",) @@ -24,7 +23,6 @@ all: build test binpath ## build executable and run tests build: ## build executable cabal build \ - --ghc-options='$(GHCOPTS)' \ $(CABALOPTS) pandoc-cli .PHONY: build @@ -33,7 +31,7 @@ prof: ## build with profiling and optimizations .PHONY: prof binpath: ## print path of built pandoc executable - @cabal list-bin -v0 $(CABALOPTS) --ghc-options='$(GHCOPTS)' pandoc-cli + @cabal list-bin -v0 $(CABALOPTS) pandoc-cli .PHONY: binpath ghcid: ## run ghcid @@ -52,14 +50,12 @@ linecounts: ## print line counts for each module # make test TESTARGS='--accept' test: ## unoptimized build and run tests with cabal cabal test \ - --ghc-options='$(GHCOPTS)' \ $(CABALOPTS) \ --test-options="--hide-successes --ansi-tricks=false $(TESTARGS)" all .PHONY: test quick-stack: ## unoptimized build and tests with stack stack install \ - --ghc-options='$(GHCOPTS)' \ --system-ghc --flag 'pandoc:embed_data_files' \ --fast \ --test \ @@ -149,7 +145,7 @@ latex-package-dependencies: ## print packages used by default latex template coverage: ## code coverage information cabal test \ - --ghc-options='-fhpc $(GHCOPTS)' \ + --ghc-option=-fhpc \ $(CABALOPTS) \ --test-options="--hide-successes --ansi-tricks=false $(TESTARGS)" hpc markup --destdir=coverage test/test-pandoc.tix @@ -169,8 +165,7 @@ debpkg: ## create linux package -v `pwd`/linux/artifacts:/artifacts \ --user $(id -u):$(id -g) \ -e REVISION=$(REVISION) \ - -e GHCOPTS="-j4 +RTS -A256m -RTS -split-sections -optc-Os -optl=-pthread" \ - -e CABALOPTS="-f-export-dynamic -fembed_data_files -fserver -flua --enable-executable-static -j4" \ + -e CABALOPTS="-f-export-dynamic -fembed_data_files -fserver -flua --enable-executable-static -j4 --ghc-option=-j4 --ghc-option=-split-sections --ghc-option=-optc-Os --ghc-option=-optl=-pthread" \ -w /mnt \ --memory=0 \ --rm \ @@ -317,7 +312,6 @@ help: ## display this help @echo @echo "Environment variables with default values:" @printf "%-16s%s\n" "CABALOPTS" "$(CABALOPTS)" - @printf "%-16s%s\n" "GHCOPTS" "$(GHCOPTS)" @printf "%-16s%s\n" "TESTARGS" "$(TESTARGS)" @printf "%-16s%s\n" "BASELINE" "$(BASELINE)" @printf "%-16s%s\n" "REVISION" "$(REVISION)" diff --git a/pandoc.cabal b/pandoc.cabal index 98493dc8582d..d045f49f79af 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -451,7 +451,7 @@ common common-options -Wpartial-fields -Wmissing-signatures -fhide-source-paths - -- -Wmissing-export-lists + -Wmissing-export-lists if impl(ghc >= 8.10) ghc-options: -Wunused-packages From 6e46b62b910a184c28747f6944a1e8d7e3d30e51 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 23 Jul 2025 14:20:01 -0700 Subject: [PATCH 37/54] Ensure that all modules have explicit export lists. --- src/Text/Pandoc/Readers/ODT/Arrows/State.hs | 16 ++++++++- src/Text/Pandoc/Readers/ODT/Arrows/Utils.hs | 35 ++++++++++++++++++- src/Text/Pandoc/Readers/ODT/Base.hs | 6 +++- .../Pandoc/Readers/ODT/Generic/Fallible.hs | 16 ++++++++- .../Pandoc/Readers/ODT/Generic/Namespaces.hs | 6 +++- src/Text/Pandoc/Readers/ODT/Generic/SetMap.hs | 8 ++++- test/test-pandoc.hs | 6 ++-- 7 files changed, 83 insertions(+), 10 deletions(-) diff --git a/src/Text/Pandoc/Readers/ODT/Arrows/State.hs b/src/Text/Pandoc/Readers/ODT/Arrows/State.hs index 742f6e9ee5b2..5307c1063548 100644 --- a/src/Text/Pandoc/Readers/ODT/Arrows/State.hs +++ b/src/Text/Pandoc/Readers/ODT/Arrows/State.hs @@ -17,7 +17,21 @@ Most of these might be implemented without access to innards, but it's much faster and easier to implement this way. -} -module Text.Pandoc.Readers.ODT.Arrows.State where +module Text.Pandoc.Readers.ODT.Arrows.State + ( ArrowState(..) + , withState + , modifyState + , ignoringState + , fromState + , extractFromState + , tryModifyState + , withSubStateF + , withSubStateF' + , foldS + , iterateS + , iterateSL + , iterateS' + ) where import Control.Arrow import qualified Control.Category as Cat diff --git a/src/Text/Pandoc/Readers/ODT/Arrows/Utils.hs b/src/Text/Pandoc/Readers/ODT/Arrows/Utils.hs index 339bff1cb3f4..f392306165e4 100644 --- a/src/Text/Pandoc/Readers/ODT/Arrows/Utils.hs +++ b/src/Text/Pandoc/Readers/ODT/Arrows/Utils.hs @@ -19,7 +19,40 @@ with an equivalent return value. -} -- We export everything -module Text.Pandoc.Readers.ODT.Arrows.Utils where +module Text.Pandoc.Readers.ODT.Arrows.Utils + ( and2 + , and3 + , and4 + , and5 + , and6 + , liftA2 + , liftA3 + , liftA4 + , liftA5 + , liftA6 + , liftA + , duplicate + , (>>%) + , keepingTheValue + , (^|||) + , (|||^) + , (^|||^) + , (^&&&) + , (&&&^) + , choiceToMaybe + , maybeToChoice + , returnV + , FallibleArrow + , liftAsSuccess + , (>>?) + , (>>?^) + , (>>?^?) + , (^>>?) + , (>>?!) + , (>>?%) + , (>>?%?) + , ifFailedDo + ) where import Prelude hiding (Applicative(..)) import Control.Arrow diff --git a/src/Text/Pandoc/Readers/ODT/Base.hs b/src/Text/Pandoc/Readers/ODT/Base.hs index 4a99f5ad6e4c..bf0fbe86e044 100644 --- a/src/Text/Pandoc/Readers/ODT/Base.hs +++ b/src/Text/Pandoc/Readers/ODT/Base.hs @@ -10,7 +10,11 @@ Core types of the odt reader. -} -module Text.Pandoc.Readers.ODT.Base where +module Text.Pandoc.Readers.ODT.Base + ( ODTConverterState + , XMLReader + , XMLReaderSafe + ) where import Text.Pandoc.Readers.ODT.Generic.XMLConverter import Text.Pandoc.Readers.ODT.Namespaces diff --git a/src/Text/Pandoc/Readers/ODT/Generic/Fallible.hs b/src/Text/Pandoc/Readers/ODT/Generic/Fallible.hs index c6f45ced107b..122e8f195200 100644 --- a/src/Text/Pandoc/Readers/ODT/Generic/Fallible.hs +++ b/src/Text/Pandoc/Readers/ODT/Generic/Fallible.hs @@ -17,7 +17,21 @@ compatible instances of "ArrowChoice". -} -- We export everything -module Text.Pandoc.Readers.ODT.Generic.Fallible where +module Text.Pandoc.Readers.ODT.Generic.Fallible + ( Failure + , Fallible + , maybeToEither + , eitherToMaybe + , recover + , failWith + , failEmpty + , succeedWith + , collapseEither + , chooseMax + , chooseMaxWith + , ChoiceVector(..) + , SuccessList(..) + ) where -- | Default for now. Will probably become a class at some point. type Failure = () diff --git a/src/Text/Pandoc/Readers/ODT/Generic/Namespaces.hs b/src/Text/Pandoc/Readers/ODT/Generic/Namespaces.hs index d7310d2e531c..7d0136f29d34 100644 --- a/src/Text/Pandoc/Readers/ODT/Generic/Namespaces.hs +++ b/src/Text/Pandoc/Readers/ODT/Generic/Namespaces.hs @@ -11,7 +11,11 @@ A class containing a set of namespace identifiers. Used to convert between typesafe Haskell namespace identifiers and unsafe "real world" namespaces. -} -module Text.Pandoc.Readers.ODT.Generic.Namespaces where +module Text.Pandoc.Readers.ODT.Generic.Namespaces + ( NameSpaceIRI + , NameSpaceIRIs + , NameSpaceID(..) + ) where import qualified Data.Map as M import Data.Text (Text) diff --git a/src/Text/Pandoc/Readers/ODT/Generic/SetMap.hs b/src/Text/Pandoc/Readers/ODT/Generic/SetMap.hs index be586803bc15..50461890b741 100644 --- a/src/Text/Pandoc/Readers/ODT/Generic/SetMap.hs +++ b/src/Text/Pandoc/Readers/ODT/Generic/SetMap.hs @@ -10,7 +10,13 @@ A map of values to sets of values. -} -module Text.Pandoc.Readers.ODT.Generic.SetMap where +module Text.Pandoc.Readers.ODT.Generic.SetMap + ( SetMap + , empty + , fromList + , insert + , union3 + ) where import qualified Data.Map as M import qualified Data.Set as S diff --git a/test/test-pandoc.hs b/test/test-pandoc.hs index d310b932f316..2f53c16beb07 100644 --- a/test/test-pandoc.hs +++ b/test/test-pandoc.hs @@ -1,6 +1,4 @@ -{-# OPTIONS_GHC -Wall #-} - -module Main where +module Main (main) where import System.Environment (getArgs, getExecutablePath) import qualified Control.Exception as E @@ -122,4 +120,4 @@ main = do _ -> inDirectory "test" $ do fp <- getExecutablePath -- putStrLn $ "Using pandoc executable at " ++ fp - defaultMain $ tests fp + defaultMain $ tests fp \ No newline at end of file From 5f56d62bfda310ad000e76ac34063fdc62d8ecc5 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 23 Jul 2025 15:20:34 -0700 Subject: [PATCH 38/54] CI: don't warn on unused imports in ghc 9.10+. For now I want to avoid having to put in lots of CPP. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00135c94d9ca..b9b933eaf7dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,10 +68,10 @@ jobs: cabalopts: '--ghc-option=-Werror' - ghc: '9.10' cabal: 'latest' - cabalopts: '--ghc-option=-Werror' + cabalopts: '--ghc-option=-Werror --ghc-option=-W-no-unused-imports' - ghc: '9.12' cabal: 'latest' - cabalopts: '--allow-newer --ghc-option=-Werror' + cabalopts: '--allow-newer --ghc-option=-Werror --ghc-options=-W-no-unused-imports' steps: - uses: actions/checkout@v4 From 538bb04d1102ae9ce7c41117ba768e5955763172 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 23 Jul 2025 15:25:15 -0700 Subject: [PATCH 39/54] CI: another stab at preventing ghc 9.10, 9.12 from erroring. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b9b933eaf7dd..d87d582cb7d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,10 +68,10 @@ jobs: cabalopts: '--ghc-option=-Werror' - ghc: '9.10' cabal: 'latest' - cabalopts: '--ghc-option=-Werror --ghc-option=-W-no-unused-imports' + cabalopts: '--ghc-option=-Werror --ghc-option=-Werror-no-unused-imports' - ghc: '9.12' cabal: 'latest' - cabalopts: '--allow-newer --ghc-option=-Werror --ghc-options=-W-no-unused-imports' + cabalopts: '--allow-newer --ghc-option=-Werror --ghc-option=-Werror-no-unused-imports --ghc-option=-Werror-no-deriving-typeable' steps: - uses: actions/checkout@v4 From 16b6ec04ac92033b6c50464a4c0219fb6251e892 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 23 Jul 2025 16:07:09 -0700 Subject: [PATCH 40/54] Fix CI again. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d87d582cb7d8..66802fbb0428 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,10 +68,10 @@ jobs: cabalopts: '--ghc-option=-Werror' - ghc: '9.10' cabal: 'latest' - cabalopts: '--ghc-option=-Werror --ghc-option=-Werror-no-unused-imports' + cabalopts: '--ghc-option=-Werror --ghc-option=-Wno-unused-imports' - ghc: '9.12' cabal: 'latest' - cabalopts: '--allow-newer --ghc-option=-Werror --ghc-option=-Werror-no-unused-imports --ghc-option=-Werror-no-deriving-typeable' + cabalopts: '--allow-newer --ghc-option=-Werror --ghc-option=-Wno-unused-imports --ghc-option=-Wno-deriving-typeable' steps: - uses: actions/checkout@v4 From f9ce3cd49757e9a455e4f980d7d629219609716b Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 23 Jul 2025 16:08:34 -0700 Subject: [PATCH 41/54] Use latest dev citeproc. --- cabal.project | 2 +- stack.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cabal.project b/cabal.project index 00875409ccb3..14d359de0eb9 100644 --- a/cabal.project +++ b/cabal.project @@ -12,6 +12,6 @@ constraints: skylighting-format-blaze-html >= 0.1.1.3, source-repository-package type: git location: https://github.com/jgm/citeproc.git - tag: 120d0914adf90908ae0eca972a061e9edd6e65a1 + tag: 723d22a112a15a8f287d4db68ba05e9083facfec -- TODO: release new skylighting-core, skylighting diff --git a/stack.yaml b/stack.yaml index 07aa047e21b8..19f481e2e3fc 100644 --- a/stack.yaml +++ b/stack.yaml @@ -23,7 +23,7 @@ extra-deps: - texmath-0.12.10.3 - typst-0.8.0.1 - git: https://github.com/jgm/citeproc.git - commit: 120d0914adf90908ae0eca972a061e9edd6e65a1 + commit: 723d22a112a15a8f287d4db68ba05e9083facfec ghc-options: "$locals": -fhide-source-paths -Wno-missing-home-modules resolver: lts-23.22 From 9b7287e2ef4e1903c2599cdac4ae976ce1673121 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 23 Jul 2025 18:46:12 -0700 Subject: [PATCH 42/54] Use dev texmath. --- cabal.project | 5 +++++ stack.yaml | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cabal.project b/cabal.project index 14d359de0eb9..e3a3eb97f407 100644 --- a/cabal.project +++ b/cabal.project @@ -14,4 +14,9 @@ source-repository-package location: https://github.com/jgm/citeproc.git tag: 723d22a112a15a8f287d4db68ba05e9083facfec +source-repository-package + type: git + location: https://github.com/jgm/texmath.git + tag: 77e20978ffcdec4ca50bbb809f061850c0998560 + -- TODO: release new skylighting-core, skylighting diff --git a/stack.yaml b/stack.yaml index 19f481e2e3fc..9aa091f152dd 100644 --- a/stack.yaml +++ b/stack.yaml @@ -22,8 +22,8 @@ extra-deps: - typst-symbols-0.1.8.1 - texmath-0.12.10.3 - typst-0.8.0.1 -- git: https://github.com/jgm/citeproc.git - commit: 723d22a112a15a8f287d4db68ba05e9083facfec +- git: https://github.com/jgm/texmath.git + commit: 77e20978ffcdec4ca50bbb809f061850c0998560 ghc-options: "$locals": -fhide-source-paths -Wno-missing-home-modules resolver: lts-23.22 From 8ecb2a8d8ae863267456add0ed5ea93f60fc45e0 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 23 Jul 2025 23:32:48 -0700 Subject: [PATCH 43/54] Fix stack.yaml. --- stack.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stack.yaml b/stack.yaml index 9aa091f152dd..40955fa00261 100644 --- a/stack.yaml +++ b/stack.yaml @@ -20,8 +20,9 @@ extra-deps: - skylighting-0.14.6 - skylighting-format-typst-0.1 - typst-symbols-0.1.8.1 -- texmath-0.12.10.3 - typst-0.8.0.1 +- git: https://github.com/jgm/citeproc.git + commit: 723d22a112a15a8f287d4db68ba05e9083facfec - git: https://github.com/jgm/texmath.git commit: 77e20978ffcdec4ca50bbb809f061850c0998560 ghc-options: From e1e24939e6cdc9cc2db24e4f9e371ae82264d764 Mon Sep 17 00:00:00 2001 From: Christopher Kenny Date: Mon, 8 Jul 2024 22:08:30 -0400 Subject: [PATCH 44/54] Add features to typst base template. This implements the changes suggested in #9956, with the exception of the filecolor/urlcolor one. These would require adding some regex to guess the link types. This is theoretically possible to do, but it wasn't clear to me that this is a good thing to put in a default template. Happy to adjust if you have thoughts on this. Closes #9956. Some things to note: I'm converting colors by passing them as content, as I was seeing pandoc escape # if that was included. I set the default fonts for math and code ("raw") to fonts that are bundled with Typst. These need not be those fonts if there are more familiar pandoc preferences. --- MANUAL.txt | 15 ++++- data/templates/default.typst | 24 ++++++++ data/templates/template.typst | 100 ++++++++++++++++++++------------- test/writer.typst | 101 +++++++++++++++++++++------------- 4 files changed, 165 insertions(+), 75 deletions(-) diff --git a/MANUAL.txt b/MANUAL.txt index 39355c4242bd..7ee20e59a48c 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -2728,7 +2728,7 @@ Currently the following pipes are predefined: documents `abstract-title` -: title of abstract, currently used only in HTML, EPUB, and docx. +: title of abstract, currently used only in HTML, EPUB, docx, and Typst. This will be set automatically to a localized value, depending on `lang`, but can be manually overridden. @@ -3391,6 +3391,19 @@ The `--css` option also affects the output. `columns` : Number of columns for body text. +`thanks` +: contents of acknowledgments footnote after document title + +`mathfont`, `codefont` +: Name of system font to use for math and code, respectively. + +`linestretch` +: adjusts line spacing, e.g. `1.25`, `1.5` + +`linkcolor`, `filecolor`, `citecolor` +: color for external links, internal links, and citation links, + respectively: expects a hexadecimal color code + ### Variables for ms `fontfamily` diff --git a/data/templates/default.typst b/data/templates/default.typst index 79b2c33f5833..00e1ec557c10 100644 --- a/data/templates/default.typst +++ b/data/templates/default.typst @@ -71,9 +71,15 @@ $endif$ $if(region)$ region: "$region$", $endif$ +$if(abstract-title)$ + abstract-title: [$abstract-title$], +$endif$ $if(abstract)$ abstract: [$abstract$], $endif$ +$if(thanks)$ + thanks: [$thanks$], +$endif$ $if(margin)$ margin: ($for(margin/pairs)$$margin.key$: $margin.value$,$endfor$), $endif$ @@ -86,10 +92,28 @@ $endif$ $if(fontsize)$ fontsize: $fontsize$, $endif$ +$if(mathfont)$ + mathfont: ($for(mathfont)$"$mathfont$",$endfor$), +$endif$ +$if(codefont)$ + codefont: ($for(codefont)$"$codefont$",$endfor$), +$endif$ +$if(linestretch)$ + linestretch: $linestretch$, +$endif$ $if(section-numbering)$ sectionnumbering: "$section-numbering$", $endif$ pagenumbering: $if(page-numbering)$"$page-numbering$"$else$none$endif$, +$if(linkcolor)$ + linkcolor: [$linkcolor$], +$endif$ +$if(citecolor)$ + citecolor: [$citecolor$], +$endif$ +$if(filecolor)$ + filecolor: [$filecolor$], +$endif$ cols: $if(columns)$$columns$$else$1$endif$, doc, ) diff --git a/data/templates/template.typst b/data/templates/template.typst index 24b1320fb910..1afaa35fc3ca 100644 --- a/data/templates/template.typst +++ b/data/templates/template.typst @@ -15,7 +15,9 @@ authors: (), keywords: (), date: none, + abstract-title: none, abstract: none, + thanks: none, cols: 1, margin: (x: 1.25in, y: 1.25in), paper: "us-letter", @@ -23,66 +25,90 @@ region: "US", font: (), fontsize: 11pt, + mathfont: none, + codefont: none, + linestretch: 1, sectionnumbering: none, + linkcolor: none, + citecolor: none, + filecolor: none, pagenumbering: "1", doc, ) = { set document( title: title, - author: authors.map(author => content-to-string(author.name)), + author: authors.map(author => content-to-string(author.name)).join(", ", last: " & "), keywords: keywords, ) set page( paper: paper, margin: margin, numbering: pagenumbering, - columns: cols, - ) - set par(justify: true) + ) + + set par( + justify: true, + leading: linestretch * 0.65em + ) set text(lang: lang, region: region, font: font, size: fontsize) + + show math.equation: set text(font: mathfont) if mathfont != none + show raw: set text(font: codefont) if codefont != none + set heading(numbering: sectionnumbering) - place(top, float: true, scope: "parent", clearance: 4mm)[ - #if title != none { - align(center)[#block(inset: 2em)[ - #text(weight: "bold", size: 1.5em)[#title] - #(if subtitle != none { - parbreak() - text(weight: "bold", size: 1.25em)[#subtitle] - }) - ]] + show link: set text(fill: rgb(content-to-string(linkcolor))) if linkcolor != none + show ref: set text(fill: rgb(content-to-string(citecolor))) if citecolor != none + show link: this => { + if filecolor != none and type(this.dest) == label { + text(this, fill: rgb(content-to-string(filecolor))) + } } - #if authors != none and authors != [] { - let count = authors.len() - let ncols = calc.min(count, 3) - grid( - columns: (1fr,) * ncols, - row-gutter: 1.5em, - ..authors.map(author => - align(center)[ - #author.name \ - #author.affiliation \ - #author.email - ] + block(below: 4mm)[ + #if title != none { + align(center)[#block(inset: 2em)[ + #text(weight: "bold", size: 1.5em)[#title #if thanks != none { + footnote(thanks, numbering: "*") + counter(footnote).update(n => n - 1) + }] + #( + if subtitle != none { + parbreak() + text(weight: "bold", size: 1.25em)[#subtitle] + } + ) + ]] + } + + #if authors != none and authors != [] { + let count = authors.len() + let ncols = calc.min(count, 3) + grid( + columns: (1fr,) * ncols, + row-gutter: 1.5em, + ..authors.map(author => align(center)[ + #author.name \ + #author.affiliation \ + #author.email + ]) ) - ) - } + } - #if date != none { - align(center)[#block(inset: 1em)[ - #date - ]] - } + #if date != none { + align(center)[#block(inset: 1em)[ + #date + ]] + } - #if abstract != none { - block(inset: 2em)[ - #text(weight: "semibold")[$if(abstract-title)$${abstract-title}$else$Abstract$endif$] #h(1em) #abstract - ] - } + #if abstract != none { + block(inset: 2em)[ + #text(weight: "semibold")[#abstract-title] #h(1em) #abstract + ] + } ] doc diff --git a/test/writer.typst b/test/writer.typst index 5ff3051d426b..5521680c70d4 100644 --- a/test/writer.typst +++ b/test/writer.typst @@ -39,7 +39,9 @@ authors: (), keywords: (), date: none, + abstract-title: none, abstract: none, + thanks: none, cols: 1, margin: (x: 1.25in, y: 1.25in), paper: "us-letter", @@ -47,66 +49,90 @@ region: "US", font: (), fontsize: 11pt, + mathfont: none, + codefont: none, + linestretch: 1, sectionnumbering: none, + linkcolor: none, + citecolor: none, + filecolor: none, pagenumbering: "1", doc, ) = { set document( title: title, - author: authors.map(author => content-to-string(author.name)), + author: authors.map(author => content-to-string(author.name)).join(", ", last: " & "), keywords: keywords, ) set page( paper: paper, margin: margin, numbering: pagenumbering, - columns: cols, - ) - set par(justify: true) + ) + + set par( + justify: true, + leading: linestretch * 0.65em + ) set text(lang: lang, region: region, font: font, size: fontsize) + + show math.equation: set text(font: mathfont) if mathfont != none + show raw: set text(font: codefont) if codefont != none + set heading(numbering: sectionnumbering) - place(top, float: true, scope: "parent", clearance: 4mm)[ - #if title != none { - align(center)[#block(inset: 2em)[ - #text(weight: "bold", size: 1.5em)[#title] - #(if subtitle != none { - parbreak() - text(weight: "bold", size: 1.25em)[#subtitle] - }) - ]] + show link: set text(fill: rgb(content-to-string(linkcolor))) if linkcolor != none + show ref: set text(fill: rgb(content-to-string(citecolor))) if citecolor != none + show link: this => { + if filecolor != none and type(this.dest) == label { + text(this, fill: rgb(content-to-string(filecolor))) + } } - #if authors != none and authors != [] { - let count = authors.len() - let ncols = calc.min(count, 3) - grid( - columns: (1fr,) * ncols, - row-gutter: 1.5em, - ..authors.map(author => - align(center)[ - #author.name \ - #author.affiliation \ - #author.email - ] + block(below: 4mm)[ + #if title != none { + align(center)[#block(inset: 2em)[ + #text(weight: "bold", size: 1.5em)[#title #if thanks != none { + footnote(thanks, numbering: "*") + counter(footnote).update(n => n - 1) + }] + #( + if subtitle != none { + parbreak() + text(weight: "bold", size: 1.25em)[#subtitle] + } + ) + ]] + } + + #if authors != none and authors != [] { + let count = authors.len() + let ncols = calc.min(count, 3) + grid( + columns: (1fr,) * ncols, + row-gutter: 1.5em, + ..authors.map(author => align(center)[ + #author.name \ + #author.affiliation \ + #author.email + ]) ) - ) - } + } - #if date != none { - align(center)[#block(inset: 1em)[ - #date - ]] - } + #if date != none { + align(center)[#block(inset: 1em)[ + #date + ]] + } - #if abstract != none { - block(inset: 2em)[ - #text(weight: "semibold")[Abstract] #h(1em) #abstract - ] - } + #if abstract != none { + block(inset: 2em)[ + #text(weight: "semibold")[#abstract-title] #h(1em) #abstract + ] + } ] doc @@ -122,6 +148,7 @@ email: "" ), ), date: [July 17, 2006], + abstract-title: [Abstract], pagenumbering: "1", cols: 1, doc, From c365732d493c84749980184bf9ec8ee4023e237c Mon Sep 17 00:00:00 2001 From: Ryan Gibb Date: Thu, 24 Jul 2025 21:40:08 +0100 Subject: [PATCH 45/54] Org reader: Recognize "fast access" characters in TODO state definitions (#10990) --- src/Text/Pandoc/Readers/Org/Meta.hs | 6 +++++- test/Tests/Readers/Org/Block/Header.hs | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Text/Pandoc/Readers/Org/Meta.hs b/src/Text/Pandoc/Readers/Org/Meta.hs index 6246947e48e1..8f19760bc8ab 100644 --- a/src/Text/Pandoc/Readers/Org/Meta.hs +++ b/src/Text/Pandoc/Readers/Org/Meta.hs @@ -252,7 +252,11 @@ todoSequence = try $ do where todoKeyword :: Monad m => OrgParser m Text - todoKeyword = many1Char nonspaceChar <* skipSpaces + todoKeyword = do + keyword <- many1Char nonspaceChar + let cleanKeyword = T.takeWhile (/= '(') keyword + skipSpaces + return cleanKeyword todoKeywords :: Monad m => OrgParser m [Text] todoKeywords = try $ diff --git a/test/Tests/Readers/Org/Block/Header.hs b/test/Tests/Readers/Org/Block/Header.hs index f0d77bc94daf..52396b90564b 100644 --- a/test/Tests/Readers/Org/Block/Header.hs +++ b/test/Tests/Readers/Org/Block/Header.hs @@ -118,6 +118,13 @@ tests = in headerWith ("compile", [], []) 1 (waiting <> space <> "compile") <> headerWith ("lunch", [], []) 1 (cancelled <> space <> "lunch") <> headerWith ("todo-feature", [], []) 1 (done <> space <> "todo-feature") + + , "Fast access TODO states" =: + T.unlines [ "#+TODO: TODO(t) | DONE(d)" + , "* TODO test" + ] =?> + let todoSpan = spanWith ("", ["todo", "TODO"], []) "TODO" + in headerWith ("test", [], []) 1 (todoSpan <> space <> "test") ] , "Tagged headers" =: From 53c3f88754da61fedc413e49c4d7cf0988e2fef8 Mon Sep 17 00:00:00 2001 From: Sean Soon Date: Thu, 24 Jul 2025 22:07:50 +0100 Subject: [PATCH 46/54] DocBook reader: Add rowspan support. (#10981) --- src/Text/Pandoc/Readers/DocBook.hs | 24 ++++-- test/docbook-reader.docbook | 33 ++++++++ test/docbook-reader.native | 122 +++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 8 deletions(-) diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs index 904be0fa4a5c..27703373de5c 100644 --- a/src/Text/Pandoc/Readers/DocBook.hs +++ b/src/Text/Pandoc/Readers/DocBook.hs @@ -53,6 +53,7 @@ import Text.TeXMath (readMathML, writeTeX) import qualified Data.Map as M import Text.Pandoc.XML.Light import Text.Pandoc.Walk (query) +import Text.Read (readMaybe) {- @@ -1060,9 +1061,8 @@ parseBlock (Elem e) = do cs -> mapMaybe (findAttr (unqual "colname" )) cs let isRow x = named "row" x || named "tr" x headrows <- case filterChild (named "thead") e' of - Just h -> case filterChild isRow h of - Just x -> parseRow colnames x - Nothing -> return [] + Just h -> mapM (parseRow colnames) + $ filterChildren isRow h Nothing -> return [] bodyrows <- case filterChild (named "tbody") e' of Just b -> mapM (parseRow colnames) @@ -1076,7 +1076,7 @@ parseBlock (Elem e) = do || x == '.') w if n > 0 then Just n else Nothing let numrows = maybe 0 maximum $ nonEmpty - $ map length bodyrows + $ map length (bodyrows ++ headrows) let aligns = case colspecs of [] -> replicate numrows AlignDefault cs -> map toAlignment cs @@ -1098,11 +1098,10 @@ parseBlock (Elem e) = do in ColWidth . scale <$> ws' Nothing -> replicate numrows ColWidthDefault let toRow = Row nullAttr - toHeaderRow l = [toRow l | not (null l)] return $ tableWith (elId,classes,attrs) (simpleCaption $ plain capt) (zip aligns widths) - (TableHead nullAttr $ toHeaderRow headrows) + (TableHead nullAttr $ map toRow headrows) [TableBody nullAttr 0 [] $ map toRow bodyrows] (TableFoot nullAttr []) sect n = sectWith(attrValue "id" e) [] [] n @@ -1180,7 +1179,7 @@ parseMixed container conts = do parseRow :: PandocMonad m => [Text] -> Element -> DB m [Cell] parseRow cn = do - let isEntry x = named "entry" x || named "td" x || named "th" x + let isEntry x = named "entry" x || named "td" x || named "th" x mapM (parseEntry cn) . filterChildren isEntry parseEntry :: PandocMonad m => [Text] -> Element -> DB m Cell @@ -1197,9 +1196,18 @@ parseEntry cn el = do case (mStrt, mEnd) of (Just start, Just end) -> colDistance start end _ -> 1 + let rowDistance mr = do + case readMaybe $ T.unpack mr :: Maybe Int of + Just moreRow -> RowSpan $ moreRow + 1 + _ -> 1 + let toRowSpan en = do + case findAttr (unqual "morerows") en of + Just moreRow -> rowDistance moreRow + _ -> 1 let colSpan = toColSpan el + let rowSpan = toRowSpan el let align = toAlignment el - (fmap (cell align 1 colSpan) . parseMixed plain . elContent) el + (fmap (cell align rowSpan colSpan) . parseMixed plain . elContent) el getInlines :: PandocMonad m => Element -> DB m Inlines getInlines e' = trimInlines . mconcat <$> diff --git a/test/docbook-reader.docbook b/test/docbook-reader.docbook index bd9fb8812c0e..076908583834 100644 --- a/test/docbook-reader.docbook +++ b/test/docbook-reader.docbook @@ -1661,6 +1661,39 @@ or here: <http://example.com/> + + Multiline table with cells spanning multiple columns and rows without caption. + + + + + + + +
Columns
ABC
A1 + B1C1 + C2
A2 + B2 + A3 + B3
C3
+
Attribute table caption @@ -1444,7 +1478,7 @@ or here: <http://example.com/> Table with attributes, without caption - +
diff --git a/test/docbook-reader.native b/test/docbook-reader.native index 13f5c49fcb7c..f46d60f4e4b9 100644 --- a/test/docbook-reader.native +++ b/test/docbook-reader.native @@ -62,39 +62,55 @@ Pandoc , Space , Str "suite." ] - , Header 1 ( "headers" , [] , [] ) [ Str "Headers" ] - , Header - 2 - ( "level-2-with-an-embedded-link" , [] , [] ) - [ Str "Level" - , Space - , Str "2" - , Space - , Str "with" - , Space - , Str "an" - , Space - , Link - ( "" , [] , [] ) - [ Str "embedded" , Space , Str "link" ] - ( "/url" , "" ) - ] - , Header - 3 - ( "level-3-with-emphasis" , [] , [] ) - [ Str "Level" - , Space - , Str "3" - , Space - , Str "with" - , Space - , Emph [ Str "emphasis" ] + , Div + ( "" + , [ "section" ] + , [ ( "role" , "sect1role" ) , ( "level" , "1" ) ] + ) + [ Header 1 ( "headers" , [] , [] ) [ Str "Headers" ] + , Div + ( "" + , [ "section" ] + , [ ( "role" , "sect2role" ) , ( "level" , "2" ) ] + ) + [ Header + 2 + ( "level-2-with-an-embedded-link" , [] , [] ) + [ Str "Level" + , Space + , Str "2" + , Space + , Str "with" + , Space + , Str "an" + , Space + , Link + ( "" , [] , [] ) + [ Str "embedded" , Space , Str "link" ] + ( "/url" , "" ) + ] + , Header + 3 + ( "level-3-with-emphasis" , [] , [] ) + [ Str "Level" + , Space + , Str "3" + , Space + , Str "with" + , Space + , Emph [ Str "emphasis" ] + ] + , Header + 4 + ( "level-4" , [] , [] ) + [ Str "Level" , Space , Str "4" ] + , Header + 5 + ( "level-5" , [] , [] ) + [ Str "Level" , Space , Str "5" ] + , Para [ Str "Hi." ] + ] ] - , Header - 4 ( "level-4" , [] , [] ) [ Str "Level" , Space , Str "4" ] - , Header - 5 ( "level-5" , [] , [] ) [ Str "Level" , Space , Str "5" ] - , Para [ Str "Hi." ] , Header 1 ( "level-1" , [] , [] ) [ Str "Level" , Space , Str "1" ] , Header @@ -151,6 +167,29 @@ Pandoc , Space , Str "paragraph." ] + , Div + ( "" + , [] + , [ ( "wrapper" , "1" ) , ( "role" , "pararole" ) ] + ) + [ Para + [ Str "And" + , Space + , Str "here\8217s" + , Space + , Str "a" + , Space + , Str "regular" + , Space + , Str "paragraph" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "role." + ] + ] , Para [ Str "In" , Space @@ -251,6 +290,31 @@ Pandoc , Str "short." ] ] + , Div + ( "" + , [] + , [ ( "wrapper" , "1" ) , ( "role" , "roleblockquote" ) ] + ) + [ BlockQuote + [ Para + [ Str "This" + , Space + , Str "is" + , Space + , Str "a" + , Space + , Str "block" + , Space + , Str "quote" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "role." + ] + ] + ] , BlockQuote [ Para [ Str "Code" @@ -348,6 +412,19 @@ Pandoc , [ Para [ Str "Second" ] ] , [ Para [ Str "Third" ] ] ] + , Para [ Str "with" , Space , Str "role:" ] + , Div + ( "" + , [] + , [ ( "wrapper" , "1" ) , ( "role" , "listrole" ) ] + ) + [ OrderedList + ( 1 , Decimal , DefaultDelim ) + [ [ Para [ Str "First" ] ] + , [ Para [ Str "Second" ] ] + , [ Para [ Str "Third" ] ] + ] + ] , Para [ Str "and" , Space , Str "tight:" ] , OrderedList ( 1 , Decimal , DefaultDelim ) @@ -931,6 +1008,38 @@ Pandoc , Space , Str "word." ] + , Para + [ Str "So" + , Space + , Str "is" + , Space + , Emph [ Emph [ Str "this" ] ] + , Space + , Str "word" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "role." + ] + , Para + [ Str "So" + , Space + , Str "is" + , Space + , Span + ( "" , [ "phraserole" ] , [ ( "role" , "phraserole" ) ] ) + [ Str "this" ] + , Space + , Str "phrase" + , Space + , Str "with" + , Space + , Str "a" + , Space + , Str "role." + ] , Para [ Str "This" , Space @@ -2570,7 +2679,9 @@ Pandoc , Table ( "mytableid1" , [ "mytableclass1" , "mytableclass2" ] - , [ ( "custom-style" , "mytabstyle1" ) ] + , [ ( "role" , "tablerole1" ) + , ( "custom-style" , "mytabstyle1" ) + ] ) (Caption Nothing @@ -2636,7 +2747,9 @@ Pandoc , Table ( "mytableid2" , [ "mytableclass3" , "mytableclass4" ] - , [ ( "custom-style" , "mytabstyle2" ) ] + , [ ( "role" , "tablerole2" ) + , ( "custom-style" , "mytabstyle2" ) + ] ) (Caption Nothing []) [ ( AlignDefault , ColWidthDefault )