diff options
Diffstat (limited to 'src/gui/text/qtextmarkdownimporter.cpp')
-rw-r--r-- | src/gui/text/qtextmarkdownimporter.cpp | 248 |
1 files changed, 131 insertions, 117 deletions
diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp index 97bdef50d7..e7fcad67b5 100644 --- a/src/gui/text/qtextmarkdownimporter.cpp +++ b/src/gui/text/qtextmarkdownimporter.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qtextmarkdownimporter_p.h" #include "qtextdocumentfragment_p.h" @@ -48,17 +12,26 @@ #include <QTextDocumentFragment> #include <QTextList> #include <QTextTable> +#if QT_CONFIG(system_textmarkdownreader) +#include <md4c.h> +#else #include "../../3rdparty/md4c/md4c.h" +#endif QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + Q_LOGGING_CATEGORY(lcMD, "qt.text.markdown") -static const QChar Newline = QLatin1Char('\n'); -static const QChar Space = QLatin1Char(' '); +static const QChar qtmi_Newline = u'\n'; +static const QChar qtmi_Space = u' '; + +static constexpr auto markerString() noexcept { return "---"_L1; } // TODO maybe eliminate the margins after all views recognize BlockQuoteLevel, CSS can format it, etc. -static const int BlockQuoteIndent = 40; // pixels, same as in QTextHtmlParserNode::initializeProperties +static const int qtmi_BlockQuoteIndent = + 40; // pixels, same as in QTextHtmlParserNode::initializeProperties static_assert(int(QTextMarkdownImporter::FeatureCollapseWhitespace) == MD_FLAG_COLLAPSEWHITESPACE); static_assert(int(QTextMarkdownImporter::FeaturePermissiveATXHeaders) == MD_FLAG_PERMISSIVEATXHEADERS); @@ -69,12 +42,14 @@ static_assert(int(QTextMarkdownImporter::FeatureNoHTMLBlocks) == MD_FLAG_NOHTMLB static_assert(int(QTextMarkdownImporter::FeatureNoHTMLSpans) == MD_FLAG_NOHTMLSPANS); static_assert(int(QTextMarkdownImporter::FeatureTables) == MD_FLAG_TABLES); static_assert(int(QTextMarkdownImporter::FeatureStrikeThrough) == MD_FLAG_STRIKETHROUGH); +static_assert(int(QTextMarkdownImporter::FeatureUnderline) == MD_FLAG_UNDERLINE); static_assert(int(QTextMarkdownImporter::FeaturePermissiveWWWAutoLinks) == MD_FLAG_PERMISSIVEWWWAUTOLINKS); static_assert(int(QTextMarkdownImporter::FeaturePermissiveAutoLinks) == MD_FLAG_PERMISSIVEAUTOLINKS); static_assert(int(QTextMarkdownImporter::FeatureTasklists) == MD_FLAG_TASKLISTS); static_assert(int(QTextMarkdownImporter::FeatureNoHTML) == MD_FLAG_NOHTML); static_assert(int(QTextMarkdownImporter::DialectCommonMark) == MD_DIALECT_COMMONMARK); -static_assert(int(QTextMarkdownImporter::DialectGitHub) == MD_DIALECT_GITHUB); +static_assert(int(QTextMarkdownImporter::DialectGitHub) == + (MD_DIALECT_GITHUB | MD_FLAG_UNDERLINE | QTextMarkdownImporter::FeatureFrontMatter)); // -------------------------------------------------------- // MD4C callback function wrappers @@ -132,18 +107,19 @@ static Qt::Alignment MdAlignment(MD_ALIGN a, Qt::Alignment defaultAlignment = Qt } } -QTextMarkdownImporter::QTextMarkdownImporter(QTextMarkdownImporter::Features features) - : m_monoFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)) +QTextMarkdownImporter::QTextMarkdownImporter(QTextDocument *doc, QTextMarkdownImporter::Features features) + : m_cursor(doc) + , m_monoFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)) , m_features(features) { } -QTextMarkdownImporter::QTextMarkdownImporter(QTextDocument::MarkdownFeatures features) - : QTextMarkdownImporter(static_cast<QTextMarkdownImporter::Features>(int(features))) +QTextMarkdownImporter::QTextMarkdownImporter(QTextDocument *doc, QTextDocument::MarkdownFeatures features) + : QTextMarkdownImporter(doc, static_cast<QTextMarkdownImporter::Features>(int(features))) { } -void QTextMarkdownImporter::import(QTextDocument *doc, const QString &markdown) +void QTextMarkdownImporter::import(const QString &markdown) { MD_PARSER callbacks = { 0, // abi_version @@ -156,19 +132,36 @@ void QTextMarkdownImporter::import(QTextDocument *doc, const QString &markdown) &CbDebugLog, nullptr // syntax }; - m_doc = doc; - m_paragraphMargin = m_doc->defaultFont().pointSize() * 2 / 3; - m_cursor = new QTextCursor(doc); + QTextDocument *doc = m_cursor.document(); + const auto defaultFont = doc->defaultFont(); + m_paragraphMargin = defaultFont.pointSize() * 2 / 3; doc->clear(); - if (doc->defaultFont().pointSize() != -1) - m_monoFont.setPointSize(doc->defaultFont().pointSize()); + if (defaultFont.pointSize() != -1) + m_monoFont.setPointSize(defaultFont.pointSize()); else - m_monoFont.setPixelSize(doc->defaultFont().pixelSize()); - qCDebug(lcMD) << "default font" << doc->defaultFont() << "mono font" << m_monoFont; - QByteArray md = markdown.toUtf8(); - md_parse(md.constData(), MD_SIZE(md.size()), &callbacks, this); - delete m_cursor; - m_cursor = nullptr; + m_monoFont.setPixelSize(defaultFont.pixelSize()); + qCDebug(lcMD) << "default font" << defaultFont << "mono font" << m_monoFont; + QStringView md = markdown; + + if (m_features.testFlag(QTextMarkdownImporter::FeatureFrontMatter) && md.startsWith(markerString())) { + qsizetype endMarkerPos = md.indexOf(markerString(), markerString().size() + 1); + if (endMarkerPos > 4) { + qsizetype firstLinePos = 4; // first line of yaml + while (md.at(firstLinePos) == '\n'_L1 || md.at(firstLinePos) == '\r'_L1) + ++firstLinePos; + auto frontMatter = md.sliced(firstLinePos, endMarkerPos - firstLinePos); + firstLinePos = endMarkerPos + 4; // first line of markdown after yaml + while (md.size() > firstLinePos && (md.at(firstLinePos) == '\n'_L1 || md.at(firstLinePos) == '\r'_L1)) + ++firstLinePos; + md = md.sliced(firstLinePos); + doc->setMetaInformation(QTextDocument::FrontMatter, frontMatter.toString()); + qCDebug(lcMD) << "extracted FrontMatter: size" << frontMatter.size(); + } + } + const auto mdUtf8 = md.toUtf8(); + m_cursor.beginEditBlock(); + md_parse(mdUtf8.constData(), MD_SIZE(mdUtf8.size()), &callbacks, this); + m_cursor.endEditBlock(); } int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det) @@ -177,7 +170,7 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det) switch (blockType) { case MD_BLOCK_P: if (!m_listStack.isEmpty()) - qCDebug(lcMD, m_listItem ? "P of LI at level %d" : "P continuation inside LI at level %d", int(m_listStack.count())); + qCDebug(lcMD, m_listItem ? "P of LI at level %d" : "P continuation inside LI at level %d", int(m_listStack.size())); else qCDebug(lcMD, "P"); m_needsInsertBlock = true; @@ -189,9 +182,9 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det) case MD_BLOCK_CODE: { MD_BLOCK_CODE_DETAIL *detail = static_cast<MD_BLOCK_CODE_DETAIL *>(det); m_codeBlock = true; - m_blockCodeLanguage = QLatin1String(detail->lang.text, int(detail->lang.size)); + m_blockCodeLanguage = QLatin1StringView(detail->lang.text, int(detail->lang.size)); m_blockCodeFence = detail->fence_char; - QString info = QLatin1String(detail->info.text, int(detail->info.size)); + QString info = QLatin1StringView(detail->info.text, int(detail->info.size)); m_needsInsertBlock = true; if (m_blockQuoteDepth) qCDebug(lcMD, "CODE lang '%s' info '%s' fenced with '%c' inside QUOTE %d", qPrintable(m_blockCodeLanguage), qPrintable(info), m_blockCodeFence, m_blockQuoteDepth); @@ -207,11 +200,11 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det) charFmt.setFontWeight(QFont::Bold); blockFmt.setHeadingLevel(int(detail->level)); m_needsInsertBlock = false; - if (m_doc->isEmpty()) { - m_cursor->setBlockFormat(blockFmt); - m_cursor->setCharFormat(charFmt); + if (m_cursor.document()->isEmpty()) { + m_cursor.setBlockFormat(blockFmt); + m_cursor.setCharFormat(charFmt); } else { - m_cursor->insertBlock(blockFmt, charFmt); + m_cursor.insertBlock(blockFmt, charFmt); } qCDebug(lcMD, "H%d", detail->level); } break; @@ -226,12 +219,12 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det) } break; case MD_BLOCK_UL: { if (m_needsInsertList) // list nested in an empty list - m_listStack.push(m_cursor->insertList(m_listFormat)); + m_listStack.push(m_cursor.insertList(m_listFormat)); else m_needsInsertList = true; MD_BLOCK_UL_DETAIL *detail = static_cast<MD_BLOCK_UL_DETAIL *>(det); m_listFormat = QTextListFormat(); - m_listFormat.setIndent(m_listStack.count() + 1); + m_listFormat.setIndent(m_listStack.size() + 1); switch (detail->mark) { case '*': m_listFormat.setStyle(QTextListFormat::ListCircle); @@ -243,19 +236,20 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det) m_listFormat.setStyle(QTextListFormat::ListDisc); break; } - qCDebug(lcMD, "UL %c level %d", detail->mark, int(m_listStack.count()) + 1); + qCDebug(lcMD, "UL %c level %d", detail->mark, int(m_listStack.size()) + 1); } break; case MD_BLOCK_OL: { if (m_needsInsertList) // list nested in an empty list - m_listStack.push(m_cursor->insertList(m_listFormat)); + m_listStack.push(m_cursor.insertList(m_listFormat)); else m_needsInsertList = true; MD_BLOCK_OL_DETAIL *detail = static_cast<MD_BLOCK_OL_DETAIL *>(det); m_listFormat = QTextListFormat(); - m_listFormat.setIndent(m_listStack.count() + 1); + m_listFormat.setIndent(m_listStack.size() + 1); m_listFormat.setNumberSuffix(QChar::fromLatin1(detail->mark_delimiter)); m_listFormat.setStyle(QTextListFormat::ListDecimal); - qCDebug(lcMD, "OL xx%d level %d", detail->mark_delimiter, int(m_listStack.count()) + 1); + m_listFormat.setStart(detail->start); + qCDebug(lcMD, "OL xx%d level %d start %d", detail->mark_delimiter, int(m_listStack.size()) + 1, detail->start); } break; case MD_BLOCK_TD: { MD_BLOCK_TD_DETAIL *detail = static_cast<MD_BLOCK_TD_DETAIL *>(det); @@ -267,10 +261,10 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det) qWarning("malformed table in Markdown input"); return 1; } - *m_cursor = cell.firstCursorPosition(); - QTextBlockFormat blockFmt = m_cursor->blockFormat(); + m_cursor = cell.firstCursorPosition(); + QTextBlockFormat blockFmt = m_cursor.blockFormat(); blockFmt.setAlignment(MdAlignment(detail->align)); - m_cursor->setBlockFormat(blockFmt); + m_cursor.setBlockFormat(blockFmt); qCDebug(lcMD) << "TD; align" << detail->align << MdAlignment(detail->align) << "col" << m_tableCol; } break; case MD_BLOCK_TH: { @@ -298,13 +292,13 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det) case MD_BLOCK_TABLE: m_tableColumnCount = 0; m_tableRowCount = 0; - m_currentTable = m_cursor->insertTable(1, 1); // we don't know the dimensions yet + m_currentTable = m_cursor.insertTable(1, 1); // we don't know the dimensions yet break; case MD_BLOCK_HR: { qCDebug(lcMD, "HR"); QTextBlockFormat blockFmt; blockFmt.setProperty(QTextFormat::BlockTrailingHorizontalRulerWidth, 1); - m_cursor->insertBlock(blockFmt, QTextCharFormat()); + m_cursor.insertBlock(blockFmt, QTextCharFormat()); } break; default: break; // nothing to do for now @@ -322,11 +316,11 @@ int QTextMarkdownImporter::cbLeaveBlock(int blockType, void *detail) case MD_BLOCK_UL: case MD_BLOCK_OL: if (Q_UNLIKELY(m_needsInsertList)) - m_listStack.push(m_cursor->createList(m_listFormat)); + m_listStack.push(m_cursor.createList(m_listFormat)); if (Q_UNLIKELY(m_listStack.isEmpty())) { qCWarning(lcMD, "list ended unexpectedly"); } else { - qCDebug(lcMD, "list at level %d ended", int(m_listStack.count())); + qCDebug(lcMD, "list at level %d ended", int(m_listStack.size())); m_listStack.pop(); } break; @@ -360,10 +354,10 @@ int QTextMarkdownImporter::cbLeaveBlock(int blockType, void *detail) case MD_BLOCK_TABLE: qCDebug(lcMD) << "table ended with" << m_currentTable->columns() << "cols and" << m_currentTable->rows() << "rows"; m_currentTable = nullptr; - m_cursor->movePosition(QTextCursor::End); + m_cursor.movePosition(QTextCursor::End); break; case MD_BLOCK_LI: - qCDebug(lcMD, "LI at level %d ended", int(m_listStack.count())); + qCDebug(lcMD, "LI at level %d ended", int(m_listStack.size())); m_listItem = false; break; case MD_BLOCK_CODE: { @@ -377,7 +371,7 @@ int QTextMarkdownImporter::cbLeaveBlock(int blockType, void *detail) m_needsInsertBlock = true; } break; case MD_BLOCK_H: - m_cursor->setCharFormat(QTextCharFormat()); + m_cursor.setCharFormat(QTextCharFormat()); break; default: break; @@ -397,6 +391,9 @@ int QTextMarkdownImporter::cbEnterSpan(int spanType, void *det) case MD_SPAN_STRONG: charFmt.setFontWeight(QFont::Bold); break; + case MD_SPAN_U: + charFmt.setFontUnderline(true); + break; case MD_SPAN_A: { MD_SPAN_A_DETAIL *detail = static_cast<MD_SPAN_A_DETAIL *>(det); QString url = QString::fromUtf8(detail->href.text, int(detail->href.size)); @@ -418,15 +415,17 @@ int QTextMarkdownImporter::cbEnterSpan(int spanType, void *det) } case MD_SPAN_CODE: charFmt.setFont(m_monoFont); + charFmt.setFontFixedPitch(true); break; case MD_SPAN_DEL: charFmt.setFontStrikeOut(true); break; } m_spanFormatStack.push(charFmt); - qCDebug(lcMD) << spanType << "setCharFormat" << charFmt.font().family() << charFmt.fontWeight() - << (charFmt.fontItalic() ? "italic" : "") << charFmt.foreground().color().name(); - m_cursor->setCharFormat(charFmt); + qCDebug(lcMD) << spanType << "setCharFormat" << charFmt.font().families().constFirst() + << charFmt.fontWeight() << (charFmt.fontItalic() ? "italic" : "") + << charFmt.foreground().color().name(); + m_cursor.setCharFormat(charFmt); return 0; // no error } @@ -439,9 +438,10 @@ int QTextMarkdownImporter::cbLeaveSpan(int spanType, void *detail) if (!m_spanFormatStack.isEmpty()) charFmt = m_spanFormatStack.top(); } - m_cursor->setCharFormat(charFmt); - qCDebug(lcMD) << spanType << "setCharFormat" << charFmt.font().family() << charFmt.fontWeight() - << (charFmt.fontItalic() ? "italic" : "") << charFmt.foreground().color().name(); + m_cursor.setCharFormat(charFmt); + qCDebug(lcMD) << spanType << "setCharFormat" << charFmt.font().families().constFirst() + << charFmt.fontWeight() << (charFmt.fontItalic() ? "italic" : "") + << charFmt.foreground().color().name(); if (spanType == int(MD_SPAN_IMG)) m_imageSpan = false; return 0; // no error @@ -470,17 +470,20 @@ int QTextMarkdownImporter::cbText(int textType, const char *text, unsigned size) s = QString(QChar(u'\xFFFD')); // CommonMark-required replacement for null break; case MD_TEXT_BR: - s = QString(Newline); + s = QString(qtmi_Newline); break; case MD_TEXT_SOFTBR: - s = QString(Space); + s = QString(qtmi_Space); break; case MD_TEXT_CODE: // We'll see MD_SPAN_CODE too, which will set the char format, and that's enough. break; #if QT_CONFIG(texthtmlparser) case MD_TEXT_ENTITY: - m_cursor->insertHtml(s); + if (m_htmlTagDepth) + m_htmlAccumulator += s; + else + m_cursor.insertHtml(s); s = QString(); break; #endif @@ -502,11 +505,11 @@ int QTextMarkdownImporter::cbText(int textType, const char *text, unsigned size) m_htmlAccumulator += s; if (!m_htmlTagDepth) { // all open tags are now closed qCDebug(lcMD) << "HTML" << m_htmlAccumulator; - m_cursor->insertHtml(m_htmlAccumulator); + m_cursor.insertHtml(m_htmlAccumulator); if (m_spanFormatStack.isEmpty()) - m_cursor->setCharFormat(QTextCharFormat()); + m_cursor.setCharFormat(QTextCharFormat()); else - m_cursor->setCharFormat(m_spanFormatStack.top()); + m_cursor.setCharFormat(m_spanFormatStack.top()); m_htmlAccumulator = QString(); } #endif @@ -518,6 +521,14 @@ int QTextMarkdownImporter::cbText(int textType, const char *text, unsigned size) case MD_BLOCK_TD: m_nonEmptyTableCells.append(m_tableCol); break; + case MD_BLOCK_CODE: + if (s == qtmi_Newline) { + // defer a blank line until we see something else in the code block, + // to avoid ending every code block with a gratuitous blank line + m_needsInsertBlock = true; + s = QString(); + } + break; default: break; } @@ -528,35 +539,33 @@ int QTextMarkdownImporter::cbText(int textType, const char *text, unsigned size) m_imageFormat.setProperty(QTextFormat::ImageAltText, s); qCDebug(lcMD) << "image" << m_imageFormat.name() << "title" << m_imageFormat.stringProperty(QTextFormat::ImageTitle) - << "alt" << s << "relative to" << m_doc->baseUrl(); - m_cursor->insertImage(m_imageFormat); + << "alt" << s << "relative to" << m_cursor.document()->baseUrl(); + m_cursor.insertImage(m_imageFormat); return 0; // no error } if (!s.isEmpty()) - m_cursor->insertText(s); - if (m_cursor->currentList()) { + m_cursor.insertText(s); + if (m_cursor.currentList()) { // The list item will indent the list item's text, so we don't need indentation on the block. - QTextBlockFormat bfmt = m_cursor->blockFormat(); + QTextBlockFormat bfmt = m_cursor.blockFormat(); bfmt.setIndent(0); - m_cursor->setBlockFormat(bfmt); + m_cursor.setBlockFormat(bfmt); } if (lcMD().isEnabled(QtDebugMsg)) { - QTextBlockFormat bfmt = m_cursor->blockFormat(); + QTextBlockFormat bfmt = m_cursor.blockFormat(); QString debugInfo; - if (m_cursor->currentList()) - debugInfo = QLatin1String("in list at depth ") + QString::number(m_cursor->currentList()->format().indent()); + if (m_cursor.currentList()) + debugInfo = "in list at depth "_L1 + QString::number(m_cursor.currentList()->format().indent()); if (bfmt.hasProperty(QTextFormat::BlockQuoteLevel)) - debugInfo += QLatin1String("in blockquote at depth ") + + debugInfo += "in blockquote at depth "_L1 + QString::number(bfmt.intProperty(QTextFormat::BlockQuoteLevel)); if (bfmt.hasProperty(QTextFormat::BlockCodeLanguage)) - debugInfo += QLatin1String("in a code block"); + debugInfo += "in a code block"_L1; qCDebug(lcMD) << textType << "in block" << m_blockType << s << qPrintable(debugInfo) << "bindent" << bfmt.indent() << "tindent" << bfmt.textIndent() << "margins" << bfmt.leftMargin() << bfmt.topMargin() << bfmt.bottomMargin() << bfmt.rightMargin(); } - qCDebug(lcMD) << textType << "in block" << m_blockType << s << "in list?" << m_cursor->currentList() - << "indent" << m_cursor->blockFormat().indent(); return 0; // no error } @@ -564,7 +573,7 @@ int QTextMarkdownImporter::cbText(int textType, const char *text, unsigned size) Insert a new block based on stored state. m_cursor cannot store the state for the _next_ block ahead of time, because - m_cursor->setBlockFormat() controls the format of the block that the cursor + m_cursor.setBlockFormat() controls the format of the block that the cursor is already in; so cbLeaveBlock() cannot call setBlockFormat() without altering the block that was just added. Therefore cbLeaveBlock() and the following cbEnterBlock() set variables to remember what formatting should @@ -586,13 +595,15 @@ void QTextMarkdownImporter::insertBlock() } if (m_blockQuoteDepth) { blockFormat.setProperty(QTextFormat::BlockQuoteLevel, m_blockQuoteDepth); - blockFormat.setLeftMargin(BlockQuoteIndent * m_blockQuoteDepth); - blockFormat.setRightMargin(BlockQuoteIndent); + blockFormat.setLeftMargin(qtmi_BlockQuoteIndent * m_blockQuoteDepth); + blockFormat.setRightMargin(qtmi_BlockQuoteIndent); } if (m_codeBlock) { blockFormat.setProperty(QTextFormat::BlockCodeLanguage, m_blockCodeLanguage); - if (m_blockCodeFence) + if (m_blockCodeFence) { + blockFormat.setNonBreakableLines(true); blockFormat.setProperty(QTextFormat::BlockCodeFence, QString(QLatin1Char(m_blockCodeFence))); + } charFormat.setFont(m_monoFont); } else { blockFormat.setTopMargin(m_paragraphMargin); @@ -603,17 +614,20 @@ void QTextMarkdownImporter::insertBlock() else blockFormat.setMarker(m_markerType); if (!m_listStack.isEmpty()) - blockFormat.setIndent(m_listStack.count()); - if (m_doc->isEmpty()) { - m_cursor->setBlockFormat(blockFormat); - m_cursor->setCharFormat(charFormat); + blockFormat.setIndent(m_listStack.size()); + if (m_cursor.document()->isEmpty()) { + m_cursor.setBlockFormat(blockFormat); + m_cursor.setCharFormat(charFormat); + } else if (m_listItem) { + m_cursor.insertBlock(blockFormat, QTextCharFormat()); + m_cursor.setCharFormat(charFormat); } else { - m_cursor->insertBlock(blockFormat, charFormat); + m_cursor.insertBlock(blockFormat, charFormat); } if (m_needsInsertList) { - m_listStack.push(m_cursor->createList(m_listFormat)); + m_listStack.push(m_cursor.createList(m_listFormat)); } else if (!m_listStack.isEmpty() && m_listItem && m_listStack.top()) { - m_listStack.top()->add(m_cursor->block()); + m_listStack.top()->add(m_cursor.block()); } m_needsInsertList = false; m_needsInsertBlock = false; |