PegMarkdownHighlighter: multi-threads highlighter support

This commit is contained in:
Le Tan 2018-07-12 20:19:23 +08:00
parent fbfc6c1dd6
commit bb308a06d1
26 changed files with 1634 additions and 259 deletions

View File

@ -29,6 +29,7 @@ HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector<HighlightingStyle> &s
int waitInterval, int waitInterval,
QTextDocument *parent) QTextDocument *parent)
: QSyntaxHighlighter(parent), : QSyntaxHighlighter(parent),
m_timeStamp(0),
highlightingStyles(styles), highlightingStyles(styles),
m_codeBlockStyles(codeBlockStyles), m_codeBlockStyles(codeBlockStyles),
m_numOfCodeBlockHighlightsToRecv(0), m_numOfCodeBlockHighlightsToRecv(0),
@ -864,9 +865,9 @@ void HGMarkdownHighlighter::handleContentChange(int /* position */, int charsRem
return; return;
} }
m_signalOut = false; ++m_timeStamp;
timer->stop(); m_signalOut = false;
timer->start(); timer->start();
} }

View File

@ -1,7 +1,6 @@
#ifndef HGMARKDOWNHIGHLIGHTER_H #ifndef HGMARKDOWNHIGHLIGHTER_H
#define HGMARKDOWNHIGHLIGHTER_H #define HGMARKDOWNHIGHLIGHTER_H
#include <QTextCharFormat>
#include <QSyntaxHighlighter> #include <QSyntaxHighlighter>
#include <QAtomicInt> #include <QAtomicInt>
#include <QMap> #include <QMap>
@ -9,177 +8,10 @@
#include <QString> #include <QString>
#include "vtextblockdata.h" #include "vtextblockdata.h"
#include "vconstants.h" #include "markdownhighlighterdata.h"
extern "C" {
#include <pmh_parser.h>
}
QT_BEGIN_NAMESPACE
class QTextDocument; class QTextDocument;
QT_END_NAMESPACE
struct HighlightingStyle
{
pmh_element_type type;
QTextCharFormat format;
};
// One continuous region for a certain markdown highlight style
// within a QTextBlock.
// Pay attention to the change of HighlightingStyles[]
struct HLUnit
{
// Highlight offset @start and @length with style HighlightingStyles[styleIndex]
// within a QTextBlock
unsigned long start;
unsigned long length;
unsigned int styleIndex;
};
struct HLUnitStyle
{
unsigned long start;
unsigned long length;
QString style;
};
// Fenced code block only.
struct VCodeBlock
{
// Global position of the start.
int m_startPos;
int m_startBlock;
int m_endBlock;
QString m_lang;
QString m_text;
bool equalContent(const VCodeBlock &p_block) const
{
return p_block.m_lang == m_lang && p_block.m_text == m_text;
}
void updateNonContent(const VCodeBlock &p_block)
{
m_startPos = p_block.m_startPos;
m_startBlock = p_block.m_startBlock;
m_endBlock = p_block.m_endBlock;
}
};
struct VMathjaxBlock
{
VMathjaxBlock()
: m_blockNumber(-1),
m_previewedAsBlock(false),
m_index(-1),
m_length(-1)
{
}
VMathjaxBlock(int p_blockNumber, const MathjaxInfo &p_info)
: m_blockNumber(p_blockNumber),
m_previewedAsBlock(p_info.m_previewedAsBlock),
m_index(p_info.m_index),
m_length(p_info.m_length),
m_text(p_info.m_text)
{
}
bool equalContent(const VMathjaxBlock &p_block) const
{
return m_text == p_block.m_text;
}
void updateNonContent(const VMathjaxBlock &p_block)
{
m_blockNumber = p_block.m_blockNumber;
m_previewedAsBlock = p_block.m_previewedAsBlock;
m_index = p_block.m_index;
m_length = p_block.m_length;
}
int m_blockNumber;
bool m_previewedAsBlock;
// Start index within the block.
int m_index;
int m_length;
QString m_text;
};
// Highlight unit with global position and string style name.
struct HLUnitPos
{
HLUnitPos() : m_position(-1), m_length(-1)
{
}
HLUnitPos(int p_position, int p_length, const QString &p_style)
: m_position(p_position), m_length(p_length), m_style(p_style)
{
}
int m_position;
int m_length;
QString m_style;
};
// Denote the region of a certain Markdown element.
struct VElementRegion
{
VElementRegion() : m_startPos(0), m_endPos(0) {}
VElementRegion(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;
}
bool intersect(int p_start, int p_end) const
{
return !(p_end <= m_startPos || p_start >= m_endPos);
}
bool operator==(const VElementRegion &p_other) const
{
return (m_startPos == p_other.m_startPos
&& m_endPos == p_other.m_endPos);
}
bool operator<(const VElementRegion &p_other) const
{
if (m_startPos < p_other.m_startPos) {
return true;
} else if (m_startPos == p_other.m_startPos) {
// If a < b is true, then b < a must be false.
return m_endPos < p_other.m_endPos;
} else {
return false;
}
}
QString toString() const
{
return QString("[%1,%2)").arg(m_startPos).arg(m_endPos);
}
};
class HGMarkdownHighlighter : public QSyntaxHighlighter class HGMarkdownHighlighter : public QSyntaxHighlighter
{ {
@ -195,8 +27,6 @@ public:
// Request to update highlihgt (re-parse and re-highlight) // Request to update highlihgt (re-parse and re-highlight)
void setCodeBlockHighlights(const QVector<HLUnitPos> &p_units); void setCodeBlockHighlights(const QVector<HLUnitPos> &p_units);
const QMap<int, bool> &getPotentialPreviewBlocks() const;
const QVector<VElementRegion> &getHeaderRegions() const; const QVector<VElementRegion> &getHeaderRegions() const;
const QSet<int> &getPossiblePreviewBlocks() const; const QSet<int> &getPossiblePreviewBlocks() const;
@ -259,6 +89,8 @@ private:
int m_length; int m_length;
}; };
TimeStamp m_timeStamp;
QRegExp codeBlockStartExp; QRegExp codeBlockStartExp;
QRegExp codeBlockEndExp; QRegExp codeBlockEndExp;

View File

@ -1,4 +1,182 @@
#ifndef MARKDOWNHIGHLIGHTERDATA_H #ifndef MARKDOWNHIGHLIGHTERDATA_H
#define MARKDOWNHIGHLIGHTERDATA_H #define MARKDOWNHIGHLIGHTERDATA_H
#include <QTextCharFormat>
#include "vconstants.h"
#include "vtextblockdata.h"
extern "C" {
#include <pmh_parser.h>
}
struct HighlightingStyle
{
pmh_element_type type;
QTextCharFormat format;
};
// One continuous region for a certain markdown highlight style
// within a QTextBlock.
// Pay attention to the change of HighlightingStyles[]
struct HLUnit
{
// Highlight offset @start and @length with style HighlightingStyles[styleIndex]
// within a QTextBlock
unsigned long start;
unsigned long length;
unsigned int styleIndex;
};
struct HLUnitStyle
{
unsigned long start;
unsigned long length;
QString style;
};
// Fenced code block only.
struct VCodeBlock
{
// Global position of the start.
int m_startPos;
int m_startBlock;
int m_endBlock;
QString m_lang;
QString m_text;
bool equalContent(const VCodeBlock &p_block) const
{
return p_block.m_lang == m_lang && p_block.m_text == m_text;
}
void updateNonContent(const VCodeBlock &p_block)
{
m_startPos = p_block.m_startPos;
m_startBlock = p_block.m_startBlock;
m_endBlock = p_block.m_endBlock;
}
};
struct VMathjaxBlock
{
VMathjaxBlock()
: m_blockNumber(-1),
m_previewedAsBlock(false),
m_index(-1),
m_length(-1)
{
}
VMathjaxBlock(int p_blockNumber, const MathjaxInfo &p_info)
: m_blockNumber(p_blockNumber),
m_previewedAsBlock(p_info.m_previewedAsBlock),
m_index(p_info.m_index),
m_length(p_info.m_length),
m_text(p_info.m_text)
{
}
bool equalContent(const VMathjaxBlock &p_block) const
{
return m_text == p_block.m_text;
}
void updateNonContent(const VMathjaxBlock &p_block)
{
m_blockNumber = p_block.m_blockNumber;
m_previewedAsBlock = p_block.m_previewedAsBlock;
m_index = p_block.m_index;
m_length = p_block.m_length;
}
int m_blockNumber;
bool m_previewedAsBlock;
// Start index within the block.
int m_index;
int m_length;
QString m_text;
};
// Highlight unit with global position and string style name.
struct HLUnitPos
{
HLUnitPos() : m_position(-1), m_length(-1)
{
}
HLUnitPos(int p_position, int p_length, const QString &p_style)
: m_position(p_position), m_length(p_length), m_style(p_style)
{
}
int m_position;
int m_length;
QString m_style;
};
// Denote the region of a certain Markdown element.
struct VElementRegion
{
VElementRegion() : m_startPos(0), m_endPos(0) {}
VElementRegion(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;
}
bool intersect(int p_start, int p_end) const
{
return !(p_end <= m_startPos || p_start >= m_endPos);
}
bool operator==(const VElementRegion &p_other) const
{
return (m_startPos == p_other.m_startPos
&& m_endPos == p_other.m_endPos);
}
bool operator<(const VElementRegion &p_other) const
{
if (m_startPos < p_other.m_startPos) {
return true;
} else if (m_startPos == p_other.m_startPos) {
// If a < b is true, then b < a must be false.
return m_endPos < p_other.m_endPos;
} else {
return false;
}
}
QString toString() const
{
return QString("[%1,%2)").arg(m_startPos).arg(m_endPos);
}
};
struct PegHighlightResult
{
TimeStamp m_timeStamp;
QVector<QVector<HLUnit> > m_blockHighlights;
};
#endif // MARKDOWNHIGHLIGHTERDATA_H #endif // MARKDOWNHIGHLIGHTERDATA_H

View File

