sw/qa/filter/md/data/quote.md |    5 ++++
 sw/qa/filter/md/md.cxx        |   51 ++++++++++++++++++++++++++++++++++++++++++
 sw/source/filter/md/swmd.cxx  |    7 +----
 sw/source/filter/md/wrtmd.cxx |    7 +++++
 4 files changed, 65 insertions(+), 5 deletions(-)

New commits:
commit c94b0c7ace10f5913aa53b593aa0ccd544df3cc3
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Sep 8 08:43:23 2025 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Sep 8 12:02:42 2025 +0200

    sw markdown export: handle block quote
    
    <https://spec.commonmark.org/0.31.2/#example-228> says the quote block
    markup should be written first, then the heading, so do it in that
    order.
    
    Also fix the import side: set the paragraph style in
    SwMarkdownParser::AddBlockQuote(), similar to how
    HtmlTokenId::BLOCKQUOTE_ON is handled in SwHTMLParser::NextToken(), so
    the export side has an easier time with recognizing this is a block
    quote.
    
    Change-Id: I305c7a31832cba44cb66943a5fc45a966ad62d55
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190656
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/filter/md/data/quote.md b/sw/qa/filter/md/data/quote.md
new file mode 100644
index 000000000000..9d3f8dd0fada
--- /dev/null
+++ b/sw/qa/filter/md/data/quote.md
@@ -0,0 +1,5 @@
+before
+
+> quote
+
+after
diff --git a/sw/qa/filter/md/md.cxx b/sw/qa/filter/md/md.cxx
index 1bbbad212a5b..61f993a403d2 100644
--- a/sw/qa/filter/md/md.cxx
+++ b/sw/qa/filter/md/md.cxx
@@ -24,6 +24,7 @@
 #include <fmtcntnt.hxx>
 #include <ndgrf.hxx>
 #include <itabenum.hxx>
+#include <ndtxt.hxx>
 
 namespace
 {
@@ -367,6 +368,56 @@ CPPUNIT_TEST_FIXTURE(Test, testExportingTable)
     CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testBlockQuoteMdImport)
+{
+    // Given a document with a "block quote" 2nd paragraph:
+    // When importing that document:
+    setImportFilterName("Markdown");
+    createSwDoc("quote.md");
+
+    // Then make sure that the paragraph style is set correctly:
+    SwDocShell* pDocShell = getSwDocShell();
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+    pWrtShell->Down(/*bSelect=*/false);
+    SwCursor* pCursor = pWrtShell->GetCursor();
+    SwTextNode* pTextNode = pCursor->GetPointNode().GetTextNode();
+    SwFormatColl* pActual = pTextNode->GetFormatColl();
+    SwDoc* pDoc = pDocShell->GetDoc();
+    IDocumentStylePoolAccess& rIDSPA = pDoc->getIDocumentStylePoolAccess();
+    SwFormatColl* pExpected = 
rIDSPA.GetTextCollFromPool(RES_POOLCOLL_HTML_BLOCKQUOTE);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: Block Quotation
+    // - Actual  : Body Text
+    // i.e. the paragraph style was not set.
+    CPPUNIT_ASSERT_EQUAL(pExpected->GetName().toString(), 
pActual->GetName().toString());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testBlockQuoteMdExport)
+{
+    // Given a document where the only paragraph is a block quote:
+    createSwDoc();
+    SwDocShell* pDocShell = getSwDocShell();
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+    SwCursor* pCursor = pWrtShell->GetCursor();
+    SwDoc* pDoc = pDocShell->GetDoc();
+    IDocumentStylePoolAccess& rIDSPA = pDoc->getIDocumentStylePoolAccess();
+    SwTextFormatColl* pColl = 
rIDSPA.GetTextCollFromPool(RES_POOLCOLL_HTML_BLOCKQUOTE);
+    pDoc->SetTextFormatColl(*pCursor, pColl);
+    pWrtShell->Insert(u"test"_ustr);
+
+    // When saving that to markdown:
+    save(mpFilter);
+
+    // Then make sure the format of the paragraph is exported:
+    std::string aActual = TempFileToString();
+    std::string aExpected("> test" SAL_NEWLINE_STRING);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: > test
+    // - Actual  : test
+    // i.e. the block quote markup was missing.
+    CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sw/source/filter/md/swmd.cxx b/sw/source/filter/md/swmd.cxx
index 3ccdb1cff3ce..cf687d3a9ea6 100644
--- a/sw/source/filter/md/swmd.cxx
+++ b/sw/source/filter/md/swmd.cxx
@@ -208,11 +208,8 @@ void SwMarkdownParser::AddBlockQuote()
 
     m_nBlockQuoteDepth++;
 
-    sal_Int32 nBaseLeftIndent = pColl->GetTextLeftMargin().ResolveTextLeft({});
-    sal_Int32 nLeftIndent = nBaseLeftIndent + m_nBlockQuoteDepth * 
nBaseLeftIndent;
-    SvxTextLeftMarginItem aLeftMargin(pColl->GetTextLeftMargin());
-    aLeftMargin.SetTextLeft(SvxIndentValue::twips(nLeftIndent));
-    m_xDoc->getIDocumentContentOperations().InsertPoolItem(*m_pPam, 
aLeftMargin);
+    // Set the style on the current paragraph.
+    m_xDoc->SetTextFormatColl(*m_pPam, pColl);
 }
 
 void SwMarkdownParser::EndBlockQuote()
diff --git a/sw/source/filter/md/wrtmd.cxx b/sw/source/filter/md/wrtmd.cxx
index a1b4dc8c98ec..ebe2aadb7966 100644
--- a/sw/source/filter/md/wrtmd.cxx
+++ b/sw/source/filter/md/wrtmd.cxx
@@ -475,6 +475,13 @@ void OutMarkdown_SwTextNode(SwMDWriter& rWrt, const 
SwTextNode& rNode, bool bFir
         if (!bFirst && !oCellInfo)
             rWrt.Strm().WriteUnicodeOrByteText(u"" SAL_NEWLINE_STRING);
 
+        const SwFormatColl* pFormatColl = rNode.GetFormatColl();
+        if (pFormatColl->GetPoolFormatId() == RES_POOLCOLL_HTML_BLOCKQUOTE)
+        {
+            // <https://spec.commonmark.org/0.31.2/#block-quotes> first block 
quote, then heading.
+            rWrt.Strm().WriteUnicodeOrByteText(u"> ");
+        }
+
         int nHeadingLevel = 0;
         for (const SwFormat* pFormat = &rNode.GetAnyFormatColl(); pFormat;
              pFormat = pFormat->DerivedFrom())

Reply via email to