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 <tamlokveer@gmail.com>
This commit is contained in:
Le Tan 2017-01-22 19:39:43 +08:00
parent 0c0fdfcbf1
commit 180ab46367
3 changed files with 46 additions and 26 deletions

View File

@ -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 <QtGui>
#include <QtDebug> #include <QtDebug>
#include "hgmarkdownhighlighter.h" #include "hgmarkdownhighlighter.h"
@ -36,9 +27,13 @@ HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector<HighlightingStyle> &s
codeBlockEndExp = QRegExp("^(\\s)*```$"); codeBlockEndExp = QRegExp("^(\\s)*```$");
codeBlockFormat.setForeground(QBrush(Qt::darkYellow)); codeBlockFormat.setForeground(QBrush(Qt::darkYellow));
for (int index = 0; index < styles.size(); ++index) { 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; 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); 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); highlightCodeBlock(text);
// PEG Markdown Highlight does not handle links with spaces in the URL.
highlightLinkWithSpacesInURL(text);
} }
void HGMarkdownHighlighter::setStyles(const QVector<HighlightingStyle> &styles) void HGMarkdownHighlighter::setStyles(const QVector<HighlightingStyle> &styles)
@ -177,7 +180,7 @@ void HGMarkdownHighlighter::highlightCodeBlock(const QString &text)
{ {
int nextIndex = 0; int nextIndex = 0;
int startIndex = 0; int startIndex = 0;
if (previousBlockState() != HighlightBlockState::BlockCodeBlock) { if (previousBlockState() != HighlightBlockState::CodeBlock) {
startIndex = codeBlockStartExp.indexIn(text); startIndex = codeBlockStartExp.indexIn(text);
if (startIndex >= 0) { if (startIndex >= 0) {
nextIndex = startIndex + codeBlockStartExp.matchedLength(); nextIndex = startIndex + codeBlockStartExp.matchedLength();
@ -190,7 +193,7 @@ void HGMarkdownHighlighter::highlightCodeBlock(const QString &text)
int endIndex = codeBlockEndExp.indexIn(text, nextIndex); int endIndex = codeBlockEndExp.indexIn(text, nextIndex);
int codeBlockLength; int codeBlockLength;
if (endIndex == -1) { if (endIndex == -1) {
setCurrentBlockState(HighlightBlockState::BlockCodeBlock); setCurrentBlockState(HighlightBlockState::CodeBlock);
codeBlockLength = text.length() - startIndex; codeBlockLength = text.length() - startIndex;
} else { } else {
codeBlockLength = endIndex - startIndex + codeBlockEndExp.matchedLength(); 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() void HGMarkdownHighlighter::parse()
{ {
if (!parsing.testAndSetRelaxed(0, 1)) { if (!parsing.testAndSetRelaxed(0, 1)) {

View File

@ -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 #ifndef HGMARKDOWNHIGHLIGHTER_H
#define HGMARKDOWNHIGHLIGHTER_H #define HGMARKDOWNHIGHLIGHTER_H
@ -31,8 +22,8 @@ struct HighlightingStyle
enum HighlightBlockState enum HighlightBlockState
{ {
BlockNormal = 0, Normal = 0,
BlockCodeBlock = 1, CodeBlock = 1,
}; };
// One continuous region for a certain markdown highlight style // One continuous region for a certain markdown highlight style
@ -74,6 +65,8 @@ private:
QRegExp codeBlockStartExp; QRegExp codeBlockStartExp;
QRegExp codeBlockEndExp; QRegExp codeBlockEndExp;
QTextCharFormat codeBlockFormat; QTextCharFormat codeBlockFormat;
QTextCharFormat m_linkFormat;
QTextCharFormat m_imageFormat;
QTextDocument *document; QTextDocument *document;
QVector<HighlightingStyle> highlightingStyles; QVector<HighlightingStyle> highlightingStyles;
@ -92,6 +85,7 @@ private:
void resizeBuffer(int newCap); void resizeBuffer(int newCap);
void highlightCodeBlock(const QString &text); void highlightCodeBlock(const QString &text);
void highlightLinkWithSpacesInURL(const QString &p_text);
void parse(); void parse();
void parseInternal(); void parseInternal();
void initBlockHighlightFromResult(int nrBlocks); void initBlockHighlightFromResult(int nrBlocks);

View File

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