@ -0,0 +1,223 @@
#include "peghighlighterresult.h"
#include <QTextDocument>
#include <QTextBlock>
#include "pegmarkdownhighlighter.h"
#include "utils/vutils.h"
PegHighlighterResult::PegHighlighterResult()
: m_timeStamp(0),
m_numOfBlocks(0),
m_numOfCodeBlockHighlightsToRecv(0)
{
m_codeBlockStartExp = QRegExp(VUtils::c_fencedCodeBlockStartRegExp);
m_codeBlockEndExp = QRegExp(VUtils::c_fencedCodeBlockEndRegExp);
}
PegHighlighterResult::PegHighlighterResult(const PegMarkdownHighlighter *p_peg,
const QSharedPointer<PegParseResult> &p_result)
: m_timeStamp(p_result->m_timeStamp),
m_numOfBlocks(p_result->m_numOfBlocks),
m_numOfCodeBlockHighlightsToRecv(0)
{
m_codeBlockStartExp = QRegExp(VUtils::c_fencedCodeBlockStartRegExp);
m_codeBlockEndExp = QRegExp(VUtils::c_fencedCodeBlockEndRegExp);
parseBlocksHighlights(p_peg, p_result);
// Implicit sharing.
m_imageRegions = p_result->m_imageRegions;
m_headerRegions = p_result->m_headerRegions;
parseFencedCodeBlocks(p_peg, p_result);
}
static bool compHLUnit(const HLUnit &p_a, const HLUnit &p_b)
{
if (p_a.start < p_b.start) {
return true;
} else if (p_a.start == p_b.start) {
return p_a.length > p_b.length;
} else {
return false;
}
}
void PegHighlighterResult::parseBlocksHighlights(const PegMarkdownHighlighter *p_peg,
const QSharedPointer<PegParseResult> &p_result)
{
m_blocksHighlights.resize(m_numOfBlocks);
if (p_result->isEmpty()) {
return;
}
const QTextDocument *doc = p_peg->getDocument();
const QVector<HighlightingStyle> &styles = p_peg->getStyles();
auto pmhResult = p_result->m_pmhElements;
for (int i = 0; i < styles.size(); i++)
{
const HighlightingStyle &style = styles[i];
pmh_element *elem_cursor = pmhResult[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;
}
parseBlocksHighlightOne(doc, elem_cursor->pos, elem_cursor->end, i);
elem_cursor = elem_cursor->next;
}
}
// Sort m_blocksHighlights.
for (int i = 0; i < m_blocksHighlights.size(); ++i) {
if (m_blocksHighlights[i].size() > 1) {
std::sort(m_blocksHighlights[i].begin(), m_blocksHighlights[i].end(), compHLUnit);
}
}
}
void PegHighlighterResult::parseBlocksHighlightOne(const QTextDocument *p_doc,
unsigned long p_pos,
unsigned long p_end,
int p_styleIndex)
{
// When the the highlight element is at the end of document, @p_end will equals
// to the characterCount.
unsigned int nrChar = (unsigned int)p_doc->characterCount();
if (p_end >= nrChar && nrChar > 0) {
p_end = nrChar - 1;
}
QTextBlock block = p_doc->findBlock(p_pos);
int startBlockNum = block.blockNumber();
int endBlockNum = p_doc->findBlock(p_end).blockNumber();
while (block.isValid())
{
int blockNum = block.blockNumber();
if (blockNum > endBlockNum) {
break;
}
int blockStartPos = block.position();
HLUnit unit;
if (blockNum == startBlockNum) {
unit.start = p_pos - blockStartPos;
unit.length = (startBlockNum == endBlockNum) ?
(p_end - p_pos) : (block.length() - unit.start);
} else if (blockNum == endBlockNum) {
unit.start = 0;
unit.length = p_end - blockStartPos;
} else {
unit.start = 0;
unit.length = block.length();
}
unit.styleIndex = p_styleIndex;
m_blocksHighlights[blockNum].append(unit);
block = block.next();
}
}
void PegHighlighterResult::parseBlocksElementRegionOne(QHash<int, QVector<VElementRegion>> &p_regs,
const QTextDocument *p_doc,
unsigned long p_pos,
unsigned long p_end)
{
// When the the highlight element is at the end of document, @p_end will equals
// to the characterCount.
unsigned int nrChar = (unsigned int)p_doc->characterCount();
if (p_end >= nrChar && nrChar > 0) {
p_end = nrChar - 1;
}
QTextBlock block = p_doc->findBlock(p_pos);
int startBlockNum = block.blockNumber();
int endBlockNum = p_doc->findBlock(p_end).blockNumber();
while (block.isValid())
{
int blockNum = block.blockNumber();
if (blockNum > endBlockNum) {
break;
}
int blockStartPos = block.position();
QVector<VElementRegion> &regs = p_regs[blockNum];
int start, end;
if (blockNum == startBlockNum) {
start = p_pos - blockStartPos;
end = (startBlockNum == endBlockNum) ? (p_end - blockStartPos)
: block.length();
} else if (blockNum == endBlockNum) {
start = 0;
end = p_end - blockStartPos;
} else {
start = 0;
end = block.length();
}
regs.append(VElementRegion(start, end));
}
}
void PegHighlighterResult::parseFencedCodeBlocks(const PegMarkdownHighlighter *p_peg,
const QSharedPointer<PegParseResult> &p_result)
{
const QMap<int, VElementRegion> &regs = p_result->m_codeBlockRegions;
const QTextDocument *doc = p_peg->getDocument();
VCodeBlock item;
bool inBlock = false;
for (auto it = regs.begin(); it != regs.end(); ++it) {
QTextBlock block = doc->findBlock(it.value().m_startPos);
int lastBlock = doc->findBlock(it.value().m_endPos - 1).blockNumber();
while (block.isValid()) {
int blockNumber = block.blockNumber();
if (blockNumber > lastBlock) {
break;
}
HighlightBlockState state = HighlightBlockState::Normal;
QString text = block.text();
if (inBlock) {
item.m_text = item.m_text + "\n" + text;
int idx = m_codeBlockEndExp.indexIn(text);
if (idx >= 0) {
// End block.
inBlock = false;
state = HighlightBlockState::CodeBlockEnd;
item.m_endBlock = blockNumber;
m_codeBlocks.append(item);
} else {
// Within code block.
state = HighlightBlockState::CodeBlock;
}
} else {
int idx = m_codeBlockStartExp.indexIn(text);
if (idx >= 0) {
// Start block.
inBlock = true;
state = HighlightBlockState::CodeBlockStart;
item.m_startBlock = blockNumber;
item.m_startPos = block.position();
item.m_text = text;
if (m_codeBlockStartExp.captureCount() == 2) {
item.m_lang = m_codeBlockStartExp.capturedTexts()[2];
}
}
}
if (state != HighlightBlockState::Normal) {
m_codeBlocksState.insert(blockNumber, state);
}
block = block.next();
}
}
}

View File

@ -0,0 +1,75 @@
#ifndef PEGHIGHLIGHTERRESULT_H
#define PEGHIGHLIGHTERRESULT_H
#include "vconstants.h"
#include "pegparser.h"
class PegMarkdownHighlighter;
class QTextDocument;
class PegHighlighterResult
{
public:
PegHighlighterResult();
PegHighlighterResult(const PegMarkdownHighlighter *p_peg,
const QSharedPointer<PegParseResult> &p_result);
bool matched(TimeStamp p_timeStamp) const;
TimeStamp m_timeStamp;
int m_numOfBlocks;
QVector<QVector<HLUnit>> m_blocksHighlights;
// Use another member to store the codeblocks highlights, because the highlight
// sequence is blockHighlights, regular-expression-based highlihgts, and then
// codeBlockHighlights.
// Support fenced code block only.
QVector<QVector<HLUnitStyle> > m_codeBlocksHighlights;
// All image link regions.
QVector<VElementRegion> m_imageRegions;
// All header regions.
// Sorted by start position.
QVector<VElementRegion> m_headerRegions;
// All fenced code blocks.
QVector<VCodeBlock> m_codeBlocks;
// Indexed by block number.
QHash<int, HighlightBlockState> m_codeBlocksState;
int m_numOfCodeBlockHighlightsToRecv;
private:
// Parse highlight elements for all the blocks from parse results.
void parseBlocksHighlights(const PegMarkdownHighlighter *p_peg,
const QSharedPointer<PegParseResult> &p_result);
// Parse highlight elements for blocks from one parse result.
void parseBlocksHighlightOne(const QTextDocument *p_doc,
unsigned long p_pos,
unsigned long p_end,
int p_styleIndex);
// Parse fenced code blocks from parse results.
void parseFencedCodeBlocks(const PegMarkdownHighlighter *p_peg,
const QSharedPointer<PegParseResult> &p_result);
void parseBlocksElementRegionOne(QHash<int, QVector<VElementRegion>> &p_regs,
const QTextDocument *p_doc,
unsigned long p_pos,
unsigned long p_end);
QRegExp m_codeBlockStartExp;
QRegExp m_codeBlockEndExp;
};
inline bool PegHighlighterResult::matched(TimeStamp p_timeStamp) const
{
return m_timeStamp == p_timeStamp;
}
#endif // PEGHIGHLIGHTERRESULT_H

View File

