15#include <QtCore/QRegularExpression>
16#if QT_CONFIG(itemmodel)
37 : m_stream(
stream), m_features(features)
48#if QT_CONFIG(itemmodel)
51 QList<int> tableColumnWidths(
table->columnCount());
52 for (
int col = 0; col <
table->columnCount(); ++col) {
55 tableColumnWidths[col] =
qMax(tableColumnWidths[col],
61 for (
int col = 0; col <
table->columnCount(); ++col) {
66 for (
int col = 0; col < tableColumnWidths.size(); ++col)
67 m_stream <<
'|' <<
QString(tableColumnWidths[col], u
'-');
72 for (
int col = 0; col <
table->columnCount(); ++col) {
84 const bool featureEnabled = m_features.testFlag(
86 qCDebug(lcMDW) <<
"writing FrontMatter?" << featureEnabled <<
"size" << fm.size();
87 if (fm.isEmpty() || !featureEnabled)
89 m_stream <<
"---\n"_L1 << fm;
92 m_stream <<
"---\n"_L1;
102 bool lastWasList =
false;
103 QList<int> tableColumnWidths;
105 tableColumnWidths.resize(
table->columns());
106 for (
int col = 0; col <
table->columns(); ++col) {
111 while (
it != cell.
end()) {
117 if (cell.
columnSpan() == 1 && tableColumnWidths[col] < cellTextLen)
118 tableColumnWidths[col] = cellTextLen;
122 while (!iterator.atEnd()) {
123 if (iterator.currentFrame() &&
child != iterator.currentFrame())
129 bool nextIsDifferent =
false;
131 int blockQuoteIndent = 0;
132 int nextBlockQuoteIndent = 0;
141 nextIsDifferent =
true;
144 if (nextFormat.indent() !=
format.indent() ||
147 nextIsDifferent =
true;
152 if (tableRow < cell.
row()) {
155 for (
int col = 0; col < tableColumnWidths.size(); ++col)
156 m_stream <<
'|' <<
QString(tableColumnWidths[col], u
'-');
160 tableRow = cell.
row();
165 m_linePrefixWritten =
false;
169 nextIsDifferent && !block.
textList());
170 m_doubleNewlineWritten =
false;
173 int paddingLen = -endingCol;
175 for (
int col = cell.
column(); col < spanEndCol; ++col)
176 paddingLen += tableColumnWidths[col];
179 for (
int col = cell.
column(); col < spanEndCol; ++col)
181 }
else if (m_fencedCodeBlock && ending) {
184 m_codeBlockFence.
clear();
185 }
else if (m_indentedCodeBlock && nextIsDifferent) {
187 }
else if (endingCol > 0) {
191 m_stream << m_linePrefix;
192 m_linePrefixWritten =
true;
196 if (nextBlockQuoteIndent < blockQuoteIndent)
197 setLinePrefixForBlockQuote(nextBlockQuoteIndent);
198 m_stream << m_linePrefix;
200 m_doubleNewlineWritten =
true;
205 child = iterator.currentFrame();
210 m_doubleNewlineWritten =
true;
215QTextMarkdownWriter::ListInfo QTextMarkdownWriter::listInfo(
QTextList *
list)
225 while (
next.isValid()) {
228 qCDebug(lcMDW) <<
"next block in list" <<
list <<
next.text() <<
"part of list?" <<
next.textList();
229 if (!
next.textList()) {
232 qCDebug(lcMDW) <<
"decided list beginning with" <<
first.text() <<
"is loose after" <<
next.text();
245void QTextMarkdownWriter::setLinePrefixForBlockQuote(
int level)
247 m_linePrefix.
clear();
251 m_linePrefix += u
"> ";
257 before =
qMin(before,
s.size());
258 int fragBegin =
qMax(before - 15, 0);
259 if (lcMDW().isDebugEnabled()) {
261 qCDebug(lcMDW) << frag << before;
264 for (
int i = before - 1;
i >= 0; --
i) {
265 if (
s.at(
i).isSpace()) {
270 qCDebug(lcMDW,
"not possible");
278 for (
int i = 0;
i <
len; ++
i) {
282 }
else if (
start >= 0) {
304 if (sTrimmed.isEmpty())
306 QChar firstChar = sTrimmed.at(0);
307 if (specialFirstCharacters.contains(firstChar)) {
308 int i =
s.indexOf(firstChar);
313 if (
match.hasMatch())
328 s.replace("\\"_L1,
"\\\\"_L1);
332 if (
int j =
s.indexOf(specialRe,
i);
j >= 0) {
336 i =
s.indexOf(spaceRe,
i);
393 while (
data < lineEndPositions.nextLineBegin) {
401 data = lineEndPositions.nextLineBegin;
412 const int ColumnLimit = 80;
414 bool missedBlankCodeBlockLine =
false;
417 blockFmt.nonBreakableLines();
419 if (m_fencedCodeBlock && !codeBlock) {
420 m_stream << m_linePrefix << m_codeBlockFence <<
qtmw_Newline;
421 m_fencedCodeBlock =
false;
422 m_codeBlockFence.
clear();
423 m_linePrefixWritten = m_linePrefix.
size() > 0;
425 m_linePrefix.
clear();
426 if (!blockFmt.headingLevel() && blockQuoteLevel > 0) {
427 setLinePrefixForBlockQuote(blockQuoteLevel);
428 if (!m_linePrefixWritten) {
429 m_stream << m_linePrefix;
430 m_linePrefixWritten =
true;
437 const int start =
fmt.start() >= 0 ?
fmt.start() : 1;
440 bool numeric =
false;
441 switch (
fmt.style()) {
444 m_wrappedLineIndent = 2;
448 m_wrappedLineIndent = 2;
452 m_wrappedLineIndent = 2;
461 m_wrappedLineIndent = 4;
464 switch (blockFmt.marker()) {
474 int indentFirstLine = (listLevel - 1) * (numeric ? 4 : 2);
475 m_wrappedLineIndent += indentFirstLine;
476 if (m_lastListIndent != listLevel && !m_doubleNewlineWritten && listInfo(block.
textList()).loose)
478 m_lastListIndent = listLevel;
485 if (numberStr.size() == 3)
493 m_stream <<
"- - -\n";
495 }
else if (codeBlock) {
499 missedBlankCodeBlockLine =
true;
500 if (!m_fencedCodeBlock) {
502 if (fenceChar.isEmpty())
504 m_codeBlockFence =
QString(3, fenceChar.at(0));
510 m_fencedCodeBlock =
true;
513 }
else if (!blockFmt.indent()) {
514 m_wrappedLineIndent = 0;
518 m_indentedCodeBlock =
true;
520 if (!m_linePrefixWritten) {
521 m_stream << m_linePrefix;
522 m_linePrefixWritten =
true;
525 if (blockFmt.headingLevel()) {
526 m_stream <<
QByteArray(blockFmt.headingLevel(),
'#') <<
' ';
534 int col = wrapIndentString.size();
536 bool startsOrEndsWithBacktick =
false;
539 bool underline =
false;
540 bool strikeOut =
false;
541 bool endingMarkers =
false;
544 missedBlankCodeBlockLine =
false;
545 QString fragmentText = frag.fragment().text();
547 fragmentText.
chop(1);
548 if (!(m_fencedCodeBlock || m_indentedCodeBlock)) {
556 }
else if (blockFmt.indent() > 0) {
561 startsOrEndsWithBacktick |=
564 if (
fmt.isImageFormat()) {
569 QString s =
"!["_L1 + desc +
"]("_L1 + ifmt.name();
574 if (
wrap && col +
s.size() > ColumnLimit) {
576 col = m_wrappedLineIndent;
585 s = u
'<' + href + u
'>';
587 s = u
'[' + fragmentText +
"]("_L1 + href;
594 if (
wrap && col +
s.size() > ColumnLimit) {
596 col = m_wrappedLineIndent;
602 bool monoFrag = fontInfo.
fixedPitch() ||
fmt.fontFixedPitch();
605 if (monoFrag != mono && !m_indentedCodeBlock && !m_fencedCodeBlock) {
609 markers += backticks;
610 if (startsOrEndsWithBacktick)
614 endingMarkers =
true;
616 if (!blockFmt.headingLevel() && !mono) {
617 if (fontInfo.
bold() != bold) {
619 bold = fontInfo.
bold();
621 endingMarkers =
true;
623 if (fontInfo.
italic() != italic) {
625 italic = fontInfo.
italic();
627 endingMarkers =
true;
633 endingMarkers =
true;
642 endingMarkers =
true;
646 if (
wrap && col + markers.size() * 2 + fragmentText.size() > ColumnLimit) {
648 const int fragLen = fragmentText.size();
649 bool breakingLine =
false;
650 while (
i < fragLen) {
651 if (col >= ColumnLimit) {
652 m_stream << markers <<
qtmw_Newline << wrapIndentString;
654 col = m_wrappedLineIndent;
655 while (
i < fragLen && fragmentText[
i].isSpace())
658 int j =
i + ColumnLimit - col;
669 col = m_wrappedLineIndent;
670 }
else if (wi >=
i) {
676 breakingLine =
false;
681 col += markers.size();
683 if (col == m_wrappedLineIndent)
688 col = m_wrappedLineIndent;
690 col += subfrag.size();
695 if (!m_linePrefixWritten && col == wrapIndentString.size()) {
696 m_stream << m_linePrefix;
697 col += m_linePrefix.
size();
699 m_stream << markers << fragmentText;
700 col += markers.size() + fragmentText.size();
705 if (startsOrEndsWithBacktick) {
709 m_stream << backticks;
710 col += backticks.size();
728 if (missedBlankCodeBlockLine)
730 m_linePrefixWritten =
false;
bool italic() const
Returns the italic value of the matched window system font.
bool fixedPitch() const
Returns the fixed pitch value of the matched window system font.
bool bold() const
Returns true if weight() would return a value greater than QFont::Normal; otherwise returns false.
bool strikeOut() const
Returns the strikeout value of the matched window system font.
bool underline() const
Returns the underline value of the matched window system font.
qsizetype count() const noexcept
iterator insert(const Key &key, const T &value)
T value(const Key &key, const T &defaultValue=T()) const
bool contains(const Key &key) const
\inmodule QtCore \reentrant
@ AnchorAtOffsetMatchOption
\macro QT_RESTRICTED_CAST_FROM_ASCII
void reserve(qsizetype size)
Ensures the string has space for at least size characters.
void chop(qsizetype n)
Removes n characters from the end of the string.
QString mid(qsizetype position, qsizetype n=-1) const &
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
void clear()
Clears the contents of the string and makes it null.
qsizetype size() const noexcept
Returns the number of characters in this string.
QChar * data()
Returns a pointer to the data stored in the QString.
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString trimmed() const &
iterator begin() const
Returns a text block iterator pointing to the beginning of the text block.
QTextBlockFormat blockFormat() const
Returns the QTextBlockFormat that describes block-specific properties.
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
int position() const
Returns the index of the block's first character within the document.
QString text() const
Returns the block's contents as plain text.
QTextList * textList() const
If the block represents a list item, returns the list that the item belongs to; otherwise returns \nu...
\reentrant \inmodule QtGui
@ BlockTrailingHorizontalRulerWidth
QTextImageFormat toImageFormat() const
Returns this format as an image format.
bool hasProperty(int propertyId) const
Returns true if the text format has a property with the given propertyId; otherwise returns false.
int indent() const
Returns the list format's indentation.
int itemNumber(const QTextBlock &) const
Returns the index of the list item that corresponds to the given block.
QTextListFormat format() const
Returns the list's format.
bool writeAll(const QTextDocument *document)
int writeBlock(const QTextBlock &block, bool table, bool ignoreFormat, bool ignoreEmpty)
void writeFrontMatter(const QString &fm)
void writeFrame(const QTextFrame *frame)
int columnSpan() const
Returns the number of columns this cell spans.
QTextFrame::iterator end() const
Returns a frame iterator pointing to the end of the table's cell.
int row() const
Returns the number of the row in the table that contains this cell.
int column() const
Returns the number of the column in the table that contains this cell.
QTextFrame::iterator begin() const
Returns a frame iterator pointing to the beginning of the table's cell.
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QTextStream & endl(QTextStream &stream)
Writes '\n' to the stream and flushes the stream.
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
GLenum GLuint GLint level
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei GLsizei GLenum format
GLenum GLenum GLsizei void * row
GLenum GLenum GLsizei void * table
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
static QT_BEGIN_NAMESPACE QAsn1Element wrap(quint8 type, const QAsn1Element &child)
static const QChar qtmw_Backtick
static const QChar qtmw_Backslash
static const QChar qtmw_DoubleQuote
static const QChar qtmw_CarriageReturn
static int nearestWordWrapIndex(const QString &s, int before)
static const QChar qtmw_Newline
static int adjacentBackticksCount(const QString &s)
static QString createLinkTitle(const QString &title)
static bool isBlankLine(const QChar *begin, const QChar *end)
static const QChar qtmw_Tab
static void maybeEscapeFirstChar(QString &s)
static const QChar qtmw_Period
static LineEndPositions findLineEnd(const QChar *begin, const QChar *end)
static const QChar qtmw_Space
static const QChar qtmw_LineBreak
static void escapeSpecialCharacters(QString &s)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
QVideoFrameFormat::PixelFormat fmt
const QChar * nextLineBegin