diff --git a/src/hgmarkdownhighlighter.cpp b/src/hgmarkdownhighlighter.cpp index fb8b44ac..11392d85 100644 --- a/src/hgmarkdownhighlighter.cpp +++ b/src/hgmarkdownhighlighter.cpp @@ -24,7 +24,7 @@ void HGMarkdownHighlighter::resizeBuffer(int newCap) // Will be freeed by parent automatically HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector &styles, - const QMap &codeBlockStyles, + const QHash &codeBlockStyles, int waitInterval, QTextDocument *parent) : QSyntaxHighlighter(parent), highlightingStyles(styles), @@ -47,10 +47,19 @@ HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector &s resizeBuffer(initCapacity); document = parent; + timer = new QTimer(this); timer->setSingleShot(true); timer->setInterval(this->waitInterval); connect(timer, &QTimer::timeout, this, &HGMarkdownHighlighter::timerTimeout); + + static const int completeWaitTime = 500; + m_completeTimer = new QTimer(this); + m_completeTimer->setSingleShot(true); + m_completeTimer->setInterval(completeWaitTime); + connect(m_completeTimer, &QTimer::timeout, + this, &HGMarkdownHighlighter::highlightCompleted); + connect(document, &QTextDocument::contentsChange, this, &HGMarkdownHighlighter::handleContentChange); } @@ -83,6 +92,12 @@ void HGMarkdownHighlighter::highlightBlock(const QString &text) // We use PEG Markdown Highlight as the main highlighter. // We can use other highlighting methods to complement it. + // If it is a block inside HTML comment, just skip it. + if (isBlockInsideCommentRegion(currentBlock())) { + setCurrentBlockState(HighlightBlockState::Comment); + goto exit; + } + // PEG Markdown Highlight does not handle the ``` code block correctly. setCurrentBlockState(HighlightBlockState::Normal); highlightCodeBlock(text); @@ -123,6 +138,9 @@ void HGMarkdownHighlighter::highlightBlock(const QString &text) } } } + +exit: + highlightChanged(); } void HGMarkdownHighlighter::initBlockHighlightFromResult(int nrBlocks) @@ -142,6 +160,8 @@ void HGMarkdownHighlighter::initBlockHighlightFromResult(int nrBlocks) pmh_element *elem_cursor = result[style.type]; while (elem_cursor != NULL) { + // elem_cursor->pos and elem_cursor->end is the start + // and end position of the element in document. if (elem_cursor->end <= elem_cursor->pos) { elem_cursor = elem_cursor->next; continue; @@ -150,9 +170,29 @@ void HGMarkdownHighlighter::initBlockHighlightFromResult(int nrBlocks) elem_cursor = elem_cursor->next; } } +} - pmh_free_elements(result); - result = NULL; +void HGMarkdownHighlighter::initHtmlCommentRegionsFromResult() +{ + m_commentRegions.clear(); + + if (!result) { + return; + } + + pmh_element *elem = result[pmh_COMMENT]; + while (elem != NULL) { + if (elem->end <= elem->pos) { + elem = elem->next; + continue; + } + + m_commentRegions.push_back(VCommentRegion(elem->pos, elem->end)); + + elem = elem->next; + } + + qDebug() << "highlighter:" << m_commentRegions.size() << "HTML comment regions"; } void HGMarkdownHighlighter::initBlockHighlihgtOne(unsigned long pos, unsigned long end, int styleIndex) @@ -249,7 +289,16 @@ void HGMarkdownHighlighter::parse() qWarning() << "HighlightingStyles is not set"; return; } + initBlockHighlightFromResult(nrBlocks); + + initHtmlCommentRegionsFromResult(); + + if (result) { + pmh_free_elements(result); + result = NULL; + } + parsing.store(0); } @@ -294,7 +343,8 @@ void HGMarkdownHighlighter::timerTimeout() if (!updateCodeBlocks()) { rehighlight(); } - emit highlightCompleted(); + + highlightChanged(); } void HGMarkdownHighlighter::updateHighlight() @@ -331,7 +381,11 @@ bool HGMarkdownHighlighter::updateCodeBlocks() // End block. inBlock = false; item.m_endBlock = block.blockNumber(); - codeBlocks.append(item); + + // See if it is a code block inside HTML comment. + if (!isBlockInsideCommentRegion(block)) { + codeBlocks.append(item); + } } } else { int idx = codeBlockStartExp.indexIn(text); @@ -427,3 +481,27 @@ exit: rehighlight(); } } + +bool HGMarkdownHighlighter::isBlockInsideCommentRegion(const QTextBlock &p_block) const +{ + if (!p_block.isValid()) { + return false; + } + + int start = p_block.position(); + int end = start + p_block.length(); + + for (auto const & reg : m_commentRegions) { + if (reg.contains(start) && reg.contains(end)) { + return true; + } + } + + return false; +} + +void HGMarkdownHighlighter::highlightChanged() +{ + m_completeTimer->stop(); + m_completeTimer->start(); +} diff --git a/src/hgmarkdownhighlighter.h b/src/hgmarkdownhighlighter.h index 927b7c1f..f77ce2b9 100644 --- a/src/hgmarkdownhighlighter.h +++ b/src/hgmarkdownhighlighter.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include extern "C" { #include @@ -26,7 +26,12 @@ struct HighlightingStyle enum HighlightBlockState { Normal = 0, - CodeBlock = 1, + + // A fenced code block. + CodeBlock, + + // This block is inside a HTML comment region. + Comment }; // One continuous region for a certain markdown highlight style @@ -76,13 +81,33 @@ struct HLUnitPos QString m_style; }; +// HTML comment. +struct VCommentRegion +{ + VCommentRegion() : m_startPos(0), m_endPos(0) {} + + VCommentRegion(int p_start, int p_end) : m_startPos(p_start), m_endPos(p_end) {} + + // The start position of the region in document. + int m_startPos; + + // The end position of the region in document. + int m_endPos; + + // Whether this region contains @p_pos. + bool contains(int p_pos) const + { + return m_startPos <= p_pos && m_endPos >= p_pos; + } +}; + class HGMarkdownHighlighter : public QSyntaxHighlighter { Q_OBJECT public: HGMarkdownHighlighter(const QVector &styles, - const QMap &codeBlockStyles, + const QHash &codeBlockStyles, int waitInterval, QTextDocument *parent = 0); ~HGMarkdownHighlighter(); @@ -112,7 +137,7 @@ private: QTextDocument *document; QVector highlightingStyles; - QMap m_codeBlockStyles; + QHash m_codeBlockStyles; QVector > blockHighlights; // Use another member to store the codeblocks highlights, because the highlight @@ -123,6 +148,12 @@ private: int m_numOfCodeBlockHighlightsToRecv; + // All HTML comment regions. + QVector m_commentRegions; + + // Timer to signal highlightCompleted(). + QTimer *m_completeTimer; + QAtomicInt parsing; QTimer *timer; int waitInterval; @@ -145,6 +176,15 @@ private: // Return true if there are fenced code blocks and it will call rehighlight() later. // Return false if there is none. bool updateCodeBlocks(); + + // Fetch all the HTML comment regions from parsing result. + void initHtmlCommentRegionsFromResult(); + + // Whether @p_block is totally inside a HTML comment. + bool isBlockInsideCommentRegion(const QTextBlock &p_block) const; + + // Highlights have been changed. Try to signal highlightCompleted(). + void highlightChanged(); }; #endif diff --git a/src/vconfigmanager.h b/src/vconfigmanager.h index 40378406..cffceb07 100644 --- a/src/vconfigmanager.h +++ b/src/vconfigmanager.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "vnotebook.h" #include "hgmarkdownhighlighter.h" #include "vmarkdownconverter.h" @@ -63,7 +64,7 @@ public: inline QVector getMdHighlightingStyles() const; - inline QMap getCodeBlockStyles() const; + inline QHash getCodeBlockStyles() const; inline QString getWelcomePagePath() const; @@ -231,7 +232,7 @@ private: QFont mdEditFont; QPalette mdEditPalette; QVector mdHighlightingStyles; - QMap m_codeBlockStyles; + QHash m_codeBlockStyles; QString welcomePagePath; QString m_templateCss; QString m_editorStyle; @@ -360,7 +361,7 @@ inline QVector VConfigManager::getMdHighlightingStyles() cons return mdHighlightingStyles; } -inline QMap VConfigManager::getCodeBlockStyles() const +inline QHash VConfigManager::getCodeBlockStyles() const { return m_codeBlockStyles; } diff --git a/src/vmdtab.cpp b/src/vmdtab.cpp index 760325a8..d6aec63b 100644 --- a/src/vmdtab.cpp +++ b/src/vmdtab.cpp @@ -490,6 +490,10 @@ void VMdTab::updateTocFromHeaders(const QVector &p_headers) m_toc.m_file = m_file; m_toc.valid = true; + // Clear current header. + m_curHeader = VAnchor(m_file, "", -1, -1); + emit curHeaderChanged(m_curHeader); + emit outlineChanged(m_toc); } diff --git a/src/vstyleparser.cpp b/src/vstyleparser.cpp index 5b2ded79..ec3de84e 100644 --- a/src/vstyleparser.cpp +++ b/src/vstyleparser.cpp @@ -130,9 +130,9 @@ QVector VStyleParser::fetchMarkdownStyles(const QFont &baseFo return styles; } -QMap VStyleParser::fetchCodeBlockStyles(const QFont & p_baseFont) const +QHash VStyleParser::fetchCodeBlockStyles(const QFont & p_baseFont) const { - QMap styles; + QHash styles; pmh_style_attribute *attrs = markdownStyles->element_styles[pmh_VERBATIM]; diff --git a/src/vstyleparser.h b/src/vstyleparser.h index 1152c009..4f2be691 100644 --- a/src/vstyleparser.h +++ b/src/vstyleparser.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "hgmarkdownhighlighter.h" extern "C" { @@ -26,7 +26,7 @@ public: // @styles: [rule] -> ([attr] -> value). void fetchMarkdownEditorStyles(QPalette &palette, QFont &font, QMap> &styles) const; - QMap fetchCodeBlockStyles(const QFont &p_baseFont) const; + QHash fetchCodeBlockStyles(const QFont &p_baseFont) const; private: QColor QColorFromPmhAttr(pmh_attr_argb_color *attr) const;