@ -0,0 +1,409 @@
#include "pegmarkdownhighlighter.h"
#include <QTextDocument>
#include <QTimer>
#include <QDebug>
#include "pegparser.h"
#include "vconfigmanager.h"
#include "utils/vutils.h"
extern VConfigManager *g_config;
PegMarkdownHighlighter::PegMarkdownHighlighter(QTextDocument *p_doc)
: QSyntaxHighlighter(p_doc),
m_doc(p_doc),
m_timeStamp(0),
m_parser(NULL),
m_parserExts(pmh_EXT_STRIKE | pmh_EXT_FRONTMATTER)
{
}
void PegMarkdownHighlighter::init(const QVector<HighlightingStyle> &p_styles,
const QHash<QString, QTextCharFormat> &p_codeBlockStyles,
bool p_mathjaxEnabled,
int p_timerInterval)
{
m_styles = p_styles;
m_codeBlockStyles = p_codeBlockStyles;
m_codeBlockFormat.setForeground(QBrush(Qt::darkYellow));
for (int index = 0; index < m_styles.size(); ++index) {
switch (m_styles[index].type) {
case pmh_FENCEDCODEBLOCK:
m_codeBlockFormat = m_styles[index].format;
break;
default:
break;
}
}
m_colorColumnFormat = m_codeBlockFormat;
m_colorColumnFormat.setForeground(QColor(g_config->getEditorColorColumnFg()));
m_colorColumnFormat.setBackground(QColor(g_config->getEditorColorColumnBg()));
m_result.reset(new PegHighlighterResult());
m_parser = new PegParser(this);
connect(m_parser, &PegParser::parseResultReady,
this, &PegMarkdownHighlighter::handleParseResult);
m_timer = new QTimer(this);
m_timer->setSingleShot(true);
m_timer->setInterval(p_timerInterval);
connect(m_timer, &QTimer::timeout,
this, [this]() {
startParse();
});
connect(m_doc, &QTextDocument::contentsChange,
this, &PegMarkdownHighlighter::handleContentsChange);
}
void PegMarkdownHighlighter::highlightBlock(const QString &p_text)
{
QSharedPointer<PegHighlighterResult> result(m_result);
int blockNum = currentBlock().blockNumber();
if (result->m_blocksHighlights.size() > blockNum) {
// units are sorted by start position and length.
const QVector<HLUnit> &units = result->m_blocksHighlights[blockNum];
if (!units.isEmpty()) {
for (int i = 0; i < units.size(); ++i) {
const HLUnit &unit = units[i];
if (i == 0) {
// No need to merge format.
setFormat(unit.start,
unit.length,
m_styles[unit.styleIndex].format);
} else {
QTextCharFormat newFormat = m_styles[unit.styleIndex].format;
for (int j = i - 1; j >= 0; --j) {
if (units[j].start + units[j].length <= unit.start) {
// It won't affect current unit.
continue;
} else {
// Merge the format.
QTextCharFormat tmpFormat(newFormat);
newFormat = m_styles[units[j].styleIndex].format;
// tmpFormat takes precedence.
newFormat.merge(tmpFormat);
}
}
setFormat(unit.start, unit.length, newFormat);
}
}
}
}
// Set current block's user data.
updateBlockUserData(blockNum, p_text);
setCurrentBlockState(HighlightBlockState::Normal);
updateCodeBlockState(result, blockNum, p_text);
if (currentBlockState() == HighlightBlockState::CodeBlock) {
highlightCodeBlock(result, blockNum);
highlightCodeBlockColorColumn(p_text);
}
}
void PegMarkdownHighlighter::handleContentsChange(int p_position, int p_charsRemoved, int p_charsAdded)
{
Q_UNUSED(p_position);
if (p_charsRemoved == 0 && p_charsAdded == 0) {
return;
}
++m_timeStamp;
// We still need a timer to start a complete parse.
m_timer->start();
}
void PegMarkdownHighlighter::startParse()
{
QSharedPointer<PegParseConfig> config(new PegParseConfig());
config->m_timeStamp = m_timeStamp;
config->m_data = m_doc->toPlainText().toUtf8();
config->m_numOfBlocks = m_doc->blockCount();
config->m_extensions = m_parserExts;
m_parser->parseAsync(config);
}
static bool compHLUnitStyle(const HLUnitStyle &a, const HLUnitStyle &b)
{
if (a.start < b.start) {
return true;
} else if (a.start == b.start) {
return a.length > b.length;
} else {
return false;
}
}
void PegMarkdownHighlighter::setCodeBlockHighlights(TimeStamp p_timeStamp,
const QVector<HLUnitPos> &p_units)
{
QSharedPointer<PegHighlighterResult> result(m_result);
if (!result->matched(p_timeStamp)) {
return;
}
if (p_units.isEmpty()) {
goto exit;
}
{
QVector<QVector<HLUnitStyle>> highlights(result->m_codeBlocksHighlights.size());
for (auto const &unit : p_units) {
int pos = unit.m_position;
int end = unit.m_position + unit.m_length;
QTextBlock block = m_doc->findBlock(pos);
int startBlockNum = block.blockNumber();
int endBlockNum = m_doc->findBlock(end).blockNumber();
// Text has been changed. Abandon the obsolete parsed result.
if (startBlockNum == -1 || endBlockNum >= highlights.size()) {
goto exit;
}
while (block.isValid()) {
int blockNumber = block.blockNumber();
if (blockNumber > endBlockNum) {
break;
}
int blockStartPos = block.position();
HLUnitStyle hl;
hl.style = unit.m_style;
if (blockNumber == startBlockNum) {
hl.start = pos - blockStartPos;
hl.length = (startBlockNum == endBlockNum) ?
(end - pos) : (block.length() - hl.start);
} else if (blockNumber == endBlockNum) {
hl.start = 0;
hl.length = end - blockStartPos;
} else {
hl.start = 0;
hl.length = block.length();
}
highlights[blockNumber].append(hl);
block = block.next();
}
}
// Need to highlight in order.
for (int i = 0; i < highlights.size(); ++i) {
QVector<HLUnitStyle> &units = highlights[i];
if (!units.isEmpty()) {
if (units.size() > 1) {
std::sort(units.begin(), units.end(), compHLUnitStyle);
}
result->m_codeBlocksHighlights[i].append(units);
}
}
}
exit:
if (--result->m_numOfCodeBlockHighlightsToRecv <= 0) {
rehighlight();
}
}
void PegMarkdownHighlighter::updateHighlightFast()
{
updateHighlight();
}
void PegMarkdownHighlighter::updateHighlight()
{
m_timer->stop();
startParse();
}
void PegMarkdownHighlighter::handleParseResult(const QSharedPointer<PegParseResult> &p_result)
{
if (!m_result.isNull() && m_result->m_timeStamp > p_result->m_timeStamp) {
return;
}
PegHighlighterResult *pegRes = new PegHighlighterResult(this, p_result);
m_result.reset(pegRes);
updateCodeBlocks(m_result);
// Now we got a new result, rehighlight.
rehighlight();
completeHighlight(m_result);
}
void PegMarkdownHighlighter::updateCodeBlocks(QSharedPointer<PegHighlighterResult> p_result)
{
if (!p_result->matched(m_timeStamp)) {
return;
}
if (g_config->getEnableCodeBlockHighlight()) {
p_result->m_codeBlocksHighlights.resize(p_result->m_numOfBlocks);
p_result->m_numOfCodeBlockHighlightsToRecv = p_result->m_codeBlocks.size();
}
emit codeBlocksUpdated(p_result->m_timeStamp, p_result->m_codeBlocks);
}
void PegMarkdownHighlighter::updateBlockUserData(int p_blockNum, const QString &p_text)
{
Q_UNUSED(p_text);
VTextBlockData *blockData = currentBlockData();
if (!blockData) {
blockData = new VTextBlockData();
setCurrentBlockUserData(blockData);
} else {
blockData->setCodeBlockIndentation(-1);
blockData->clearMathjax();
}
if (blockData->getPreviews().isEmpty()) {
m_possiblePreviewBlocks.remove(p_blockNum);
} else {
m_possiblePreviewBlocks.insert(p_blockNum);
}
}
void PegMarkdownHighlighter::updateCodeBlockState(const QSharedPointer<PegHighlighterResult> &p_result,
int p_blockNum,
const QString &p_text)
{
if (!p_result->matched(m_timeStamp)) {
return;
}
auto it = p_result->m_codeBlocksState.find(p_blockNum);
if (it != p_result->m_codeBlocksState.end()) {
VTextBlockData *blockData = currentBlockData();
Q_ASSERT(blockData);
HighlightBlockState state = it.value();
// Set code block indentation.
switch (state) {
case HighlightBlockState::CodeBlockStart:
{
int startLeadingSpaces = 0;
QRegExp reg(VUtils::c_fencedCodeBlockStartRegExp);
int idx = reg.indexIn(p_text);
if (idx >= 0) {
startLeadingSpaces = reg.capturedTexts()[1].size();
}
blockData->setCodeBlockIndentation(startLeadingSpaces);
break;
}
case HighlightBlockState::CodeBlock:
V_FALLTHROUGH;
case HighlightBlockState::CodeBlockEnd:
{
int startLeadingSpaces = 0;
VTextBlockData *preBlockData = previousBlockData();
if (preBlockData) {
startLeadingSpaces = preBlockData->getCodeBlockIndentation();
}
blockData->setCodeBlockIndentation(startLeadingSpaces);
break;
}
default:
Q_ASSERT(false);
break;
}
// Set code block state.
setCurrentBlockState(state);
}
}
void PegMarkdownHighlighter::highlightCodeBlock(const QSharedPointer<PegHighlighterResult> &p_result,
int p_blockNum)
{
if (p_result->m_codeBlocksHighlights.size() > p_blockNum) {
const QVector<HLUnitStyle> &units = p_result->m_codeBlocksHighlights[p_blockNum];
if (!units.isEmpty()) {
QVector<QTextCharFormat *> formats(units.size(), NULL);
for (int i = 0; i < units.size(); ++i) {
const HLUnitStyle &unit = units[i];
auto it = m_codeBlockStyles.find(unit.style);
if (it == m_codeBlockStyles.end()) {
continue;
}
formats[i] = &(*it);
QTextCharFormat newFormat = m_codeBlockFormat;
newFormat.merge(*it);
for (int j = i - 1; j >= 0; --j) {
if (units[j].start + units[j].length <= unit.start) {
// It won't affect current unit.
continue;
} else {
// Merge the format.
if (formats[j]) {
QTextCharFormat tmpFormat(newFormat);
newFormat = *(formats[j]);
// tmpFormat takes precedence.
newFormat.merge(tmpFormat);
}
}
}
setFormat(unit.start, unit.length, newFormat);
}
}
}
}
void PegMarkdownHighlighter::highlightCodeBlockColorColumn(const QString &p_text)
{
int cc = g_config->getColorColumn();
if (cc <= 0) {
return;
}
VTextBlockData *blockData = currentBlockData();
Q_ASSERT(blockData);
int indent = blockData->getCodeBlockIndentation();
if (indent == -1) {
return;
}
cc += indent;
if (p_text.size() < cc) {
return;
}
setFormat(cc - 1, 1, m_colorColumnFormat);
}
void PegMarkdownHighlighter::completeHighlight(QSharedPointer<PegHighlighterResult> p_result)
{
if (!p_result->matched(m_timeStamp)) {
return;
}
emit imageLinksUpdated(p_result->m_imageRegions);
emit headersUpdated(p_result->m_headerRegions);
emit highlightCompleted();
}

