diff options
6 files changed, 80 insertions, 20 deletions
diff --git a/src/gui/text/qtextmarkdownwriter.cpp b/src/gui/text/qtextmarkdownwriter.cpp index c8a5d40b52..5d6c673179 100644 --- a/src/gui/text/qtextmarkdownwriter.cpp +++ b/src/gui/text/qtextmarkdownwriter.cpp @@ -125,17 +125,22 @@ void QTextMarkdownWriter::writeFrame(const QTextFrame *frame) // suppress needless blank lines, when there will be a big change in block format bool nextIsDifferent = false; bool ending = false; + int blockQuoteIndent = 0; + int nextBlockQuoteIndent = 0; { QTextFrame::iterator next = iterator; ++next; + QTextBlockFormat format = iterator.currentBlock().blockFormat(); + QTextBlockFormat nextFormat = next.currentBlock().blockFormat(); + blockQuoteIndent = format.intProperty(QTextFormat::BlockQuoteLevel); + nextBlockQuoteIndent = nextFormat.intProperty(QTextFormat::BlockQuoteLevel); if (next.atEnd()) { nextIsDifferent = true; ending = true; } else { - QTextBlockFormat format = iterator.currentBlock().blockFormat(); - QTextBlockFormat nextFormat = next.currentBlock().blockFormat(); if (nextFormat.indent() != format.indent() || - nextFormat.property(QTextFormat::BlockCodeLanguage) != format.property(QTextFormat::BlockCodeLanguage)) + nextFormat.property(QTextFormat::BlockCodeLanguage) != + format.property(QTextFormat::BlockCodeLanguage)) nextIsDifferent = true; } } @@ -152,8 +157,10 @@ void QTextMarkdownWriter::writeFrame(const QTextFrame *frame) tableRow = cell.row(); } } else if (!block.textList()) { - if (lastWasList) + if (lastWasList) { m_stream << qtmw_Newline; + m_linePrefixWritten = false; + } } int endingCol = writeBlock(block, !table, table && tableRow == 0, nextIsDifferent && !block.textList()); @@ -177,8 +184,16 @@ void QTextMarkdownWriter::writeFrame(const QTextFrame *frame) } else if (endingCol > 0) { if (block.textList() || block.blockFormat().hasProperty(QTextFormat::BlockCodeLanguage)) { m_stream << qtmw_Newline; + if (block.textList()) { + m_stream << m_linePrefix; + m_linePrefixWritten = true; + } } else { - m_stream << qtmw_Newline << qtmw_Newline; + m_stream << qtmw_Newline; + if (nextBlockQuoteIndent < blockQuoteIndent) + setLinePrefixForBlockQuote(nextBlockQuoteIndent); + m_stream << m_linePrefix; + m_stream << qtmw_Newline; m_doubleNewlineWritten = true; } } @@ -224,6 +239,16 @@ QTextMarkdownWriter::ListInfo QTextMarkdownWriter::listInfo(QTextList *list) return m_listInfo.value(list); } +void QTextMarkdownWriter::setLinePrefixForBlockQuote(int level) +{ + m_linePrefix.clear(); + if (level > 0) { + m_linePrefix.reserve(level * 2); + for (int i = 0; i < level; ++i) + m_linePrefix += u"> "; + } +} + static int nearestWordWrapIndex(const QString &s, int before) { before = qMin(before, s.size()); @@ -349,10 +374,20 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign const bool codeBlock = blockFmt.hasProperty(QTextFormat::BlockCodeFence) || blockFmt.stringProperty(QTextFormat::BlockCodeLanguage).size() > 0 || blockFmt.nonBreakableLines(); + const int blockQuoteLevel = blockFmt.intProperty(QTextFormat::BlockQuoteLevel); if (m_fencedCodeBlock && !codeBlock) { m_stream << m_linePrefix << m_codeBlockFence << qtmw_Newline; m_fencedCodeBlock = false; m_codeBlockFence.clear(); + m_linePrefixWritten = m_linePrefix.size() > 0; + } + m_linePrefix.clear(); + if (!blockFmt.headingLevel() && blockQuoteLevel > 0) { + setLinePrefixForBlockQuote(blockQuoteLevel); + if (!m_linePrefixWritten) { + m_stream << m_linePrefix; + m_linePrefixWritten = true; + } } if (block.textList()) { // it's a list-item auto fmt = block.textList()->format(); @@ -429,31 +464,25 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign if (blockFmt.hasProperty(QTextFormat::BlockIndent)) m_codeBlockFence = QString(m_wrappedLineIndent, qtmw_Space) + m_codeBlockFence; // A block quote can contain an indented code block, but not vice-versa. - m_stream << m_linePrefix << m_codeBlockFence - << blockFmt.stringProperty(QTextFormat::BlockCodeLanguage) << qtmw_Newline; + m_stream << m_codeBlockFence << blockFmt.stringProperty(QTextFormat::BlockCodeLanguage) + << qtmw_Newline << m_linePrefix; m_fencedCodeBlock = true; } wrap = false; } else if (!blockFmt.indent()) { m_wrappedLineIndent = 0; - m_linePrefix.clear(); - if (blockFmt.hasProperty(QTextFormat::BlockQuoteLevel)) { - int level = blockFmt.intProperty(QTextFormat::BlockQuoteLevel); - QString quoteMarker = QStringLiteral("> "); - m_linePrefix.reserve(level * 2); - for (int i = 0; i < level; ++i) - m_linePrefix += quoteMarker; - } if (blockFmt.hasProperty(QTextFormat::BlockCodeLanguage)) { // A block quote can contain an indented code block, but not vice-versa. m_linePrefix += QString(4, qtmw_Space); m_indentedCodeBlock = true; } + if (!m_linePrefixWritten) { + m_stream << m_linePrefix; + m_linePrefixWritten = true; + } } if (blockFmt.headingLevel()) m_stream << QByteArray(blockFmt.headingLevel(), '#') << ' '; - else - m_stream << m_linePrefix; QString wrapIndentString = m_linePrefix + QString(m_wrappedLineIndent, qtmw_Space); // It would be convenient if QTextStream had a lineCharPos() accessor, @@ -597,6 +626,10 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign i = j + 1; } } else { + if (!m_linePrefixWritten && col == wrapIndentString.size()) { + m_stream << m_linePrefix; + col += m_linePrefix.size(); + } m_stream << markers << fragmentText; col += markers.size() + fragmentText.size(); } @@ -628,6 +661,7 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign } if (missedBlankCodeBlockLine) m_stream << qtmw_Newline; + m_linePrefixWritten = false; return col; } diff --git a/src/gui/text/qtextmarkdownwriter_p.h b/src/gui/text/qtextmarkdownwriter_p.h index 21cfeaba39..c0989b8f72 100644 --- a/src/gui/text/qtextmarkdownwriter_p.h +++ b/src/gui/text/qtextmarkdownwriter_p.h @@ -44,6 +44,7 @@ private: }; ListInfo listInfo(QTextList *list); + void setLinePrefixForBlockQuote(int level); private: QTextStream &m_stream; @@ -54,6 +55,7 @@ private: int m_wrappedLineIndent = 0; int m_lastListIndent = 1; bool m_doubleNewlineWritten = false; + bool m_linePrefixWritten = false; bool m_indentedCodeBlock = false; bool m_fencedCodeBlock = false; }; diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md index a021f15aba..8e605ef7e6 100644 --- a/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md @@ -8,17 +8,17 @@ MacFarlane writes: > What distinguishes Markdown from many other lightweight markup syntaxes, > which are often easier to write, is its readability. As Gruber writes: - +> > > The overriding design goal for Markdown's formatting syntax is to make it > > as readable as possible. The idea is that a Markdown-formatted document should > > be publishable as-is, as plain text, without looking like it's been marked up > > with tags or formatting instructions. ( > > <http://daringfireball.net/projects/markdown/> ) - +> > The point can be illustrated by comparing a sample of AsciiDoc with an > equivalent sample of Markdown. Here is a sample of AsciiDoc from the AsciiDoc > manual: - +> > ```AsciiDoc > 1. List item one. > + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotesWithLists.md b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotesWithLists.md new file mode 100644 index 0000000000..1728889adc --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotesWithLists.md @@ -0,0 +1,14 @@ +What if we have a quotation containing a list? + +> First some quoted text, and then a list: +> +> - one +> - two is longer and has enough words to form a paragraph with text continuing +> onto the next line +> +> enough of that, let's try a numbered list +> +> 1. List item one +> 2. List item two is longer and has enough words to form a paragraph with +> text continuing onto the next line. +>
\ No newline at end of file diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/listItemWithBlockquote.md b/tests/auto/gui/text/qtextmarkdownwriter/data/listItemWithBlockquote.md new file mode 100644 index 0000000000..c417125fea --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/listItemWithBlockquote.md @@ -0,0 +1,6 @@ +What if we have a list item containing a block quote? + +- one +- > two is longer and has enough words to form a paragraph with text continuing + > onto the next line + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp index ce21ff730b..03c0fa0adc 100644 --- a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp +++ b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp @@ -544,6 +544,8 @@ void tst_QTextMarkdownWriter::rewriteDocument_data() QTest::addColumn<QString>("inputFile"); QTest::newRow("block quotes") << "blockquotes.md"; + QTest::newRow("block quotes with lists") << "blockquotesWithLists.md"; + // QTest::newRow("list item with block quote") << "listItemWithBlockquote.md"; // not supported for now QTest::newRow("example") << "example.md"; QTest::newRow("list items after headings") << "headingsAndLists.md"; QTest::newRow("word wrap") << "wordWrap.md"; @@ -644,6 +646,8 @@ void tst_QTextMarkdownWriter::fromHtml() } #endif + output = output.trimmed(); + expectedOutput = expectedOutput.trimmed(); if (output != expectedOutput && (isMainFontFixed() || isFixedFontProportional())) QEXPECT_FAIL("", "fixed main font or proportional fixed font (QTBUG-103484)", Continue); QCOMPARE(output, expectedOutput); |