From 381b82e4a36e6fc6ec92cecabd7a652e79bc33f6 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 9 Apr 2026 21:11:13 +0000 Subject: [PATCH] Docx writer: fix FirstParagraph style lost after heading with footnote. When a heading contained a footnote, processing the footnote's block content would consume the stFirstPara flag, causing the following paragraph to incorrectly receive BodyText style instead of FirstParagraph. Fix by saving and restoring stFirstPara around footnote block processing. Closes #11573. Co-Authored-By: Claude --- src/Text/Pandoc/Writers/Docx/OpenXML.hs | 2 ++ test/Tests/Writers/Docx.hs | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/Text/Pandoc/Writers/Docx/OpenXML.hs b/src/Text/Pandoc/Writers/Docx/OpenXML.hs index 5490a732d..044367c64 100644 --- a/src/Text/Pandoc/Writers/Docx/OpenXML.hs +++ b/src/Text/Pandoc/Writers/Docx/OpenXML.hs @@ -907,6 +907,7 @@ inlineToOpenXML' opts (Code attrs str) = do inlineToOpenXML' opts (Note bs) = do notes <- gets stFootnotes notenum <- getUniqueId + oldFirstPara <- gets stFirstPara footnoteStyle <- rStyleM "Footnote Reference" let notemarker = mknode "w:r" [] [ mknode "w:rPr" [] footnoteStyle @@ -922,6 +923,7 @@ inlineToOpenXML' opts (Note bs) = do , envInNote = True }) (withParaPropM (pStyleM "Footnote Text") $ blocksToOpenXML opts $ insertNoteRef bs) + modify $ \s -> s{ stFirstPara = oldFirstPara } let newnote = mknode "w:footnote" [("w:id", notenum)] contents modify $ \s -> s{ stFootnotes = newnote : notes } return [ Elem $ mknode "w:r" [] diff --git a/test/Tests/Writers/Docx.hs b/test/Tests/Writers/Docx.hs index dcc44a93a..c4bad66e7 100644 --- a/test/Tests/Writers/Docx.hs +++ b/test/Tests/Writers/Docx.hs @@ -353,4 +353,25 @@ tests = [ testGroup "inlines" assertBool "Language from metadata did not override reference docx (expected fr-FR)" (any ("fr-FR" `isInfixOf`) (getLangLines stylesXml)) ] + , testGroup "paragraph styles" + [ testCase "FirstParagraph after heading with footnote (#11573)" $ do + let opts = def + bs <- runIOorExplode $ do + setVerbosity ERROR + let doc = Pandoc mempty + [ Header 3 ("heading-with-note", [], []) + [Note [Para [Str "note"]], Str "Heading"] + , Para [Str "Para", Space, Str "after."] + ] + writeDocx opts doc + let archive = toArchive bs + entry <- case findEntryByPath "word/document.xml" archive of + Nothing -> assertFailure "Missing word/document.xml in output docx" + Just e -> return e + let docXml = show (fromEntry entry) + assertBool + ("Expected FirstParagraph style after heading with footnote, got: " + ++ docXml) + ("FirstParagraph" `isInfixOf` docXml) + ] ]