View File

@ -0,0 +1,179 @@
#ifndef PEGMARKDOWNHIGHLIGHTER_H
#define PEGMARKDOWNHIGHLIGHTER_H
#include <QSyntaxHighlighter>
#include <QTextCharFormat>
#include "vtextblockdata.h"
#include "markdownhighlighterdata.h"
#include "peghighlighterresult.h"
class PegParser;
class QTimer;
class PegMarkdownHighlighter : public QSyntaxHighlighter
{
Q_OBJECT
public:
explicit PegMarkdownHighlighter(QTextDocument *p_doc = nullptr);
void init(const QVector<HighlightingStyle> &p_styles,
const QHash<QString, QTextCharFormat> &p_codeBlockStyles,
bool p_mathjaxEnabled,
int p_timerInterval);
// Set code block highlight result by VCodeBlockHighlightHelper.
void setCodeBlockHighlights(TimeStamp p_timeStamp, const QVector<HLUnitPos> &p_units);
const QVector<VElementRegion> &getHeaderRegions() const;
const QSet<int> &getPossiblePreviewBlocks() const;
void clearPossiblePreviewBlocks(const QVector<int> &p_blocksToClear);
void addPossiblePreviewBlock(int p_blockNumber);
// Parse and only update the highlight results for rehighlight().
void updateHighlightFast();
QHash<QString, QTextCharFormat> &getCodeBlockStyles();
QVector<HighlightingStyle> &getStyles();
const QVector<HighlightingStyle> &getStyles() const;
const QTextDocument *getDocument() const;
public slots:
// Parse and rehighlight immediately.
void updateHighlight();
signals:
void highlightCompleted();
// QVector is implicitly shared.
void codeBlocksUpdated(TimeStamp p_timeStamp, const QVector<VCodeBlock> &p_codeBlocks);
// Emitted when image regions have been fetched from a new parsing result.
void imageLinksUpdated(const QVector<VElementRegion> &p_imageRegions);
// Emitted when header regions have been fetched from a new parsing result.
void headersUpdated(const QVector<VElementRegion> &p_headerRegions);
// Emitted when Mathjax blocks updated.
void mathjaxBlocksUpdated(const QVector<VMathjaxBlock> &p_mathjaxBlocks);
protected:
void highlightBlock(const QString &p_text) Q_DECL_OVERRIDE;
private slots:
void handleContentsChange(int p_position, int p_charsRemoved, int p_charsAdded);
void handleParseResult(const QSharedPointer<PegParseResult> &p_result);
private:
void startParse();
void updateCodeBlocks(QSharedPointer<PegHighlighterResult> p_result);
// Set the user data of currentBlock().
void updateBlockUserData(int p_blockNum, const QString &p_text);
void updateCodeBlockState(const QSharedPointer<PegHighlighterResult> &p_result,
int p_blockNum,
const QString &p_text);
// Highlight fenced code block according to VCodeBlockHighlightHelper result.
void highlightCodeBlock(const QSharedPointer<PegHighlighterResult> &p_result,
int p_blockNum);
// Highlight color column in code block.
void highlightCodeBlockColorColumn(const QString &p_text);
VTextBlockData *currentBlockData() const;
VTextBlockData *previousBlockData() const;
void completeHighlight(QSharedPointer<PegHighlighterResult> p_result);
QTextDocument *m_doc;
TimeStamp m_timeStamp;
QVector<HighlightingStyle> m_styles;
QHash<QString, QTextCharFormat> m_codeBlockStyles;
QTextCharFormat m_codeBlockFormat;
QTextCharFormat m_colorColumnFormat;
PegParser *m_parser;
QSharedPointer<PegHighlighterResult> m_result;
// Block number of those blocks which possible contains previewed image.
QSet<int> m_possiblePreviewBlocks;
// Extensions for parser.
int m_parserExts;
// Timer to trigger parse.
QTimer *m_timer;
};
inline const QVector<VElementRegion> &PegMarkdownHighlighter::getHeaderRegions() const
{
return m_result->m_headerRegions;
}
inline const QSet<int> &PegMarkdownHighlighter::getPossiblePreviewBlocks() const
{
return m_possiblePreviewBlocks;
}
inline void PegMarkdownHighlighter::clearPossiblePreviewBlocks(const QVector<int> &p_blocksToClear)
{
for (auto i : p_blocksToClear) {
m_possiblePreviewBlocks.remove(i);
}
}
inline void PegMarkdownHighlighter::addPossiblePreviewBlock(int p_blockNumber)
{
m_possiblePreviewBlocks.insert(p_blockNumber);
}
inline QHash<QString, QTextCharFormat> &PegMarkdownHighlighter::getCodeBlockStyles()
{
return m_codeBlockStyles;
}
inline QVector<HighlightingStyle> &PegMarkdownHighlighter::getStyles()
{
return m_styles;
}
inline const QVector<HighlightingStyle> &PegMarkdownHighlighter::getStyles() const
{
return m_styles;
}
inline const QTextDocument *PegMarkdownHighlighter::getDocument() const
{
return m_doc;
}
inline VTextBlockData *PegMarkdownHighlighter::currentBlockData() const
{
return static_cast<VTextBlockData *>(currentBlockUserData());
}
inline VTextBlockData *PegMarkdownHighlighter::previousBlockData() const
{
QTextBlock block = currentBlock().previous();
if (!block.isValid()) {
return NULL;
}
return static_cast<VTextBlockData *>(block.userData());
}
#endif // PEGMARKDOWNHIGHLIGHTER_H

276
src/pegparser.cpp Normal file
View File

@ -0,0 +1,276 @@
#include "pegparser.h"
enum WorkerState
{
Idle,
Busy,
Cancelled,
Finished
};
void PegParseResult::parse(QAtomicInt &p_stop)
{
parseImageRegions(p_stop);
parseHeaderRegions(p_stop);
parseFencedCodeBlockRegions(p_stop);
}
void PegParseResult::parseImageRegions(QAtomicInt &p_stop)
{
// From Qt5.7, the capacity is preserved.
m_imageRegions.clear();
if (isEmpty()) {
return;
}
pmh_element *elem = m_pmhElements[pmh_IMAGE];
while (elem != NULL) {
if (elem->end <= elem->pos) {
elem = elem->next;
continue;
}
if (p_stop.load() == 1) {
return;
}
m_imageRegions.push_back(VElementRegion(elem->pos, elem->end));
elem = elem->next;
}
}
void PegParseResult::parseHeaderRegions(QAtomicInt &p_stop)
{
// From Qt5.7, the capacity is preserved.
m_headerRegions.clear();
if (isEmpty()) {
return;
}
pmh_element_type hx[6] = {pmh_H1, pmh_H2, pmh_H3, pmh_H4, pmh_H5, pmh_H6};
for (int i = 0; i < 6; ++i) {
pmh_element *elem = m_pmhElements[hx[i]];
while (elem != NULL) {
if (elem->end <= elem->pos) {
elem = elem->next;
continue;
}
if (p_stop.load() == 1) {
return;
}
m_headerRegions.push_back(VElementRegion(elem->pos, elem->end));
elem = elem->next;
}
}
if (p_stop.load() == 1) {
return;
}
std::sort(m_headerRegions.begin(), m_headerRegions.end());
}
void PegParseResult::parseFencedCodeBlockRegions(QAtomicInt &p_stop)
{
m_codeBlockRegions.clear();
if (isEmpty()) {
return;
}
pmh_element *elem = m_pmhElements[pmh_FENCEDCODEBLOCK];
while (elem != NULL) {
if (elem->end <= elem->pos) {
elem = elem->next;
continue;
}
if (p_stop.load() == 1) {
return;
}
if (!m_codeBlockRegions.contains(elem->pos)) {
m_codeBlockRegions.insert(elem->pos, VElementRegion(elem->pos, elem->end));
}
elem = elem->next;
}
}
PegParserWorker::PegParserWorker(QObject *p_parent)
: QThread(p_parent),
m_stop(0),
m_state(WorkerState::Idle)
{
}
void PegParserWorker::prepareParse(const QSharedPointer<PegParseConfig> &p_config)
{
Q_ASSERT(m_parseConfig.isNull());
m_state = WorkerState::Busy;
m_parseConfig = p_config;
}
void PegParserWorker::reset()
{
m_parseConfig.reset();
m_parseResult.reset();
m_stop.store(0);
m_state = WorkerState::Idle;
}
void PegParserWorker::stop()
{
m_stop.store(1);
}
void PegParserWorker::run()
{
Q_ASSERT(m_state == WorkerState::Busy);
m_parseResult = parseMarkdown(m_parseConfig, m_stop);
if (isAskedToStop()) {
m_state = WorkerState::Cancelled;
return;
}
m_state = WorkerState::Finished;
}
QSharedPointer<PegParseResult> PegParserWorker::parseMarkdown(const QSharedPointer<PegParseConfig> &p_config,
QAtomicInt &p_stop)
{
QSharedPointer<PegParseResult> result(new PegParseResult(p_config));
if (p_config->m_data.isEmpty()) {
return result;
}
pmh_element **pmhResult = NULL;
char *data = p_config->m_data.data();
pmh_markdown_to_elements(data, p_config->m_extensions, &pmhResult);
result->m_pmhElements = pmhResult;
if (p_stop.load() == 1) {
return result;
}
result->parse(p_stop);
return result;
}
#define NUM_OF_THREADS 2
PegParser::PegParser(QObject *p_parent)
: QObject(p_parent)
{
init();
}
void PegParser::parseAsync(const QSharedPointer<PegParseConfig> &p_config)
{
m_pendingWork = p_config;
pickWorker();
}
void PegParser::init()
{
for (int i = 0; i < NUM_OF_THREADS; ++i) {
PegParserWorker *th = new PegParserWorker(this);
connect(th, &PegParserWorker::finished,
this, [this, th]() {
handleWorkerFinished(th);
});
m_workers.append(th);
}
}
void PegParser::clear()
{
m_pendingWork.reset();
for (auto const & th : m_workers) {
th->quit();
th->wait();
delete th;
}
m_workers.clear();
}
PegParser::~PegParser()
{
clear();
}
void PegParser::handleWorkerFinished(PegParserWorker *p_worker)
{
QSharedPointer<PegParseResult> result;
if (p_worker->state() == WorkerState::Finished) {
result = p_worker->parseResult();
}
p_worker->reset();
pickWorker();
if (!result.isNull()) {
emit parseResultReady(result);
}
}
void PegParser::pickWorker()
{
if (m_pendingWork.isNull()) {
return;
}
bool allBusy = true;
for (auto th : m_workers) {
if (th->state() == WorkerState::Idle) {
scheduleWork(th, m_pendingWork);
m_pendingWork.reset();
return;
} else if (th->state() != WorkerState::Busy) {
allBusy = false;
}
}
if (allBusy) {
// Need to stop the worker with non-minimal timestamp.
int idx = 0;
TimeStamp minTS = m_workers[idx]->workTimeStamp();
if (m_workers.size() > 1) {
if (m_workers[1]->workTimeStamp() > minTS) {
idx = 1;
}
}
m_workers[idx]->stop();
}
}
void PegParser::scheduleWork(PegParserWorker *p_worker,
const QSharedPointer<PegParseConfig> &p_config)
{
Q_ASSERT(p_worker->state() == WorkerState::Idle);
p_worker->reset();
p_worker->prepareParse(p_config);
p_worker->start();
}

