6#include <QLoggingCategory>
7#if QT_CONFIG(regularexpression)
8#include <QRegularExpression>
11#include <QTextDocument>
12#include <QTextDocumentFragment>
15#if QT_CONFIG(system_textmarkdownreader)
18#include "../../3rdparty/md4c/md4c.h"
35static_assert(
int(
QTextMarkdownImporter::FeaturePermissiveATXHeaders) == MD_FLAG_PERMISSIVEATXHEADERS);
36static_assert(
int(
QTextMarkdownImporter::FeaturePermissiveURLAutoLinks) == MD_FLAG_PERMISSIVEURLAUTOLINKS);
37static_assert(
int(
QTextMarkdownImporter::FeaturePermissiveMailAutoLinks) == MD_FLAG_PERMISSIVEEMAILAUTOLINKS);
38static_assert(
int(
QTextMarkdownImporter::FeatureNoIndentedCodeBlocks) == MD_FLAG_NOINDENTEDCODEBLOCKS);
44static_assert(
int(
QTextMarkdownImporter::FeaturePermissiveWWWAutoLinks) == MD_FLAG_PERMISSIVEWWWAUTOLINKS);
103 return defaultAlignment;
109 , m_features(features)
122 unsigned(m_features),
150 m_blockType = blockType;
154 qCDebug(lcMD, m_listItem ?
"P of LI at level %d" :
"P continuation inside LI at level %d", int(m_listStack.
size()));
157 m_needsInsertBlock =
true;
161 qCDebug(lcMD,
"QUOTE level %d", m_blockQuoteDepth);
163 case MD_BLOCK_CODE: {
164 MD_BLOCK_CODE_DETAIL *
detail =
static_cast<MD_BLOCK_CODE_DETAIL *
>(det);
167 m_blockCodeFence =
detail->fence_char;
169 m_needsInsertBlock =
true;
170 if (m_blockQuoteDepth)
171 qCDebug(lcMD,
"CODE lang '%s' info '%s' fenced with '%c' inside QUOTE %d",
qPrintable(m_blockCodeLanguage),
qPrintable(
info), m_blockCodeFence, m_blockQuoteDepth);
176 MD_BLOCK_H_DETAIL *
detail =
static_cast<MD_BLOCK_H_DETAIL *
>(det);
179 int sizeAdjustment = 4 - int(
detail->level);
183 m_needsInsertBlock =
false;
193 m_needsInsertBlock =
true;
195 MD_BLOCK_LI_DETAIL *
detail =
static_cast<MD_BLOCK_LI_DETAIL *
>(det);
196 m_markerType =
detail->is_task ?
202 if (m_needsInsertList)
205 m_needsInsertList =
true;
206 MD_BLOCK_UL_DETAIL *
detail =
static_cast<MD_BLOCK_UL_DETAIL *
>(det);
223 if (m_needsInsertList)
226 m_needsInsertList =
true;
227 MD_BLOCK_OL_DETAIL *
detail =
static_cast<MD_BLOCK_OL_DETAIL *
>(det);
233 qCDebug(lcMD,
"OL xx%d level %d start %d",
detail->mark_delimiter,
int(m_listStack.
size()) + 1,
detail->start);
236 MD_BLOCK_TD_DETAIL *
detail =
static_cast<MD_BLOCK_TD_DETAIL *
>(det);
242 qWarning(
"malformed table in Markdown input");
252 ++m_tableColumnCount;
254 if (m_currentTable->
columns() < m_tableColumnCount)
256 auto cell = m_currentTable->
cellAt(m_tableRowCount - 1, m_tableCol);
257 if (!cell.isValid()) {
258 qWarning(
"malformed table in Markdown input");
261 auto fmt = cell.format();
267 m_nonEmptyTableCells.
clear();
268 if (m_currentTable->
rows() < m_tableRowCount)
274 m_tableColumnCount = 0;
302 qCWarning(lcMD,
"list ended unexpectedly");
304 qCDebug(lcMD,
"list at level %d ended",
int(m_listStack.
size()));
314 for (
int col = m_tableCol; col >= 0; --col) {
315 if (m_nonEmptyTableCells.
contains(col)) {
316 if (mergeEnd >= 0 && mergeBegin >= 0) {
317 qCDebug(lcMD) <<
"merging cells" << mergeBegin <<
"to" << mergeEnd <<
"inclusive, on row" << m_currentTable->
rows() - 1;
318 m_currentTable->
mergeCells(m_currentTable->
rows() - 1, mergeBegin - 1, 1, mergeEnd - mergeBegin + 2);
330 case MD_BLOCK_QUOTE: {
331 qCDebug(lcMD,
"QUOTE level %d ended", m_blockQuoteDepth);
333 m_needsInsertBlock =
true;
336 qCDebug(lcMD) <<
"table ended with" << m_currentTable->
columns() <<
"cols and" << m_currentTable->
rows() <<
"rows";
337 m_currentTable =
nullptr;
341 qCDebug(lcMD,
"LI at level %d ended",
int(m_listStack.
size()));
344 case MD_BLOCK_CODE: {
346 m_blockCodeLanguage.
clear();
347 m_blockCodeFence = 0;
348 if (m_blockQuoteDepth)
349 qCDebug(lcMD,
"CODE ended inside QUOTE %d", m_blockQuoteDepth);
352 m_needsInsertBlock =
true;
366 if (!m_spanFormatStack.
isEmpty())
367 charFmt = m_spanFormatStack.
top();
379 MD_SPAN_A_DETAIL *
detail =
static_cast<MD_SPAN_A_DETAIL *
>(det);
392 MD_SPAN_IMG_DETAIL *
detail =
static_cast<MD_SPAN_IMG_DETAIL *
>(det);
405 m_spanFormatStack.
push(charFmt);
417 if (!m_spanFormatStack.
isEmpty()) {
418 m_spanFormatStack.
pop();
419 if (!m_spanFormatStack.
isEmpty())
420 charFmt = m_spanFormatStack.
top();
426 if (spanType ==
int(MD_SPAN_IMG))
433 if (m_needsInsertBlock)
435#if QT_CONFIG(regularexpression)
443#if QT_CONFIG(regularexpression)
444 if (m_htmlTagDepth) {
445 m_htmlAccumulator +=
s;
450 case MD_TEXT_NULLCHAR:
462#if QT_CONFIG(texthtmlparser)
465 m_htmlAccumulator +=
s;
473#if QT_CONFIG(regularexpression) && QT_CONFIG(texthtmlparser)
476 while ((startIdx =
s.indexOf(openingBracket, startIdx)) >= 0) {
481 while ((startIdx =
s.indexOf(closingBracket, startIdx)) >= 0) {
486 m_htmlAccumulator +=
s;
487 if (!m_htmlTagDepth) {
488 qCDebug(lcMD) <<
"HTML" << m_htmlAccumulator;
490 if (m_spanFormatStack.
isEmpty())
501 switch (m_blockType) {
503 m_nonEmptyTableCells.
append(m_tableCol);
509 m_needsInsertBlock =
true;
523 <<
"alt" <<
s <<
"relative to" << m_doc->
baseUrl();
542 debugInfo +=
"in blockquote at depth "_L1 +
545 debugInfo +=
"in a code block"_L1;
564void QTextMarkdownImporter::insertBlock()
567 if (!m_spanFormatStack.
isEmpty())
568 charFormat = m_spanFormatStack.
top();
570 if (!m_listStack.
isEmpty() && !m_needsInsertList && m_listItem) {
575 qWarning() <<
"attempted to insert into a list that no longer exists";
577 if (m_blockQuoteDepth) {
584 if (m_blockCodeFence) {
588 charFormat.
setFont(m_monoFont);
602 }
else if (m_listItem) {
608 if (m_needsInsertList) {
610 }
else if (!m_listStack.
isEmpty() && m_listItem && m_listStack.
top()) {
613 m_needsInsertList =
false;
614 m_needsInsertBlock =
false;
const QColor & color() const
Returns the brush color.
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
static constexpr QChar fromLatin1(char c) noexcept
Converts the Latin-1 character c to its equivalent QChar.
QString name(NameFormat format=HexRgb) const
\threadsafe \inmodule QtGui
void setPointSize(int)
Sets the point size to pointSize.
int pixelSize() const
Returns the pixel size of the font if it was set with setPixelSize().
QStringList families() const
int pointSize() const
Returns the point size of the font.
void setPixelSize(int)
Sets the font size to pixelSize pixels, with a maxiumum size of an unsigned 16-bit integer.
qsizetype size() const noexcept
bool isEmpty() const noexcept
qsizetype count() const noexcept
void append(parameter_type t)
const QBrush & link() const
Returns the unvisited link text brush of the current color group.
\inmodule QtCore \reentrant
T & top()
Returns a reference to the stack's top item.
T pop()
Removes the top item from the stack and returns it.
void push(const T &t)
Adds element t to the top of the stack.
\macro QT_RESTRICTED_CAST_FROM_ASCII
void clear()
Clears the contents of the string and makes it null.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray toUtf8() const &
qreal bottomMargin() const
Returns the paragraph's bottom margin.
qreal topMargin() const
Returns the paragraph's top margin.
void setLeftMargin(qreal margin)
Sets the paragraph's left margin.
void setAlignment(Qt::Alignment alignment)
Sets the paragraph's alignment.
void setMarker(MarkerType marker)
void setBottomMargin(qreal margin)
Sets the paragraph's bottom margin.
void setNonBreakableLines(bool b)
If b is true, the lines in the paragraph are treated as non-breakable; otherwise they are breakable.
void setRightMargin(qreal margin)
Sets the paragraph's right margin.
void setIndent(int indent)
Sets the paragraph's indentation.
int indent() const
Returns the paragraph's indent.
qreal leftMargin() const
Returns the paragraph's left margin.
qreal textIndent() const
Returns the paragraph's text indent.
void setHeadingLevel(int alevel)
qreal rightMargin() const
Returns the paragraph's right margin.
void setTopMargin(qreal margin)
Sets the paragraph's top margin.
int fontWeight() const
Returns the text format's font weight.
void setAnchor(bool anchor)
If anchor is true, text with this format represents an anchor, and is formatted in the appropriate wa...
void setFontUnderline(bool underline)
If underline is true, sets the text format's font to be underlined; otherwise it is displayed non-und...
void setToolTip(const QString &tip)
QFont font() const
Returns the font for this character format.
void setFontFixedPitch(bool fixedPitch)
If fixedPitch is true, sets the text format's font to be fixed pitch; otherwise a non-fixed pitch fon...
void setFontStrikeOut(bool strikeOut)
If strikeOut is true, sets the text format's font with strike-out enabled (with a horizontal line thr...
bool fontItalic() const
Returns true if the text format's font is italic; otherwise returns false.
void setAnchorHref(const QString &value)
Sets the hypertext link for the text format to the given value.
void setFontItalic(bool italic)
If italic is true, sets the text format's font to be italic; otherwise the font will be non-italic.
void setFontWeight(int weight)
Sets the text format's font weight to weight.
void setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior=FontPropertiesAll)
\reentrant \inmodule QtGui
QTextBlockFormat blockFormat() const
Returns the block format of the block the cursor is in.
QTextBlock block() const
Returns the block that contains the cursor.
void beginEditBlock()
Indicates the start of a block of editing operations on the document that should appear as a single o...
bool movePosition(MoveOperation op, MoveMode=MoveAnchor, int n=1)
Moves the cursor by performing the given operation n times, using the specified mode,...
void insertHtml(const QString &html)
void setBlockFormat(const QTextBlockFormat &format)
Sets the block format of the current block (or all blocks that are contained in the selection) to for...
void setCharFormat(const QTextCharFormat &format)
Sets the cursor's current character format to the given format.
void insertText(const QString &text)
Inserts text at the current position, using the current character format.
QTextList * currentList() const
Returns the current list if the cursor position() is inside a block that is part of a list; otherwise...
void insertImage(const QTextImageFormat &format, QTextFrameFormat::Position alignment)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void insertBlock()
Inserts a new empty block at the cursor position() with the current blockFormat() and charFormat().
void endEditBlock()
Indicates the end of a block of editing operations on the document that should appear as a single ope...
QTextList * insertList(const QTextListFormat &format)
Inserts a new block at the current position and makes it the first list item of a newly created list ...
QTextTable * insertTable(int rows, int cols, const QTextTableFormat &format)
Creates a new table with the given number of rows and columns in the specified format,...
QTextList * createList(const QTextListFormat &format)
Creates and returns a new list with the given format, and makes the current paragraph the cursor is i...
\reentrant \inmodule QtGui
bool isEmpty() const
Returns true if the document is empty; otherwise returns false.
QFont defaultFont
the default font used to display the document's text
virtual void clear()
Clears the document.
QUrl baseUrl
the base URL used to resolve relative resource URLs within the document.
QString stringProperty(int propertyId) const
Returns the value of the property given by propertyId; if the property isn't of QMetaType::QString ty...
void setForeground(const QBrush &brush)
Sets the foreground brush to the specified brush.
@ BlockTrailingHorizontalRulerWidth
int intProperty(int propertyId) const
Returns the value of the property specified by propertyId.
void setProperty(int propertyId, const QVariant &value)
Sets the property specified by the propertyId to the given value.
bool hasProperty(int propertyId) const
Returns true if the text format has a property with the given propertyId; otherwise returns false.
void clearProperty(int propertyId)
Clears the value of the property given by propertyId.
QBrush foreground() const
Returns the brush used to render foreground details, such as text, frame outlines,...
QString name() const
Returns the name of the image.
void setName(const QString &name)
Sets the name of the image.
void setStyle(Style style)
Sets the list format's style.
void setIndent(int indent)
Sets the list format's indentation.
void setNumberSuffix(const QString &numberSuffix)
int indent() const
Returns the list format's indentation.
void setStart(int indent)
void add(const QTextBlock &block)
Makes the given block part of the list.
QTextListFormat format() const
Returns the list's format.
int cbLeaveBlock(int blockType, void *detail)
int cbText(int textType, const char *text, unsigned size)
QTextMarkdownImporter(Features features)
int cbEnterBlock(int blockType, void *detail)
void import(QTextDocument *doc, const QString &markdown)
int cbEnterSpan(int spanType, void *detail)
int cbLeaveSpan(int spanType, void *detail)
QTextCursor firstCursorPosition() const
Returns the first valid cursor position in this cell.
bool isValid() const
Returns true if this is a valid table cell; otherwise returns false.
int columns() const
Returns the number of columns in the table.
void appendRows(int count)
void appendColumns(int count)
int rows() const
Returns the number of rows in the table.
QTextTableCell cellAt(int row, int col) const
Returns the table cell at the given row and column in the table.
void mergeCells(int row, int col, int numRows, int numCols)
Combined button and popup list for selecting options.
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
PromiseCallbacks callbacks
#define qPrintable(string)
#define QStringLiteral(str)
static void CbDebugLog(const char *msg, void *userdata)
static int CbEnterSpan(MD_SPANTYPE type, void *detail, void *userdata)
static int CbLeaveBlock(MD_BLOCKTYPE type, void *detail, void *userdata)
static int CbText(MD_TEXTTYPE type, const MD_CHAR *text, MD_SIZE size, void *userdata)
static const QChar qtmi_Newline
static const QChar qtmi_Space
static const int qtmi_BlockQuoteIndent
static Qt::Alignment MdAlignment(MD_ALIGN a, Qt::Alignment defaultAlignment=Qt::AlignLeft|Qt::AlignVCenter)
static int CbEnterBlock(MD_BLOCKTYPE type, void *detail, void *userdata)
static int CbLeaveSpan(MD_SPANTYPE type, void *detail, void *userdata)
QVideoFrameFormat::PixelFormat fmt
QFileInfo info(fileName)
[8]
QUrl url("example.com")
[constructor-url-reference]
\inmodule QtCore \reentrant
bool contains(const AT &t) const noexcept