Browse Source

handle HTML comment correctly

Le Tan 8 years ago
parent
commit
5b150a3634
6 changed files with 139 additions and 16 deletions
  1. 83 5
      src/hgmarkdownhighlighter.cpp
  2. 44 4
      src/hgmarkdownhighlighter.h
  3. 4 3
      src/vconfigmanager.h
  4. 4 0
      src/vmdtab.cpp
  5. 2 2
      src/vstyleparser.cpp
  6. 2 2
      src/vstyleparser.h

+ 83 - 5
src/hgmarkdownhighlighter.cpp

@@ -24,7 +24,7 @@ void HGMarkdownHighlighter::resizeBuffer(int newCap)
 
 // Will be freeed by parent automatically
 HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector<HighlightingStyle> &styles,
-                                             const QMap<QString, QTextCharFormat> &codeBlockStyles,
+                                             const QHash<QString, QTextCharFormat> &codeBlockStyles,
                                              int waitInterval,
                                              QTextDocument *parent)
     : QSyntaxHighlighter(parent), highlightingStyles(styles),
@@ -47,10 +47,19 @@ HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector<HighlightingStyle> &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;
         }
     }
+}
+
+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;
+    }
 
-    pmh_free_elements(result);
-    result = NULL;
+    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();
+}

+ 44 - 4
src/hgmarkdownhighlighter.h

@@ -7,7 +7,7 @@
 #include <QSet>
 #include <QList>
 #include <QString>
-#include <QMap>
+#include <QHash>
 
 extern "C" {
 #include <pmh_parser.h>
@@ -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<HighlightingStyle> &styles,
-                          const QMap<QString, QTextCharFormat> &codeBlockStyles,
+                          const QHash<QString, QTextCharFormat> &codeBlockStyles,
                           int waitInterval,
                           QTextDocument *parent = 0);
     ~HGMarkdownHighlighter();
@@ -112,7 +137,7 @@ private:
 
     QTextDocument *document;
     QVector<HighlightingStyle> highlightingStyles;
-    QMap<QString, QTextCharFormat> m_codeBlockStyles;
+    QHash<QString, QTextCharFormat> m_codeBlockStyles;
     QVector<QVector<HLUnit> > 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<VCommentRegion> 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

+ 4 - 3
src/vconfigmanager.h

@@ -5,6 +5,7 @@
 #include <QPalette>
 #include <QVector>
 #include <QSettings>
+#include <QHash>
 #include "vnotebook.h"
 #include "hgmarkdownhighlighter.h"
 #include "vmarkdownconverter.h"
@@ -63,7 +64,7 @@ public:
 
     inline QVector<HighlightingStyle> getMdHighlightingStyles() const;
 
-    inline QMap<QString, QTextCharFormat> getCodeBlockStyles() const;
+    inline QHash<QString, QTextCharFormat> getCodeBlockStyles() const;
 
     inline QString getWelcomePagePath() const;
 
@@ -231,7 +232,7 @@ private:
     QFont mdEditFont;
     QPalette mdEditPalette;
     QVector<HighlightingStyle> mdHighlightingStyles;
-    QMap<QString, QTextCharFormat> m_codeBlockStyles;
+    QHash<QString, QTextCharFormat> m_codeBlockStyles;
     QString welcomePagePath;
     QString m_templateCss;
     QString m_editorStyle;
@@ -360,7 +361,7 @@ inline QVector<HighlightingStyle> VConfigManager::getMdHighlightingStyles() cons
     return mdHighlightingStyles;
 }
 
-inline QMap<QString, QTextCharFormat> VConfigManager::getCodeBlockStyles() const
+inline QHash<QString, QTextCharFormat> VConfigManager::getCodeBlockStyles() const
 {
     return m_codeBlockStyles;
 }

+ 4 - 0
src/vmdtab.cpp

@@ -490,6 +490,10 @@ void VMdTab::updateTocFromHeaders(const QVector<VHeader> &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);
 }
 

+ 2 - 2
src/vstyleparser.cpp

@@ -130,9 +130,9 @@ QVector<HighlightingStyle> VStyleParser::fetchMarkdownStyles(const QFont &baseFo
     return styles;
 }
 
-QMap<QString, QTextCharFormat> VStyleParser::fetchCodeBlockStyles(const QFont & p_baseFont) const
+QHash<QString, QTextCharFormat> VStyleParser::fetchCodeBlockStyles(const QFont & p_baseFont) const
 {
-    QMap<QString, QTextCharFormat> styles;
+    QHash<QString, QTextCharFormat> styles;
 
     pmh_style_attribute *attrs = markdownStyles->element_styles[pmh_VERBATIM];
 

+ 2 - 2
src/vstyleparser.h

@@ -4,7 +4,7 @@
 #include <QPalette>
 #include <QVector>
 #include <QString>
-#include <QMap>
+#include <QHash>
 #include "hgmarkdownhighlighter.h"
 
 extern "C" {
@@ -26,7 +26,7 @@ public:
     // @styles: [rule] -> ([attr] -> value).
     void fetchMarkdownEditorStyles(QPalette &palette, QFont &font,
                                    QMap<QString, QMap<QString, QString>> &styles) const;
-    QMap<QString, QTextCharFormat> fetchCodeBlockStyles(const QFont &p_baseFont) const;
+    QHash<QString, QTextCharFormat> fetchCodeBlockStyles(const QFont &p_baseFont) const;
 
 private:
     QColor QColorFromPmhAttr(pmh_attr_argb_color *attr) const;