186
src/pegparser.h Normal file
View File

@ -0,0 +1,186 @@
#ifndef PEGPARSER_H
#define PEGPARSER_H
#include <QObject>
#include <QSharedPointer>
#include <QThread>
#include <QAtomicInt>
#include <QVector>
#include "vconstants.h"
#include "markdownhighlighterdata.h"
struct PegParseConfig
{
TimeStamp m_timeStamp;
QByteArray m_data;
int m_numOfBlocks;
int m_extensions;
QString toString() const
{
return QString("PegParseConfig ts %1 data %2 blocks %3").arg(m_timeStamp)
.arg(m_data.size())
.arg(m_numOfBlocks);
}
};
struct PegParseResult
{
PegParseResult(const QSharedPointer<PegParseConfig> &p_config)
: m_timeStamp(p_config->m_timeStamp),
m_numOfBlocks(p_config->m_numOfBlocks),
m_pmhElements(NULL)
{
}
~PegParseResult()
{
clearPmhElements();
}
void clearPmhElements()
{
if (m_pmhElements) {
pmh_free_elements(m_pmhElements);
m_pmhElements = NULL;
}
}
bool operator<(const PegParseResult &p_other) const
{
return m_timeStamp < p_other.m_timeStamp;
}
QString toString() const
{
return QString("PegParseResult ts %1").arg(m_timeStamp);
}
bool isEmpty() const
{
return !m_pmhElements;
}
// Parse m_pmhElements.
void parse(QAtomicInt &p_stop);
TimeStamp m_timeStamp;
int m_numOfBlocks;
pmh_element **m_pmhElements;
// All image link regions.
QVector<VElementRegion> m_imageRegions;
// All header regions.
// Sorted by start position.
QVector<VElementRegion> m_headerRegions;
// Fenced code block regions.
// Ordered by start position in ascending order.
QMap<int, VElementRegion> m_codeBlockRegions;
private:
void parseImageRegions(QAtomicInt &p_stop);
void parseHeaderRegions(QAtomicInt &p_stop);
void parseFencedCodeBlockRegions(QAtomicInt &p_stop);
};
class PegParserWorker : public QThread
{
Q_OBJECT
public:
explicit PegParserWorker(QObject *p_parent = nullptr);
void prepareParse(const QSharedPointer<PegParseConfig> &p_config);
void reset();
int state() const
{
return m_state;
}
TimeStamp workTimeStamp() const
{
if (m_parseConfig.isNull()) {
return 0;
}
return m_parseConfig->m_timeStamp;
}
const QSharedPointer<PegParseConfig> &parseConfig() const
{
return m_parseConfig;
}
const QSharedPointer<PegParseResult> &parseResult() const
{
return m_parseResult;
}
public slots:
void stop();
protected:
void run() Q_DECL_OVERRIDE;
private:
QSharedPointer<PegParseResult> parseMarkdown(const QSharedPointer<PegParseConfig> &p_config,
QAtomicInt &p_stop);
bool isAskedToStop() const
{
return m_stop.load() == 1;
}
QAtomicInt m_stop;
int m_state;
QSharedPointer<PegParseConfig> m_parseConfig;
QSharedPointer<PegParseResult> m_parseResult;
};
class PegParser : public QObject
{
Q_OBJECT
public:
explicit PegParser(QObject *p_parent = nullptr);
~PegParser();
void parseAsync(const QSharedPointer<PegParseConfig> &p_config);
signals:
void parseResultReady(const QSharedPointer<PegParseResult> &p_result);
private slots:
void handleWorkerFinished(PegParserWorker *p_worker);
private:
void init();
void clear();
void pickWorker();
void scheduleWork(PegParserWorker *p_worker, const QSharedPointer<PegParseConfig> &p_config);
// Maintain a fixed number of workers to pick work.
QVector<PegParserWorker *> m_workers;
QSharedPointer<PegParseConfig> m_pendingWork;
};
#endif // PEGPARSER_H

View File

@ -106,7 +106,7 @@ minimize_to_system_tray=-1
markdown_suffix=md,markdown,mkd markdown_suffix=md,markdown,mkd
; Markdown highlight timer interval (milliseconds) ; Markdown highlight timer interval (milliseconds)
markdown_highlight_interval=400 markdown_highlight_interval=200
; Adds specified height between lines (in pixels) ; Adds specified height between lines (in pixels)
line_distance_height=3 line_distance_height=3

View File

@ -140,7 +140,10 @@ SOURCES += main.cpp\
vtagpanel.cpp \ vtagpanel.cpp \
valltagspanel.cpp \ valltagspanel.cpp \
vtaglabel.cpp \ vtaglabel.cpp \
vtagexplorer.cpp vtagexplorer.cpp \
pegmarkdownhighlighter.cpp \
pegparser.cpp \
peghighlighterresult.cpp
HEADERS += vmainwindow.h \ HEADERS += vmainwindow.h \
vdirectorytree.h \ vdirectorytree.h \
@ -274,7 +277,11 @@ HEADERS += vmainwindow.h \
vtagpanel.h \ vtagpanel.h \
valltagspanel.h \ valltagspanel.h \
vtaglabel.h \ vtaglabel.h \
vtagexplorer.h vtagexplorer.h \
markdownhighlighterdata.h \
pegmarkdownhighlighter.h \
pegparser.h \
peghighlighterresult.h
RESOURCES += \ RESOURCES += \
vnote.qrc \ vnote.qrc \

View File

