Browse Source

bugfix: highlight links and images with spaces in URL

It is said that URL should not contain spaces. Anyway, we use regular
expression syntax highlighting to complement PEG Markdown Highlight.

Signed-off-by: Le Tan <[email protected]>
Le Tan 8 years ago
parent
commit
180ab46367
3 changed files with 46 additions and 26 deletions
  1. 40 14
      src/hgmarkdownhighlighter.cpp
  2. 5 11
      src/hgmarkdownhighlighter.h
  3. 1 1
      src/vmdedit.cpp

+ 40 - 14
src/hgmarkdownhighlighter.cpp

@@ -1,12 +1,3 @@
-/* PEG Markdown Highlight
- * Copyright 2011-2016 Ali Rantakari -- http://hasseg.org
- * Licensed under the GPL2+ and MIT licenses (see LICENSE for more info).
- * 
- * highlighter.cpp
- * 
- * Qt 4.7 example for highlighting a rich text widget.
- */
-
 #include <QtGui>
 #include <QtDebug>
 #include "hgmarkdownhighlighter.h"
@@ -36,9 +27,13 @@ HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector<HighlightingStyle> &s
     codeBlockEndExp = QRegExp("^(\\s)*```$");
     codeBlockFormat.setForeground(QBrush(Qt::darkYellow));
     for (int index = 0; index < styles.size(); ++index) {
-        if (styles[index].type == pmh_VERBATIM) {
+        const pmh_element_type &eleType = styles[index].type;
+        if (eleType == pmh_VERBATIM) {
             codeBlockFormat = styles[index].format;
-            break;
+        } else if (eleType == pmh_LINK) {
+            m_linkFormat = styles[index].format;
+        } else if (eleType == pmh_IMAGE) {
+            m_imageFormat = styles[index].format;
         }
     }
 
@@ -77,8 +72,16 @@ void HGMarkdownHighlighter::highlightBlock(const QString &text)
             setFormat(unit.start, unit.length, highlightingStyles[unit.styleIndex].format);
         }
     }
-    setCurrentBlockState(HighlightBlockState::BlockNormal);
+
+    // We use PEG Markdown Highlight as the main highlighter.
+    // We can use other highlighting methods to complement it.
+
+    // PEG Markdown Highlight does not handle the ``` code block correctly.
+    setCurrentBlockState(HighlightBlockState::Normal);
     highlightCodeBlock(text);
+
+    // PEG Markdown Highlight does not handle links with spaces in the URL.
+    highlightLinkWithSpacesInURL(text);
 }
 
 void HGMarkdownHighlighter::setStyles(const QVector<HighlightingStyle> &styles)
@@ -177,7 +180,7 @@ void HGMarkdownHighlighter::highlightCodeBlock(const QString &text)
 {
     int nextIndex = 0;
     int startIndex = 0;
-    if (previousBlockState() != HighlightBlockState::BlockCodeBlock) {
+    if (previousBlockState() != HighlightBlockState::CodeBlock) {
         startIndex = codeBlockStartExp.indexIn(text);
         if (startIndex >= 0) {
             nextIndex = startIndex + codeBlockStartExp.matchedLength();
@@ -190,7 +193,7 @@ void HGMarkdownHighlighter::highlightCodeBlock(const QString &text)
         int endIndex = codeBlockEndExp.indexIn(text, nextIndex);
         int codeBlockLength;
         if (endIndex == -1) {
-            setCurrentBlockState(HighlightBlockState::BlockCodeBlock);
+            setCurrentBlockState(HighlightBlockState::CodeBlock);
             codeBlockLength = text.length() - startIndex;
         } else {
             codeBlockLength = endIndex - startIndex + codeBlockEndExp.matchedLength();
@@ -205,6 +208,29 @@ void HGMarkdownHighlighter::highlightCodeBlock(const QString &text)
     }
 }
 
+void HGMarkdownHighlighter::highlightLinkWithSpacesInURL(const QString &p_text)
+{
+    if (currentBlockState() == HighlightBlockState::CodeBlock) {
+        return;
+    }
+    // TODO: should select links with spaces in URL.
+    QRegExp regExp("[\\!]?\\[[^\\]]*\\]\\(([^\\n\\)]+)\\)");
+    int index = regExp.indexIn(p_text);
+    while (index >= 0) {
+        Q_ASSERT(regExp.captureCount() == 1);
+        int length = regExp.matchedLength();
+        const QString &capturedText = regExp.capturedTexts()[1];
+        if (capturedText.contains(' ')) {
+            if (p_text[index] == '!' && m_imageFormat.isValid()) {
+                setFormat(index, length, m_imageFormat);
+            } else if (m_linkFormat.isValid()) {
+                setFormat(index, length, m_linkFormat);
+            }
+        }
+        index = regExp.indexIn(p_text, index + length);
+    }
+}
+
 void HGMarkdownHighlighter::parse()
 {
     if (!parsing.testAndSetRelaxed(0, 1)) {

+ 5 - 11
src/hgmarkdownhighlighter.h

@@ -1,12 +1,3 @@
-/* PEG Markdown Highlight
- * Copyright 2011-2016 Ali Rantakari -- http://hasseg.org
- * Licensed under the GPL2+ and MIT licenses (see LICENSE for more info).
- * 
- * highlighter.h
- * 
- * Qt 4.7 example for highlighting a rich text widget.
- */
-
 #ifndef HGMARKDOWNHIGHLIGHTER_H
 #define HGMARKDOWNHIGHLIGHTER_H
 
@@ -31,8 +22,8 @@ struct HighlightingStyle
 
 enum HighlightBlockState
 {
-    BlockNormal = 0,
-    BlockCodeBlock = 1,
+    Normal = 0,
+    CodeBlock = 1,
 };
 
 // One continuous region for a certain markdown highlight style
@@ -74,6 +65,8 @@ private:
     QRegExp codeBlockStartExp;
     QRegExp codeBlockEndExp;
     QTextCharFormat codeBlockFormat;
+    QTextCharFormat m_linkFormat;
+    QTextCharFormat m_imageFormat;
 
     QTextDocument *document;
     QVector<HighlightingStyle> highlightingStyles;
@@ -92,6 +85,7 @@ private:
 
     void resizeBuffer(int newCap);
     void highlightCodeBlock(const QString &text);
+    void highlightLinkWithSpacesInURL(const QString &p_text);
     void parse();
     void parseInternal();
     void initBlockHighlightFromResult(int nrBlocks);

+ 1 - 1
src/vmdedit.cpp

@@ -204,7 +204,7 @@ void VMdEdit::generateEditOutline()
     QRegExp headerReg("(#{1,6})\\s*(\\S.*)");  // Need to trim the spaces
     for (QTextBlock block = doc->begin(); block != doc->end(); block = block.next()) {
         Q_ASSERT(block.lineCount() == 1);
-        if ((block.userState() == HighlightBlockState::BlockNormal) &&
+        if ((block.userState() == HighlightBlockState::Normal) &&
             headerReg.exactMatch(block.text())) {
             VHeader header(headerReg.cap(1).length(),
                            headerReg.cap(2).trimmed(), "", block.firstLineNumber());