handle HTML comment correctly

This commit is contained in:
Le Tan 2017-06-01 22:05:02 +08:00
parent 97051badf0
commit 5b150a3634
6 changed files with 139 additions and 16 deletions

View File

@ -24,7 +24,7 @@ void HGMarkdownHighlighter::resizeBuffer(int newCap)
// Will be freeed by parent automatically // Will be freeed by parent automatically
HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector<HighlightingStyle> &styles, HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector<HighlightingStyle> &styles,
const QMap<QString, QTextCharFormat> &codeBlockStyles, const QHash<QString, QTextCharFormat> &codeBlockStyles,
int waitInterval, int waitInterval,
QTextDocument *parent) QTextDocument *parent)
: QSyntaxHighlighter(parent), highlightingStyles(styles), : QSyntaxHighlighter(parent), highlightingStyles(styles),
@ -47,10 +47,19 @@ HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector<HighlightingStyle> &s
resizeBuffer(initCapacity); resizeBuffer(initCapacity);
document = parent; document = parent;
timer = new QTimer(this); timer = new QTimer(this);
timer->setSingleShot(true); timer->setSingleShot(true);
timer->setInterval(this->waitInterval); timer->setInterval(this->waitInterval);
connect(timer, &QTimer::timeout, this, &HGMarkdownHighlighter::timerTimeout); 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, connect(document, &QTextDocument::contentsChange,
this, &HGMarkdownHighlighter::handleContentChange); this, &HGMarkdownHighlighter::handleContentChange);
} }
@ -83,6 +92,12 @@ void HGMarkdownHighlighter::highlightBlock(const QString &text)
// We use PEG Markdown Highlight as the main highlighter. // We use PEG Markdown Highlight as the main highlighter.
// We can use other highlighting methods to complement it. // 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. // PEG Markdown Highlight does not handle the ``` code block correctly.
setCurrentBlockState(HighlightBlockState::Normal); setCurrentBlockState(HighlightBlockState::Normal);
highlightCodeBlock(text); highlightCodeBlock(text);
@ -123,6 +138,9 @@ void HGMarkdownHighlighter::highlightBlock(const QString &text)
} }
} }
} }
exit:
highlightChanged();
} }
void HGMarkdownHighlighter::initBlockHighlightFromResult(int nrBlocks) void HGMarkdownHighlighter::initBlockHighlightFromResult(int nrBlocks)
@ -142,6 +160,8 @@ void HGMarkdownHighlighter::initBlockHighlightFromResult(int nrBlocks)
pmh_element *elem_cursor = result[style.type]; pmh_element *elem_cursor = result[style.type];
while (elem_cursor != NULL) 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) { if (elem_cursor->end <= elem_cursor->pos) {
elem_cursor = elem_cursor->next; elem_cursor = elem_cursor->next;
continue; continue;
@ -150,9 +170,29 @@ void HGMarkdownHighlighter::initBlockHighlightFromResult(int nrBlocks)
elem_cursor = elem_cursor->next; elem_cursor = elem_cursor->next;
} }
} }
}
pmh_free_elements(result); void HGMarkdownHighlighter::initHtmlCommentRegionsFromResult()
result = NULL; {
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) void HGMarkdownHighlighter::initBlockHighlihgtOne(unsigned long pos, unsigned long end, int styleIndex)
@ -249,7 +289,16 @@ void HGMarkdownHighlighter::parse()
qWarning() << "HighlightingStyles is not set"; qWarning() << "HighlightingStyles is not set";
return; return;
} }
initBlockHighlightFromResult(nrBlocks); initBlockHighlightFromResult(nrBlocks);
initHtmlCommentRegionsFromResult();
if (result) {
pmh_free_elements(result);
result = NULL;
}
parsing.store(0); parsing.store(0);
} }
@ -294,7 +343,8 @@ void HGMarkdownHighlighter::timerTimeout()
if (!updateCodeBlocks()) { if (!updateCodeBlocks()) {
rehighlight(); rehighlight();
} }
emit highlightCompleted();
highlightChanged();
} }
void HGMarkdownHighlighter::updateHighlight() void HGMarkdownHighlighter::updateHighlight()
@ -331,7 +381,11 @@ bool HGMarkdownHighlighter::updateCodeBlocks()
// End block. // End block.
inBlock = false; inBlock = false;
item.m_endBlock = block.blockNumber(); 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 { } else {
int idx = codeBlockStartExp.indexIn(text); int idx = codeBlockStartExp.indexIn(text);
@ -427,3 +481,27 @@ exit:
rehighlight(); 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();
}