@ -2,10 +2,12 @@
#include <QDebug> #include <QDebug>
#include <QStringList> #include <QStringList>
#include "vdocument.h" #include "vdocument.h"
#include "utils/vutils.h" #include "utils/vutils.h"
#include "pegmarkdownhighlighter.h"
VCodeBlockHighlightHelper::VCodeBlockHighlightHelper(HGMarkdownHighlighter *p_highlighter, VCodeBlockHighlightHelper::VCodeBlockHighlightHelper(PegMarkdownHighlighter *p_highlighter,
VDocument *p_vdoc, VDocument *p_vdoc,
MarkdownConverterType p_type) MarkdownConverterType p_type)
: QObject(p_highlighter), : QObject(p_highlighter),
@ -14,14 +16,14 @@ VCodeBlockHighlightHelper::VCodeBlockHighlightHelper(HGMarkdownHighlighter *p_hi
m_type(p_type), m_type(p_type),
m_timeStamp(0) m_timeStamp(0)
{ {
connect(m_highlighter, &HGMarkdownHighlighter::codeBlocksUpdated, connect(m_highlighter, &PegMarkdownHighlighter::codeBlocksUpdated,
this, &VCodeBlockHighlightHelper::handleCodeBlocksUpdated); this, &VCodeBlockHighlightHelper::handleCodeBlocksUpdated);
connect(m_vdocument, &VDocument::textHighlighted, connect(m_vdocument, &VDocument::textHighlighted,
this, &VCodeBlockHighlightHelper::handleTextHighlightResult); this, &VCodeBlockHighlightHelper::handleTextHighlightResult);
// Web side is ready for code block highlight. // Web side is ready for code block highlight.
connect(m_vdocument, &VDocument::readyToHighlightText, connect(m_vdocument, &VDocument::readyToHighlightText,
m_highlighter, &HGMarkdownHighlighter::updateHighlight); m_highlighter, &PegMarkdownHighlighter::updateHighlight);
} }
QString VCodeBlockHighlightHelper::unindentCodeBlock(const QString &p_text) QString VCodeBlockHighlightHelper::unindentCodeBlock(const QString &p_text)
@ -57,44 +59,45 @@ QString VCodeBlockHighlightHelper::unindentCodeBlock(const QString &p_text)
return res; return res;
} }
void VCodeBlockHighlightHelper::handleCodeBlocksUpdated(const QVector<VCodeBlock> &p_codeBlocks) void VCodeBlockHighlightHelper::handleCodeBlocksUpdated(TimeStamp p_timeStamp,
const QVector<VCodeBlock> &p_codeBlocks)
{ {
if (!m_vdocument->isReadyToHighlight()) { if (!m_vdocument->isReadyToHighlight()) {
// Immediately return empty results. // Immediately return empty results.
QVector<HLUnitPos> emptyRes; QVector<HLUnitPos> emptyRes;
for (int i = 0; i < p_codeBlocks.size(); ++i) { for (int i = 0; i < p_codeBlocks.size(); ++i) {
updateHighlightResults(0, emptyRes); updateHighlightResults(p_timeStamp, 0, emptyRes);
} }
return; return;
} }
int curStamp = m_timeStamp.fetchAndAddRelaxed(1) + 1; m_timeStamp = p_timeStamp;
m_codeBlocks = p_codeBlocks; m_codeBlocks = p_codeBlocks;
for (int i = 0; i < m_codeBlocks.size(); ++i) { for (int i = 0; i < m_codeBlocks.size(); ++i) {
const VCodeBlock &block = m_codeBlocks[i]; const VCodeBlock &block = m_codeBlocks[i];
auto it = m_cache.find(block.m_text); auto it = m_cache.find(block.m_text);
if (it != m_cache.end()) { if (it != m_cache.end()) {
// Hit cache. // Hit cache.
qDebug() << "code block highlight hit cache" << curStamp << i; qDebug() << "code block highlight hit cache" << p_timeStamp << i;
it.value().m_timeStamp = curStamp; it.value().m_timeStamp = p_timeStamp;
updateHighlightResults(block.m_startPos, it.value().m_units); updateHighlightResults(p_timeStamp, block.m_startPos, it.value().m_units);
} else { } else {
QString unindentedText = unindentCodeBlock(block.m_text); QString unindentedText = unindentCodeBlock(block.m_text);
m_vdocument->highlightTextAsync(unindentedText, i, curStamp); m_vdocument->highlightTextAsync(unindentedText, i, p_timeStamp);
} }
} }
} }
void VCodeBlockHighlightHelper::handleTextHighlightResult(const QString &p_html, void VCodeBlockHighlightHelper::handleTextHighlightResult(const QString &p_html,
int p_id, int p_id,
int p_timeStamp) unsigned long long p_timeStamp)
{ {
int curStamp = m_timeStamp.load();
// Abandon obsolete result. // Abandon obsolete result.
if (curStamp != p_timeStamp) { if (m_timeStamp != p_timeStamp) {
return; return;
} }
parseHighlightResult(p_timeStamp, p_id, p_html); parseHighlightResult(p_timeStamp, p_id, p_html);
} }
@ -137,7 +140,7 @@ static void matchTokenRelaxed(const QString &p_text, const QString &p_tokenStr,
} }
// For now, we could only handle code blocks outside the list. // For now, we could only handle code blocks outside the list.
void VCodeBlockHighlightHelper::parseHighlightResult(int p_timeStamp, void VCodeBlockHighlightHelper::parseHighlightResult(TimeStamp p_timeStamp,
int p_idx, int p_idx,
const QString &p_html) const QString &p_html)
{ {
@ -209,9 +212,8 @@ void VCodeBlockHighlightHelper::parseHighlightResult(int p_timeStamp,
exit: exit:
// Pass result back to highlighter. // Pass result back to highlighter.
int curStamp = m_timeStamp.load();
// Abandon obsolete result. // Abandon obsolete result.
if (curStamp != p_timeStamp) { if (m_timeStamp != p_timeStamp) {
return; return;
} }
@ -224,10 +226,11 @@ exit:
// Add it to cache. // Add it to cache.
addToHighlightCache(text, p_timeStamp, hlUnits); addToHighlightCache(text, p_timeStamp, hlUnits);
updateHighlightResults(startPos, hlUnits); updateHighlightResults(p_timeStamp, startPos, hlUnits);
} }
void VCodeBlockHighlightHelper::updateHighlightResults(int p_startPos, void VCodeBlockHighlightHelper::updateHighlightResults(TimeStamp p_timeStamp,
int p_startPos,
QVector<HLUnitPos> p_units) QVector<HLUnitPos> p_units)
{ {
for (int i = 0; i < p_units.size(); ++i) { for (int i = 0; i < p_units.size(); ++i) {
@ -235,7 +238,7 @@ void VCodeBlockHighlightHelper::updateHighlightResults(int p_startPos,
} }
// We need to call this function anyway to trigger the rehighlight. // We need to call this function anyway to trigger the rehighlight.
m_highlighter->setCodeBlockHighlights(p_units); m_highlighter->setCodeBlockHighlights(p_timeStamp, p_units);
} }
bool VCodeBlockHighlightHelper::parseSpanElement(QXmlStreamReader &p_xml, bool VCodeBlockHighlightHelper::parseSpanElement(QXmlStreamReader &p_xml,
@ -283,7 +286,7 @@ bool VCodeBlockHighlightHelper::parseSpanElement(QXmlStreamReader &p_xml,
} }
void VCodeBlockHighlightHelper::addToHighlightCache(const QString &p_text, void VCodeBlockHighlightHelper::addToHighlightCache(const QString &p_text,
int p_timeStamp, TimeStamp p_timeStamp,
const QVector<HLUnitPos> &p_units) const QVector<HLUnitPos> &p_units)
{ {
const int c_maxEntries = 100; const int c_maxEntries = 100;

View File

@ -6,15 +6,17 @@
#include <QAtomicInteger> #include <QAtomicInteger>
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <QHash> #include <QHash>
#include "vconfigmanager.h" #include "vconfigmanager.h"
class VDocument; class VDocument;
class PegMarkdownHighlighter;
class VCodeBlockHighlightHelper : public QObject class VCodeBlockHighlightHelper : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
VCodeBlockHighlightHelper(HGMarkdownHighlighter *p_highlighter, VCodeBlockHighlightHelper(PegMarkdownHighlighter *p_highlighter,
VDocument *p_vdoc, MarkdownConverterType p_type); VDocument *p_vdoc, MarkdownConverterType p_type);
// @p_text: text of fenced code block. // @p_text: text of fenced code block.
@ -25,27 +27,30 @@ public:
static QString unindentCodeBlock(const QString &p_text); static QString unindentCodeBlock(const QString &p_text);
private slots: private slots:
void handleCodeBlocksUpdated(const QVector<VCodeBlock> &p_codeBlocks); void handleCodeBlocksUpdated(TimeStamp p_timeStamp, const QVector<VCodeBlock> &p_codeBlocks);
void handleTextHighlightResult(const QString &p_html, int p_id, int p_timeStamp); void handleTextHighlightResult(const QString &p_html, int p_id, unsigned long long p_timeStamp);
private: private:
struct HLResult struct HLResult
{ {
HLResult() : m_timeStamp(-1) HLResult()
: m_timeStamp(0)
{ {
} }
HLResult(int p_timeStamp, const QVector<HLUnitPos> &p_units) HLResult(TimeStamp p_timeStamp, const QVector<HLUnitPos> &p_units)
: m_timeStamp(p_timeStamp), m_units(p_units) : m_timeStamp(p_timeStamp),
m_units(p_units)
{ {
} }
int m_timeStamp; TimeStamp m_timeStamp;
QVector<HLUnitPos> m_units; QVector<HLUnitPos> m_units;
}; };
void parseHighlightResult(int p_timeStamp, int p_idx, const QString &p_html); void parseHighlightResult(TimeStamp p_timeStamp, int p_idx, const QString &p_html);
// @p_text: the raw text of the code block; // @p_text: the raw text of the code block;
// @p_index: the start index of the span element within @p_text; // @p_index: the start index of the span element within @p_text;
@ -54,16 +59,18 @@ private:
const QString &p_text, int &p_index, const QString &p_text, int &p_index,
QVector<HLUnitPos> &p_units); QVector<HLUnitPos> &p_units);
void updateHighlightResults(int p_startPos, QVector<HLUnitPos> p_units); void updateHighlightResults(TimeStamp p_timeStamp, int p_startPos, QVector<HLUnitPos> p_units);
void addToHighlightCache(const QString &p_text, void addToHighlightCache(const QString &p_text,
int p_timeStamp, TimeStamp p_timeStamp,
const QVector<HLUnitPos> &p_units); const QVector<HLUnitPos> &p_units);
HGMarkdownHighlighter *m_highlighter; PegMarkdownHighlighter *m_highlighter;
VDocument *m_vdocument; VDocument *m_vdocument;
MarkdownConverterType m_type; MarkdownConverterType m_type;
QAtomicInteger<int> m_timeStamp;
TimeStamp m_timeStamp;
QVector<VCodeBlock> m_codeBlocks; QVector<VCodeBlock> m_codeBlocks;
// Cache for highlight result, using the code block text as key. // Cache for highlight result, using the code block text as key.

View File

@ -11,7 +11,7 @@
#include <QDir> #include <QDir>
#include "vnotebook.h" #include "vnotebook.h"
#include "hgmarkdownhighlighter.h" #include "markdownhighlighterdata.h"
#include "vmarkdownconverter.h" #include "vmarkdownconverter.h"
#include "vconstants.h" #include "vconstants.h"
#include "vfilesessioninfo.h" #include "vfilesessioninfo.h"

View File

@ -122,9 +122,11 @@ enum HighlightBlockState
CodeBlockEnd, CodeBlockEnd,
// This block is inside a HTML comment region. // This block is inside a HTML comment region.
// Obsolete.
Comment, Comment,
// Verbatim code block. // Verbatim code block.
// Obsolete.
Verbatim, Verbatim,
// Mathjax. It means the pending state of the block. // Mathjax. It means the pending state of the block.
@ -132,6 +134,7 @@ enum HighlightBlockState
MathjaxInline, MathjaxInline,
// Header. // Header.
// Obsolete.
Header Header
}; };

View File

@ -74,12 +74,12 @@ void VDocument::keyPressEvent(int p_key, bool p_ctrl, bool p_shift, bool p_meta)
emit keyPressed(p_key, p_ctrl, p_shift, p_meta); emit keyPressed(p_key, p_ctrl, p_shift, p_meta);
} }
void VDocument::highlightTextAsync(const QString &p_text, int p_id, int p_timeStamp) void VDocument::highlightTextAsync(const QString &p_text, int p_id, unsigned long long p_timeStamp)
{ {
emit requestHighlightText(p_text, p_id, p_timeStamp); emit requestHighlightText(p_text, p_id, p_timeStamp);
} }
void VDocument::highlightTextCB(const QString &p_html, int p_id, int p_timeStamp) void VDocument::highlightTextCB(const QString &p_html, int p_id, unsigned long long p_timeStamp)
{ {
emit textHighlighted(p_html, p_id, p_timeStamp); emit textHighlighted(p_html, p_id, p_timeStamp);
} }

