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
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;
}
}
}
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();
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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];

View File

@ -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;