View File

@ -7,7 +7,7 @@
#include <QSet> #include <QSet>
#include <QList> #include <QList>
#include <QString> #include <QString>
#include <QMap> #include <QHash>
extern "C" { extern "C" {
#include <pmh_parser.h> #include <pmh_parser.h>
@ -26,7 +26,12 @@ struct HighlightingStyle
enum HighlightBlockState enum HighlightBlockState
{ {
Normal = 0, 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 // One continuous region for a certain markdown highlight style
@ -76,13 +81,33 @@ struct HLUnitPos
QString m_style; 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 class HGMarkdownHighlighter : public QSyntaxHighlighter
{ {
Q_OBJECT Q_OBJECT
public: public:
HGMarkdownHighlighter(const QVector<HighlightingStyle> &styles, HGMarkdownHighlighter(const QVector<HighlightingStyle> &styles,
const QMap<QString, QTextCharFormat> &codeBlockStyles, const QHash<QString, QTextCharFormat> &codeBlockStyles,
int waitInterval, int waitInterval,
QTextDocument *parent = 0); QTextDocument *parent = 0);
~HGMarkdownHighlighter(); ~HGMarkdownHighlighter();
@ -112,7 +137,7 @@ private:
QTextDocument *document; QTextDocument *document;
QVector<HighlightingStyle> highlightingStyles; QVector<HighlightingStyle> highlightingStyles;
QMap<QString, QTextCharFormat> m_codeBlockStyles; QHash<QString, QTextCharFormat> m_codeBlockStyles;
QVector<QVector<HLUnit> > blockHighlights; QVector<QVector<HLUnit> > blockHighlights;
// Use another member to store the codeblocks highlights, because the highlight // Use another member to store the codeblocks highlights, because the highlight
@ -123,6 +148,12 @@ private:
int m_numOfCodeBlockHighlightsToRecv; int m_numOfCodeBlockHighlightsToRecv;
// All HTML comment regions.
QVector<VCommentRegion> m_commentRegions;
// Timer to signal highlightCompleted().
QTimer *m_completeTimer;
QAtomicInt parsing; QAtomicInt parsing;
QTimer *timer; QTimer *timer;
int waitInterval; int waitInterval;
@ -145,6 +176,15 @@ private:
// Return true if there are fenced code blocks and it will call rehighlight() later. // Return true if there are fenced code blocks and it will call rehighlight() later.
// Return false if there is none. // Return false if there is none.
bool updateCodeBlocks(); 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 #endif

View File

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

View File

@ -490,6 +490,10 @@ void VMdTab::updateTocFromHeaders(const QVector<VHeader> &p_headers)
m_toc.m_file = m_file; m_toc.m_file = m_file;
m_toc.valid = true; m_toc.valid = true;
// Clear current header.
m_curHeader = VAnchor(m_file, "", -1, -1);
emit curHeaderChanged(m_curHeader);
emit outlineChanged(m_toc); emit outlineChanged(m_toc);
} }

View File

@ -130,9 +130,9 @@ QVector<HighlightingStyle> VStyleParser::fetchMarkdownStyles(const QFont &baseFo
return styles; 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]; pmh_style_attribute *attrs = markdownStyles->element_styles[pmh_VERBATIM];

View File

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