View File

@ -31,7 +31,7 @@ public:
// Request to highlight a segment text. // Request to highlight a segment text.
// Use p_id to identify the result. // Use p_id to identify the result.
void highlightTextAsync(const QString &p_text, int p_id, int p_timeStamp); void highlightTextAsync(const QString &p_text, int p_id, unsigned long long p_timeStamp);
// Request to convert @p_text to HTML. // Request to convert @p_text to HTML.
void textToHtmlAsync(int p_identitifer, void textToHtmlAsync(int p_identitifer,
@ -84,7 +84,7 @@ public slots:
void keyPressEvent(int p_key, bool p_ctrl, bool p_shift, bool p_meta); void keyPressEvent(int p_key, bool p_ctrl, bool p_shift, bool p_meta);
void updateText(); void updateText();
void highlightTextCB(const QString &p_html, int p_id, int p_timeStamp); void highlightTextCB(const QString &p_html, int p_id, unsigned long long p_timeStamp);
void noticeReadyToHighlightText(); void noticeReadyToHighlightText();
@ -128,9 +128,9 @@ signals:
void keyPressed(int p_key, bool p_ctrl, bool p_shift, bool p_meta); void keyPressed(int p_key, bool p_ctrl, bool p_shift, bool p_meta);
void requestHighlightText(const QString &p_text, int p_id, int p_timeStamp); void requestHighlightText(const QString &p_text, int p_id, unsigned long long p_timeStamp);
void textHighlighted(const QString &p_html, int p_id, int p_timeStamp); void textHighlighted(const QString &p_html, int p_id, unsigned long long p_timeStamp);
void readyToHighlightText(); void readyToHighlightText();

View File

@ -125,8 +125,9 @@ void VLivePreviewHelper::checkLang(const QString &p_lang,
} }
} }
void VLivePreviewHelper::updateCodeBlocks(const QVector<VCodeBlock> &p_codeBlocks) void VLivePreviewHelper::updateCodeBlocks(TimeStamp p_timeStamp, const QVector<VCodeBlock> &p_codeBlocks)
{ {
Q_UNUSED(p_timeStamp);
if (!m_livePreviewEnabled && !m_inplacePreviewEnabled) { if (!m_livePreviewEnabled && !m_inplacePreviewEnabled) {
return; return;
} }

View File

@ -109,7 +109,7 @@ public:
bool isPreviewEnabled() const; bool isPreviewEnabled() const;
public slots: public slots:
void updateCodeBlocks(const QVector<VCodeBlock> &p_codeBlocks); void updateCodeBlocks(TimeStamp p_timeStamp, const QVector<VCodeBlock> &p_codeBlocks);
signals: signals:
void inplacePreviewCodeBlockUpdated(const QVector<QSharedPointer<VImageToPreview> > &p_images); void inplacePreviewCodeBlockUpdated(const QVector<QSharedPointer<VImageToPreview> > &p_images);

View File

@ -1,7 +1,6 @@
#include <QtWidgets> #include <QtWidgets>
#include "vmdedit.h" #include "vmdedit.h"
#include "hgmarkdownhighlighter.h" #include "hgmarkdownhighlighter.h"
#include "vcodeblockhighlighthelper.h"
#include "vmdeditoperations.h" #include "vmdeditoperations.h"
#include "vnote.h" #include "vnote.h"
#include "vconfigmanager.h" #include "vconfigmanager.h"
@ -24,6 +23,9 @@ VMdEdit::VMdEdit(VFile *p_file, VDocument *p_vdoc, MarkdownConverterType p_type,
: VEdit(p_file, p_parent), m_mdHighlighter(NULL), m_freshEdit(true), : VEdit(p_file, p_parent), m_mdHighlighter(NULL), m_freshEdit(true),
m_finishedAsyncJobs(c_numberOfAysncJobs) m_finishedAsyncJobs(c_numberOfAysncJobs)
{ {
Q_UNUSED(p_type);
Q_UNUSED(p_vdoc);
V_ASSERT(p_file->getDocType() == DocType::Markdown); V_ASSERT(p_file->getDocType() == DocType::Markdown);
setAcceptRichText(false); setAcceptRichText(false);
@ -43,9 +45,6 @@ VMdEdit::VMdEdit(VFile *p_file, VDocument *p_vdoc, MarkdownConverterType p_type,
makeBlockVisible(textCursor().block()); makeBlockVisible(textCursor().block());
}); });
m_cbHighlighter = new VCodeBlockHighlightHelper(m_mdHighlighter, p_vdoc,
p_type);
/* /*
m_imagePreviewer = new VImagePreviewer(this, m_mdHighlighter); m_imagePreviewer = new VImagePreviewer(this, m_mdHighlighter);
connect(m_mdHighlighter, &HGMarkdownHighlighter::imageLinksUpdated, connect(m_mdHighlighter, &HGMarkdownHighlighter::imageLinksUpdated,

View File

@ -13,7 +13,6 @@
#include "utils/vutils.h" #include "utils/vutils.h"
class HGMarkdownHighlighter; class HGMarkdownHighlighter;
class VCodeBlockHighlightHelper;
class VDocument; class VDocument;
class VMdEdit : public VEdit class VMdEdit : public VEdit
@ -110,7 +109,6 @@ private:
int indexOfCurrentHeader() const; int indexOfCurrentHeader() const;
HGMarkdownHighlighter *m_mdHighlighter; HGMarkdownHighlighter *m_mdHighlighter;
VCodeBlockHighlightHelper *m_cbHighlighter;
// VImagePreviewer *m_imagePreviewer; // VImagePreviewer *m_imagePreviewer;
// Image links inserted while editing. // Image links inserted while editing.

View File

@ -9,7 +9,7 @@
#include "vdocument.h" #include "vdocument.h"
#include "utils/veditutils.h" #include "utils/veditutils.h"
#include "vedittab.h" #include "vedittab.h"
#include "hgmarkdownhighlighter.h" #include "pegmarkdownhighlighter.h"
#include "vcodeblockhighlighthelper.h" #include "vcodeblockhighlighthelper.h"
#include "vmdeditoperations.h" #include "vmdeditoperations.h"
#include "vtableofcontent.h" #include "vtableofcontent.h"
@ -35,7 +35,7 @@ VMdEditor::VMdEditor(VFile *p_file,
QWidget *p_parent) QWidget *p_parent)
: VTextEdit(p_parent), : VTextEdit(p_parent),
VEditor(p_file, this), VEditor(p_file, this),
m_mdHighlighter(NULL), m_pegHighlighter(NULL),
m_freshEdit(true), m_freshEdit(true),
m_textToHtmlDialog(NULL), m_textToHtmlDialog(NULL),
m_zoomDelta(0), m_zoomDelta(0),
@ -60,18 +60,17 @@ VMdEditor::VMdEditor(VFile *p_file,
setReadOnly(true); setReadOnly(true);
m_mdHighlighter = new HGMarkdownHighlighter(g_config->getMdHighlightingStyles(), m_pegHighlighter = new PegMarkdownHighlighter(document());
m_pegHighlighter->init(g_config->getMdHighlightingStyles(),
g_config->getCodeBlockStyles(), g_config->getCodeBlockStyles(),
g_config->getMarkdownHighlightInterval(), g_config->getEnableMathjax(),
document()); g_config->getMarkdownHighlightInterval());
m_mdHighlighter->setMathjaxEnabled(g_config->getEnableMathjax()); connect(m_pegHighlighter, &PegMarkdownHighlighter::headersUpdated,
connect(m_mdHighlighter, &HGMarkdownHighlighter::headersUpdated,
this, &VMdEditor::updateHeaders); this, &VMdEditor::updateHeaders);
// After highlight, the cursor may trun into non-visible. We should make it visible // After highlight, the cursor may trun into non-visible. We should make it visible
// in this case. // in this case.
connect(m_mdHighlighter, &HGMarkdownHighlighter::highlightCompleted, connect(m_pegHighlighter, &PegMarkdownHighlighter::highlightCompleted,
this, [this]() { this, [this]() {
makeBlockVisible(textCursor().block()); makeBlockVisible(textCursor().block());
@ -81,15 +80,15 @@ VMdEditor::VMdEditor(VFile *p_file,
} }
}); });
m_cbHighlighter = new VCodeBlockHighlightHelper(m_mdHighlighter, m_cbHighlighter = new VCodeBlockHighlightHelper(m_pegHighlighter,
p_doc, p_doc,
p_type); p_type);
m_previewMgr = new VPreviewManager(this, m_mdHighlighter); m_previewMgr = new VPreviewManager(this, m_pegHighlighter);
connect(m_mdHighlighter, &HGMarkdownHighlighter::imageLinksUpdated, connect(m_pegHighlighter, &PegMarkdownHighlighter::imageLinksUpdated,
m_previewMgr, &VPreviewManager::updateImageLinks); m_previewMgr, &VPreviewManager::updateImageLinks);
connect(m_previewMgr, &VPreviewManager::requestUpdateImageLinks, connect(m_previewMgr, &VPreviewManager::requestUpdateImageLinks,
m_mdHighlighter, &HGMarkdownHighlighter::updateHighlight); m_pegHighlighter, &PegMarkdownHighlighter::updateHighlight);
m_editOps = new VMdEditOperations(this, m_file); m_editOps = new VMdEditOperations(this, m_file);
connect(m_editOps, &VEditOperations::statusMessage, connect(m_editOps, &VEditOperations::statusMessage,
@ -132,10 +131,10 @@ void VMdEditor::beginEdit()
emit statusChanged(); emit statusChanged();
if (m_freshEdit) { if (m_freshEdit) {
m_mdHighlighter->updateHighlight(); m_pegHighlighter->updateHighlight();
relayout(); relayout();
} else { } else {
updateHeaders(m_mdHighlighter->getHeaderRegions()); updateHeaders(m_pegHighlighter->getHeaderRegions());
} }
} }
@ -170,7 +169,7 @@ void VMdEditor::reloadFile()
const QString &content = m_file->getContent(); const QString &content = m_file->getContent();
setPlainText(content); setPlainText(content);
setModified(false); setModified(false);
m_mdHighlighter->updateHighlightFast(); m_pegHighlighter->updateHighlightFast();
m_freshEdit = true; m_freshEdit = true;
@ -461,7 +460,7 @@ static void insertSequenceToHeader(QTextCursor& p_cursor,
void VMdEditor::updateHeaderSequenceByConfigChange() void VMdEditor::updateHeaderSequenceByConfigChange()
{ {
updateHeadersHelper(m_mdHighlighter->getHeaderRegions(), true); updateHeadersHelper(m_pegHighlighter->getHeaderRegions(), true);
} }
void VMdEditor::updateHeadersHelper(const QVector<VElementRegion> &p_headerRegions, bool p_configChanged) void VMdEditor::updateHeadersHelper(const QVector<VElementRegion> &p_headerRegions, bool p_configChanged)
@ -493,8 +492,7 @@ void VMdEditor::updateHeadersHelper(const QVector<VElementRegion> &p_headerRegio
<< block.text(); << block.text();
} }
if ((block.userState() == HighlightBlockState::Header) if (headerReg.exactMatch(block.text())) {
&& headerReg.exactMatch(block.text())) {
int level = headerReg.cap(1).length(); int level = headerReg.cap(1).length();
VTableOfContentItem header(headerReg.cap(2).trimmed(), VTableOfContentItem header(headerReg.cap(2).trimmed(),
level, level,
@ -1199,7 +1197,7 @@ void VMdEditor::zoomPage(bool p_zoomIn, int p_range)
m_zoomDelta += delta; m_zoomDelta += delta;
QVector<HighlightingStyle> &styles = m_mdHighlighter->getHighlightingStyles(); QVector<HighlightingStyle> &styles = m_pegHighlighter->getStyles();
for (auto & it : styles) { for (auto & it : styles) {
int size = it.format.fontPointSize(); int size = it.format.fontPointSize();
if (size == 0) { if (size == 0) {
@ -1215,7 +1213,7 @@ void VMdEditor::zoomPage(bool p_zoomIn, int p_range)
it.format.setFontPointSize(size); it.format.setFontPointSize(size);
} }
QHash<QString, QTextCharFormat> &cbStyles = m_mdHighlighter->getCodeBlockStyles(); QHash<QString, QTextCharFormat> &cbStyles = m_pegHighlighter->getCodeBlockStyles();
for (auto it = cbStyles.begin(); it != cbStyles.end(); ++it) { for (auto it = cbStyles.begin(); it != cbStyles.end(); ++it) {
int size = it.value().fontPointSize(); int size = it.value().fontPointSize();
if (size == 0) { if (size == 0) {
@ -1231,7 +1229,7 @@ void VMdEditor::zoomPage(bool p_zoomIn, int p_range)
it.value().setFontPointSize(size); it.value().setFontPointSize(size);
} }
m_mdHighlighter->rehighlight(); m_pegHighlighter->rehighlight();
} }
void VMdEditor::initCopyAsMenu(QAction *p_before, QMenu *p_menu) void VMdEditor::initCopyAsMenu(QAction *p_before, QMenu *p_menu)

View File

@ -14,7 +14,7 @@
#include "vconfigmanager.h" #include "vconfigmanager.h"
#include "utils/vutils.h" #include "utils/vutils.h"
class HGMarkdownHighlighter; class PegMarkdownHighlighter;
class VCodeBlockHighlightHelper; class VCodeBlockHighlightHelper;
class VDocument; class VDocument;
class VPreviewManager; class VPreviewManager;
@ -72,7 +72,7 @@ public:
void setEditTab(VEditTab *p_editTab); void setEditTab(VEditTab *p_editTab);
HGMarkdownHighlighter *getMarkdownHighlighter() const; PegMarkdownHighlighter *getMarkdownHighlighter() const;
VPreviewManager *getPreviewManager() const; VPreviewManager *getPreviewManager() const;
@ -256,7 +256,7 @@ private:
void insertImageLink(const QString &p_text, const QString &p_url); void insertImageLink(const QString &p_text, const QString &p_url);
HGMarkdownHighlighter *m_mdHighlighter; PegMarkdownHighlighter *m_pegHighlighter;
VCodeBlockHighlightHelper *m_cbHighlighter; VCodeBlockHighlightHelper *m_cbHighlighter;
@ -282,9 +282,9 @@ private:
int m_copyTimeStamp; int m_copyTimeStamp;
}; };
inline HGMarkdownHighlighter *VMdEditor::getMarkdownHighlighter() const inline PegMarkdownHighlighter *VMdEditor::getMarkdownHighlighter() const
{ {
return m_mdHighlighter; return m_pegHighlighter;
} }
inline VPreviewManager *VMdEditor::getPreviewManager() const inline VPreviewManager *VMdEditor::getPreviewManager() const

View File

@ -8,7 +8,7 @@
#include "vnote.h" #include "vnote.h"
#include "utils/vutils.h" #include "utils/vutils.h"
#include "vpreviewpage.h" #include "vpreviewpage.h"
#include "hgmarkdownhighlighter.h" #include "pegmarkdownhighlighter.h"
#include "vconfigmanager.h" #include "vconfigmanager.h"
#include "vmarkdownconverter.h" #include "vmarkdownconverter.h"
#include "vnotebook.h" #include "vnotebook.h"
@ -535,7 +535,7 @@ void VMdTab::setupMarkdownEditor()
m_splitter->insertWidget(0, m_editor); m_splitter->insertWidget(0, m_editor);
m_livePreviewHelper = new VLivePreviewHelper(m_editor, m_document, this); m_livePreviewHelper = new VLivePreviewHelper(m_editor, m_document, this);
connect(m_editor->getMarkdownHighlighter(), &HGMarkdownHighlighter::codeBlocksUpdated, connect(m_editor->getMarkdownHighlighter(), &PegMarkdownHighlighter::codeBlocksUpdated,
m_livePreviewHelper, &VLivePreviewHelper::updateCodeBlocks); m_livePreviewHelper, &VLivePreviewHelper::updateCodeBlocks);
connect(m_editor->getPreviewManager(), &VPreviewManager::previewEnabledChanged, connect(m_editor->getPreviewManager(), &VPreviewManager::previewEnabledChanged,
m_livePreviewHelper, &VLivePreviewHelper::setInplacePreviewEnabled); m_livePreviewHelper, &VLivePreviewHelper::setInplacePreviewEnabled);
@ -546,7 +546,7 @@ void VMdTab::setupMarkdownEditor()
m_livePreviewHelper->setInplacePreviewEnabled(m_editor->getPreviewManager()->isPreviewEnabled()); m_livePreviewHelper->setInplacePreviewEnabled(m_editor->getPreviewManager()->isPreviewEnabled());
m_mathjaxPreviewHelper = new VMathJaxInplacePreviewHelper(m_editor, m_document, this); m_mathjaxPreviewHelper = new VMathJaxInplacePreviewHelper(m_editor, m_document, this);
connect(m_editor->getMarkdownHighlighter(), &HGMarkdownHighlighter::mathjaxBlocksUpdated, connect(m_editor->getMarkdownHighlighter(), &PegMarkdownHighlighter::mathjaxBlocksUpdated,
m_mathjaxPreviewHelper, &VMathJaxInplacePreviewHelper::updateMathjaxBlocks); m_mathjaxPreviewHelper, &VMathJaxInplacePreviewHelper::updateMathjaxBlocks);
connect(m_editor->getPreviewManager(), &VPreviewManager::previewEnabledChanged, connect(m_editor->getPreviewManager(), &VPreviewManager::previewEnabledChanged,
m_mathjaxPreviewHelper, &VMathJaxInplacePreviewHelper::setEnabled); m_mathjaxPreviewHelper, &VMathJaxInplacePreviewHelper::setEnabled);

View File

@ -10,11 +10,11 @@
#include "vconfigmanager.h" #include "vconfigmanager.h"
#include "utils/vutils.h" #include "utils/vutils.h"
#include "vdownloader.h" #include "vdownloader.h"
#include "hgmarkdownhighlighter.h" #include "pegmarkdownhighlighter.h"
extern VConfigManager *g_config; extern VConfigManager *g_config;
VPreviewManager::VPreviewManager(VMdEditor *p_editor, HGMarkdownHighlighter *p_highlighter) VPreviewManager::VPreviewManager(VMdEditor *p_editor, PegMarkdownHighlighter *p_highlighter)
: QObject(p_editor), : QObject(p_editor),
m_editor(p_editor), m_editor(p_editor),
m_document(p_editor->document()), m_document(p_editor->document()),

View File

@ -8,7 +8,7 @@
#include <QVector> #include <QVector>
#include <QSharedPointer> #include <QSharedPointer>
#include "hgmarkdownhighlighter.h" #include "markdownhighlighterdata.h"
#include "vmdeditor.h" #include "vmdeditor.h"
#include "vtextblockdata.h" #include "vtextblockdata.h"
@ -59,7 +59,7 @@ class VPreviewManager : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
VPreviewManager(VMdEditor *p_editor, HGMarkdownHighlighter *p_highlighter); VPreviewManager(VMdEditor *p_editor, PegMarkdownHighlighter *p_highlighter);
void setPreviewEnabled(bool p_enabled); void setPreviewEnabled(bool p_enabled);
@ -215,7 +215,7 @@ private:
QTextDocument *m_document; QTextDocument *m_document;
HGMarkdownHighlighter *m_highlighter; PegMarkdownHighlighter *m_highlighter;
VDownloader *m_downloader; VDownloader *m_downloader;