diff --git a/filter/Configuration_filter.mk b/filter/Configuration_filter.mk
index 42ebab575cd3..dbe04df3f7ba 100644
--- a/filter/Configuration_filter.mk
+++ b/filter/Configuration_filter.mk
@@ -361,6 +361,7 @@ $(eval $(call filter_Configuration_add_types,fcfg_langpack,fcfg_writer_types.xcu
StarOffice_Writer \
writer_EPUB_Document \
writer_PocketWord_File \
+ generic_Markdown \
))
$(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_writer_filters.xcu,filter/source/config/fragments/filters,\
@@ -411,6 +412,7 @@ $(eval $(call filter_Configuration_add_filters,fcfg_langpack,fcfg_writer_filters
StarOffice_Writer \
EPUB \
PocketWord_File \
+ Markdown \
))
# fcfg_web
diff --git a/filter/source/config/fragments/filters/Markdown.xcu b/filter/source/config/fragments/filters/Markdown.xcu
new file mode 100644
index 000000000000..33ce9369d9ac
--- /dev/null
+++ b/filter/source/config/fragments/filters/Markdown.xcu
@@ -0,0 +1,21 @@
+
+
+ EXPORT ALIEN
+
+
+ Markdown
+ 0
+ generic_Markdown
+
+ com.sun.star.text.TextDocument
+
+ Markdown Document
+
+
diff --git a/filter/source/config/fragments/types/generic_Markdown.xcu b/filter/source/config/fragments/types/generic_Markdown.xcu
new file mode 100644
index 000000000000..b6ad050f1066
--- /dev/null
+++ b/filter/source/config/fragments/types/generic_Markdown.xcu
@@ -0,0 +1,18 @@
+
+
+ com.sun.star.comp.filters.PlainTextFilterDetect
+
+ md
+ text/markdown
+ false
+
+ Markdown Document
+
+
diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index 7b4fc359997a..cfa4a2e9ee45 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -557,6 +557,7 @@ certain functionality.
@li @c sw.layout - Writer core view: document layout
@li @c sw.layout.debug - Writer layout dbg_lay output
@li @c sw.mailmerge - Writer mail merge
+@li @c sw.md - Markdown export filter
@li @c sw.pageframe - debug lifecycle of SwPageFrame
@li @c sw.qa
@li @c sw.rtf - .rtf export filter
diff --git a/officecfg/registry/schema/org/openoffice/Office/Writer.xcs b/officecfg/registry/schema/org/openoffice/Office/Writer.xcs
index 1acc49a8c739..8fe6aa00847b 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Writer.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Writer.xcs
@@ -6238,6 +6238,17 @@
true
+
+
+ Contains settings for the Markdown filter.
+
+
+
+ Whether hidden text (sections, etc) is included in the output.
+
+ false
+
+
diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk
index b007b90de126..6aecbaf797d9 100644
--- a/sw/Library_sw.mk
+++ b/sw/Library_sw.mk
@@ -567,6 +567,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
sw/source/filter/html/svxcss1 \
sw/source/filter/html/swhtml \
sw/source/filter/html/wrthtml \
+ sw/source/filter/md/wrtmd \
sw/source/filter/writer/writer \
sw/source/filter/writer/wrt_fn \
sw/source/filter/writer/wrtswtbl \
diff --git a/sw/inc/iodetect.hxx b/sw/inc/iodetect.hxx
index cb47a7b7f3b2..1ab043a6cffc 100644
--- a/sw/inc/iodetect.hxx
+++ b/sw/inc/iodetect.hxx
@@ -39,6 +39,7 @@ inline constexpr OUString FILTER_XML = u"CXML"_ustr; ///< XML filter
#define FILTER_XMLV "CXMLV" ///< XML filter
#define FILTER_XMLVW "CXMLVWEB" ///< XML filter
inline constexpr OUString FILTER_DOCX = u"OXML"_ustr;
+inline constexpr OUString FILTER_MD = u"Markdown"_ustr; // markdown filter
inline constexpr OUString sHTML = u"HTML"_ustr;
inline constexpr OUString sWW5 = u"WW6"_ustr;
inline constexpr OUString sWW6 = u"CWW6"_ustr;
@@ -80,6 +81,7 @@ enum ReaderWriterEnum {
READER_WRITER_TEXT_DLG,
READER_WRITER_TEXT,
READER_WRITER_DOCX,
+ READER_WRITER_MD,
MAXFILTER
};
diff --git a/sw/inc/shellio.hxx b/sw/inc/shellio.hxx
index a0c3b2eb32ea..f82ac9301da5 100644
--- a/sw/inc/shellio.hxx
+++ b/sw/inc/shellio.hxx
@@ -575,6 +575,7 @@ void GetRTFWriter( std::u16string_view, const OUString&, WriterRef& );
void GetASCWriter( std::u16string_view, const OUString&, WriterRef&);
void GetHTMLWriter( std::u16string_view, const OUString&, WriterRef& );
void GetXMLWriter( std::u16string_view, const OUString&, WriterRef& );
+void GetMDWriter(std::u16string_view, const OUString&, WriterRef&);
#endif
diff --git a/sw/source/filter/basflt/fltini.cxx b/sw/source/filter/basflt/fltini.cxx
index 260a88134d24..80189e8e707f 100644
--- a/sw/source/filter/basflt/fltini.cxx
+++ b/sw/source/filter/basflt/fltini.cxx
@@ -63,7 +63,8 @@ static SwReaderWriterEntry aReaderWriter[] =
SwReaderWriterEntry( nullptr, &::GetXMLWriter, true ),
SwReaderWriterEntry( nullptr, &::GetASCWriter, false ),
SwReaderWriterEntry( nullptr, &::GetASCWriter, true ),
- SwReaderWriterEntry( &::GetDOCXReader, nullptr, true )
+ SwReaderWriterEntry( &::GetDOCXReader, nullptr, true ),
+ SwReaderWriterEntry(nullptr, &GetMDWriter, false),
};
Reader* SwReaderWriterEntry::GetReader()
diff --git a/sw/source/filter/basflt/iodetect.cxx b/sw/source/filter/basflt/iodetect.cxx
index ac857a806b55..144bc1c86bb0 100644
--- a/sw/source/filter/basflt/iodetect.cxx
+++ b/sw/source/filter/basflt/iodetect.cxx
@@ -49,7 +49,8 @@ SwIoDetect aFilterDetect[] =
SwIoDetect( FILTER_XML ),
SwIoDetect( FILTER_TEXT_DLG ),
SwIoDetect( FILTER_TEXT ),
- SwIoDetect( FILTER_DOCX )
+ SwIoDetect( FILTER_DOCX ),
+ SwIoDetect( FILTER_MD ),
};
OUString SwIoSystem::GetSubStorageName( const SfxFilter& rFltr )
diff --git a/sw/source/filter/md/wrtmd.cxx b/sw/source/filter/md/wrtmd.cxx
new file mode 100644
index 000000000000..8124a1100fac
--- /dev/null
+++ b/sw/source/filter/md/wrtmd.cxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include "wrtmd.hxx"
+
+namespace
+{
+/* Output of the nodes*/
+void OutMarkdown_SwTextNode(SwMDWriter& /*rWrt*/, const SwTextNode& /*rNode*/) {}
+}
+
+SwMDWriter::SwMDWriter(const OUString& rBaseURL) { SetBaseURL(rBaseURL); }
+
+ErrCode SwMDWriter::WriteStream()
+{
+ if (m_bShowProgress)
+ ::StartProgress(STR_STATSTR_W4WWRITE, 0, sal_Int32(m_pDoc->GetNodes().Count()),
+ m_pDoc->GetDocShell());
+
+ // respect table and section at document beginning
+ {
+ if (m_bWriteAll)
+ {
+ while (const SwStartNode* pTNd = m_pCurrentPam->GetPointNode().FindTableBoxStartNode())
+ {
+ // start with table node !!
+ m_pCurrentPam->GetPoint()->Assign(*pTNd->FindTableNode());
+
+ if (m_bWriteOnlyFirstTable)
+ m_pCurrentPam->GetMark()->Assign(
+ *m_pCurrentPam->GetPointNode().EndOfSectionNode());
+ }
+ }
+
+ // first node (which can contain a page break)
+ m_nStartNodeIndex = m_pCurrentPam->GetPoint()->GetNode().GetIndex();
+
+ for (SwSectionNode* pSNd = m_pCurrentPam->GetPointNode().FindSectionNode(); pSNd;
+ pSNd = pSNd->StartOfSectionNode()->FindSectionNode())
+ {
+ if (m_bWriteAll)
+ {
+ // start with section node !!
+ m_pCurrentPam->GetPoint()->Assign(*pSNd);
+ }
+ }
+ }
+
+ Out_SwDoc(m_pOrigPam);
+
+ if (m_bShowProgress)
+ ::EndProgress(m_pDoc->GetDocShell());
+ return ERRCODE_NONE;
+}
+
+void SwMDWriter::Out_SwDoc(SwPaM* pPam)
+{
+ bool bSaveWriteAll = m_bWriteAll;
+ bool bIncludeHidden
+ = officecfg::Office::Writer::FilterFlags::Markdown::IncludeHiddenText::get();
+ bool bFirstLine = true;
+
+ do
+ {
+ m_bWriteAll = bSaveWriteAll;
+
+ while (*m_pCurrentPam->GetPoint() <= *m_pCurrentPam->GetMark())
+ {
+ SwNode& rNd = m_pCurrentPam->GetPointNode();
+
+ SAL_WARN_IF(rNd.IsGrfNode() || rNd.IsOLENode(), "sw.md",
+ "Unexpected Grf- or OLE-Node here");
+
+ if (SwTextNode* pTextNd = rNd.GetTextNode())
+ {
+ if (bIncludeHidden || !pTextNd->IsHidden())
+ {
+ if (!bFirstLine)
+ m_pCurrentPam->GetPoint()->SetContent(0);
+
+ OutMarkdown_SwTextNode(*this, *pTextNd);
+ }
+ }
+ else if (rNd.IsTableNode())
+ {
+ // TODO
+ }
+ else if (rNd.IsSectionNode())
+ {
+ SwSectionNode* pSectionNode = rNd.GetSectionNode();
+ if (!pSectionNode->GetSection().IsHiddenFlag() || bIncludeHidden)
+ {
+ // TODO
+ }
+ }
+ else if (&rNd == &m_pDoc->GetNodes().GetEndOfContent())
+ break;
+
+ m_pCurrentPam->GetPoint()->Adjust(SwNodeOffset(+1)); // move
+ SwNodeOffset nPos = m_pCurrentPam->GetPoint()->GetNodeIndex();
+
+ if (m_bShowProgress)
+ ::SetProgressState(sal_Int32(nPos), m_pDoc->GetDocShell()); // How far ?
+
+ /* If only the selected area should be saved, so only the complete
+ * nodes should be saved, this means the first and n-th node
+ * partly, the 2nd till n-1 node complete. (complete means with
+ * all formats!)
+ */
+ m_bWriteAll = bSaveWriteAll || nPos != m_pCurrentPam->GetMark()->GetNodeIndex();
+ bFirstLine = false;
+ }
+ } while (CopyNextPam(&pPam)); // until all PaM's processed
+
+ m_bWriteAll = bSaveWriteAll; // reset to old values
+}
+
+void GetMDWriter(std::u16string_view /*rFilterOptions*/, const OUString& rBaseURL, WriterRef& xRet)
+{
+ xRet = new SwMDWriter(rBaseURL);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sw/source/filter/md/wrtmd.hxx b/sw/source/filter/md/wrtmd.hxx
new file mode 100644
index 000000000000..6b26135ea5a5
--- /dev/null
+++ b/sw/source/filter/md/wrtmd.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include
+
+#include
+
+#include
+#include
+
+class SwMDWriter : public Writer
+{
+public:
+ SW_DLLPUBLIC explicit SwMDWriter(const OUString& rBaseURL);
+
+ bool isInTable() const { return m_bOutTable; }
+ SwNodeOffset StartNodeIndex() const { return m_nStartNodeIndex; }
+
+protected:
+ ErrCode WriteStream() override;
+
+private:
+ void Out_SwDoc(SwPaM* pPam);
+
+ bool m_bOutTable = false;
+ SwNodeOffset m_nStartNodeIndex{ 0 };
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */