mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 22:09:52 +08:00
PegHighlighter: support fast parse
This commit is contained in:
parent
0e724635b3
commit
abee597812
@ -7,6 +7,19 @@
|
|||||||
#include "pegmarkdownhighlighter.h"
|
#include "pegmarkdownhighlighter.h"
|
||||||
#include "utils/vutils.h"
|
#include "utils/vutils.h"
|
||||||
|
|
||||||
|
PegHighlighterFastResult::PegHighlighterFastResult()
|
||||||
|
: m_timeStamp(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PegHighlighterFastResult::PegHighlighterFastResult(const PegMarkdownHighlighter *p_peg,
|
||||||
|
const QSharedPointer<PegParseResult> &p_result)
|
||||||
|
: m_timeStamp(p_result->m_timeStamp)
|
||||||
|
{
|
||||||
|
PegHighlighterResult::parseBlocksHighlights(m_blocksHighlights, p_peg, p_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PegHighlighterResult::PegHighlighterResult()
|
PegHighlighterResult::PegHighlighterResult()
|
||||||
: m_timeStamp(0),
|
: m_timeStamp(0),
|
||||||
m_numOfBlocks(0),
|
m_numOfBlocks(0),
|
||||||
@ -25,7 +38,7 @@ PegHighlighterResult::PegHighlighterResult(const PegMarkdownHighlighter *p_peg,
|
|||||||
m_codeBlockStartExp = QRegExp(VUtils::c_fencedCodeBlockStartRegExp);
|
m_codeBlockStartExp = QRegExp(VUtils::c_fencedCodeBlockStartRegExp);
|
||||||
m_codeBlockEndExp = QRegExp(VUtils::c_fencedCodeBlockEndRegExp);
|
m_codeBlockEndExp = QRegExp(VUtils::c_fencedCodeBlockEndRegExp);
|
||||||
|
|
||||||
parseBlocksHighlights(p_peg, p_result);
|
parseBlocksHighlights(m_blocksHighlights, p_peg, p_result);
|
||||||
|
|
||||||
// Implicit sharing.
|
// Implicit sharing.
|
||||||
m_imageRegions = p_result->m_imageRegions;
|
m_imageRegions = p_result->m_imageRegions;
|
||||||
@ -47,14 +60,16 @@ static bool compHLUnit(const HLUnit &p_a, const HLUnit &p_b)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PegHighlighterResult::parseBlocksHighlights(const PegMarkdownHighlighter *p_peg,
|
void PegHighlighterResult::parseBlocksHighlights(QVector<QVector<HLUnit>> &p_blocksHighlights,
|
||||||
|
const PegMarkdownHighlighter *p_peg,
|
||||||
const QSharedPointer<PegParseResult> &p_result)
|
const QSharedPointer<PegParseResult> &p_result)
|
||||||
{
|
{
|
||||||
m_blocksHighlights.resize(m_numOfBlocks);
|
p_blocksHighlights.resize(p_result->m_numOfBlocks);
|
||||||
if (p_result->isEmpty()) {
|
if (p_result->isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int offset = p_result->m_offset;
|
||||||
const QTextDocument *doc = p_peg->getDocument();
|
const QTextDocument *doc = p_peg->getDocument();
|
||||||
const QVector<HighlightingStyle> &styles = p_peg->getStyles();
|
const QVector<HighlightingStyle> &styles = p_peg->getStyles();
|
||||||
auto pmhResult = p_result->m_pmhElements;
|
auto pmhResult = p_result->m_pmhElements;
|
||||||
@ -71,20 +86,25 @@ void PegHighlighterResult::parseBlocksHighlights(const PegMarkdownHighlighter *p
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseBlocksHighlightOne(doc, elem_cursor->pos, elem_cursor->end, i);
|
parseBlocksHighlightOne(p_blocksHighlights,
|
||||||
|
doc,
|
||||||
|
offset + elem_cursor->pos,
|
||||||
|
offset + elem_cursor->end,
|
||||||
|
i);
|
||||||
elem_cursor = elem_cursor->next;
|
elem_cursor = elem_cursor->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort m_blocksHighlights.
|
// Sort p_blocksHighlights.
|
||||||
for (int i = 0; i < m_blocksHighlights.size(); ++i) {
|
for (int i = 0; i < p_blocksHighlights.size(); ++i) {
|
||||||
if (m_blocksHighlights[i].size() > 1) {
|
if (p_blocksHighlights[i].size() > 1) {
|
||||||
std::sort(m_blocksHighlights[i].begin(), m_blocksHighlights[i].end(), compHLUnit);
|
std::sort(p_blocksHighlights[i].begin(), p_blocksHighlights[i].end(), compHLUnit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PegHighlighterResult::parseBlocksHighlightOne(const QTextDocument *p_doc,
|
void PegHighlighterResult::parseBlocksHighlightOne(QVector<QVector<HLUnit>> &p_blocksHighlights,
|
||||||
|
const QTextDocument *p_doc,
|
||||||
unsigned long p_pos,
|
unsigned long p_pos,
|
||||||
unsigned long p_end,
|
unsigned long p_end,
|
||||||
int p_styleIndex)
|
int p_styleIndex)
|
||||||
@ -121,7 +141,7 @@ void PegHighlighterResult::parseBlocksHighlightOne(const QTextDocument *p_doc,
|
|||||||
}
|
}
|
||||||
unit.styleIndex = p_styleIndex;
|
unit.styleIndex = p_styleIndex;
|
||||||
|
|
||||||
m_blocksHighlights[blockNum].append(unit);
|
p_blocksHighlights[blockNum].append(unit);
|
||||||
|
|
||||||
block = block.next();
|
block = block.next();
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,41 @@
|
|||||||
class PegMarkdownHighlighter;
|
class PegMarkdownHighlighter;
|
||||||
class QTextDocument;
|
class QTextDocument;
|
||||||
|
|
||||||
|
class PegHighlighterFastResult
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PegHighlighterFastResult();
|
||||||
|
|
||||||
|
PegHighlighterFastResult(const PegMarkdownHighlighter *p_peg,
|
||||||
|
const QSharedPointer<PegParseResult> &p_result);
|
||||||
|
|
||||||
|
bool matched(TimeStamp p_timeStamp) const
|
||||||
|
{
|
||||||
|
return m_timeStamp == p_timeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeStamp m_timeStamp;
|
||||||
|
|
||||||
|
QVector<QVector<HLUnit>> m_blocksHighlights;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class PegHighlighterResult
|
class PegHighlighterResult
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PegHighlighterResult();
|
PegHighlighterResult();
|
||||||
|
|
||||||
|
// TODO: handle p_result->m_offset.
|
||||||
PegHighlighterResult(const PegMarkdownHighlighter *p_peg,
|
PegHighlighterResult(const PegMarkdownHighlighter *p_peg,
|
||||||
const QSharedPointer<PegParseResult> &p_result);
|
const QSharedPointer<PegParseResult> &p_result);
|
||||||
|
|
||||||
bool matched(TimeStamp p_timeStamp) const;
|
bool matched(TimeStamp p_timeStamp) const;
|
||||||
|
|
||||||
|
// Parse highlight elements for all the blocks from parse results.
|
||||||
|
static void parseBlocksHighlights(QVector<QVector<HLUnit>> &p_blocksHighlights,
|
||||||
|
const PegMarkdownHighlighter *p_peg,
|
||||||
|
const QSharedPointer<PegParseResult> &p_result);
|
||||||
|
|
||||||
TimeStamp m_timeStamp;
|
TimeStamp m_timeStamp;
|
||||||
|
|
||||||
int m_numOfBlocks;
|
int m_numOfBlocks;
|
||||||
@ -48,15 +73,12 @@ public:
|
|||||||
QVector<VMathjaxBlock> m_mathjaxBlocks;
|
QVector<VMathjaxBlock> m_mathjaxBlocks;
|
||||||
|
|
||||||
private:
|
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.
|
// Parse highlight elements for blocks from one parse result.
|
||||||
void parseBlocksHighlightOne(const QTextDocument *p_doc,
|
static void parseBlocksHighlightOne(QVector<QVector<HLUnit>> &p_blocksHighlights,
|
||||||
unsigned long p_pos,
|
const QTextDocument *p_doc,
|
||||||
unsigned long p_end,
|
unsigned long p_pos,
|
||||||
int p_styleIndex);
|
unsigned long p_end,
|
||||||
|
int p_styleIndex);
|
||||||
|
|
||||||
// Parse fenced code blocks from parse results.
|
// Parse fenced code blocks from parse results.
|
||||||
void parseFencedCodeBlocks(const PegMarkdownHighlighter *p_peg,
|
void parseFencedCodeBlocks(const PegMarkdownHighlighter *p_peg,
|
||||||
|
@ -49,6 +49,7 @@ void PegMarkdownHighlighter::init(const QVector<HighlightingStyle> &p_styles,
|
|||||||
m_colorColumnFormat.setBackground(QColor(g_config->getEditorColorColumnBg()));
|
m_colorColumnFormat.setBackground(QColor(g_config->getEditorColorColumnBg()));
|
||||||
|
|
||||||
m_result.reset(new PegHighlighterResult());
|
m_result.reset(new PegHighlighterResult());
|
||||||
|
m_fastResult.reset(new PegHighlighterFastResult());
|
||||||
|
|
||||||
m_parser = new PegParser(this);
|
m_parser = new PegParser(this);
|
||||||
connect(m_parser, &PegParser::parseResultReady,
|
connect(m_parser, &PegParser::parseResultReady,
|
||||||
@ -62,6 +63,24 @@ void PegMarkdownHighlighter::init(const QVector<HighlightingStyle> &p_styles,
|
|||||||
startParse();
|
startParse();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_fastParseTimer = new QTimer(this);
|
||||||
|
m_fastParseTimer->setSingleShot(true);
|
||||||
|
m_fastParseTimer->setInterval(50);
|
||||||
|
connect(m_fastParseTimer, &QTimer::timeout,
|
||||||
|
this, [this]() {
|
||||||
|
QSharedPointer<PegHighlighterFastResult> result(m_fastResult);
|
||||||
|
if (!result->matched(m_timeStamp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QVector<QVector<HLUnit>> &hls = result->m_blocksHighlights;
|
||||||
|
for (int i = 0; i < hls.size(); ++i) {
|
||||||
|
if (!hls[i].isEmpty()) {
|
||||||
|
rehighlightBlock(m_doc->findBlockByNumber(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
connect(m_doc, &QTextDocument::contentsChange,
|
connect(m_doc, &QTextDocument::contentsChange,
|
||||||
this, &PegMarkdownHighlighter::handleContentsChange);
|
this, &PegMarkdownHighlighter::handleContentsChange);
|
||||||
}
|
}
|
||||||
@ -71,9 +90,31 @@ void PegMarkdownHighlighter::highlightBlock(const QString &p_text)
|
|||||||
QSharedPointer<PegHighlighterResult> result(m_result);
|
QSharedPointer<PegHighlighterResult> result(m_result);
|
||||||
|
|
||||||
int blockNum = currentBlock().blockNumber();
|
int blockNum = currentBlock().blockNumber();
|
||||||
if (result->m_blocksHighlights.size() > blockNum) {
|
|
||||||
|
highlightBlockOne(result->m_blocksHighlights, blockNum);
|
||||||
|
|
||||||
|
highlightBlockOne(m_fastResult->m_blocksHighlights, blockNum);
|
||||||
|
|
||||||
|
// 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, p_text);
|
||||||
|
|
||||||
|
highlightCodeBlockColorColumn(p_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PegMarkdownHighlighter::highlightBlockOne(const QVector<QVector<HLUnit>> &p_highlights,
|
||||||
|
int p_blockNum)
|
||||||
|
{
|
||||||
|
if (p_highlights.size() > p_blockNum) {
|
||||||
// units are sorted by start position and length.
|
// units are sorted by start position and length.
|
||||||
const QVector<HLUnit> &units = result->m_blocksHighlights[blockNum];
|
const QVector<HLUnit> &units = p_highlights[p_blockNum];
|
||||||
if (!units.isEmpty()) {
|
if (!units.isEmpty()) {
|
||||||
for (int i = 0; i < units.size(); ++i) {
|
for (int i = 0; i < units.size(); ++i) {
|
||||||
const HLUnit &unit = units[i];
|
const HLUnit &unit = units[i];
|
||||||
@ -102,19 +143,6 @@ void PegMarkdownHighlighter::highlightBlock(const QString &p_text)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, p_text);
|
|
||||||
|
|
||||||
highlightCodeBlockColorColumn(p_text);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PegMarkdownHighlighter::handleContentsChange(int p_position, int p_charsRemoved, int p_charsAdded)
|
void PegMarkdownHighlighter::handleContentsChange(int p_position, int p_charsRemoved, int p_charsAdded)
|
||||||
@ -127,6 +155,8 @@ void PegMarkdownHighlighter::handleContentsChange(int p_position, int p_charsRem
|
|||||||
|
|
||||||
++m_timeStamp;
|
++m_timeStamp;
|
||||||
|
|
||||||
|
startFastParse(p_position, p_charsRemoved, p_charsAdded);
|
||||||
|
|
||||||
// We still need a timer to start a complete parse.
|
// We still need a timer to start a complete parse.
|
||||||
m_timer->start();
|
m_timer->start();
|
||||||
}
|
}
|
||||||
@ -142,6 +172,47 @@ void PegMarkdownHighlighter::startParse()
|
|||||||
m_parser->parseAsync(config);
|
m_parser->parseAsync(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PegMarkdownHighlighter::startFastParse(int p_position, int p_charsRemoved, int p_charsAdded)
|
||||||
|
{
|
||||||
|
// Get affected block range.
|
||||||
|
int firstBlockNum, lastBlockNum;
|
||||||
|
getFastParseBlockRange(p_position, p_charsRemoved, p_charsAdded, firstBlockNum, lastBlockNum);
|
||||||
|
|
||||||
|
QString text;
|
||||||
|
QTextBlock block = m_doc->findBlockByNumber(firstBlockNum);
|
||||||
|
int offset = block.position();
|
||||||
|
while (block.isValid()) {
|
||||||
|
int blockNum = block.blockNumber();
|
||||||
|
if (blockNum > lastBlockNum) {
|
||||||
|
break;
|
||||||
|
} else if (blockNum == firstBlockNum) {
|
||||||
|
text = block.text();
|
||||||
|
} else {
|
||||||
|
text = text + "\n" + block.text();
|
||||||
|
}
|
||||||
|
|
||||||
|
block = block.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<PegParseConfig> config(new PegParseConfig());
|
||||||
|
config->m_timeStamp = m_timeStamp;
|
||||||
|
config->m_data = text.toUtf8();
|
||||||
|
config->m_numOfBlocks = m_doc->blockCount();
|
||||||
|
config->m_offset = offset;
|
||||||
|
config->m_extensions = m_parserExts;
|
||||||
|
config->m_fast = true;
|
||||||
|
|
||||||
|
QSharedPointer<PegParseResult> parseRes = m_parser->parse(config);
|
||||||
|
processFastParseResult(parseRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PegMarkdownHighlighter::processFastParseResult(const QSharedPointer<PegParseResult> &p_result)
|
||||||
|
{
|
||||||
|
m_fastParseTimer->stop();
|
||||||
|
m_fastResult.reset(new PegHighlighterFastResult(this, p_result));
|
||||||
|
m_fastParseTimer->start();
|
||||||
|
}
|
||||||
|
|
||||||
static bool compHLUnitStyle(const HLUnitStyle &a, const HLUnitStyle &b)
|
static bool compHLUnitStyle(const HLUnitStyle &a, const HLUnitStyle &b)
|
||||||
{
|
{
|
||||||
if (a.start < b.start) {
|
if (a.start < b.start) {
|
||||||
@ -424,3 +495,97 @@ void PegMarkdownHighlighter::completeHighlight(QSharedPointer<PegHighlighterResu
|
|||||||
|
|
||||||
emit highlightCompleted();
|
emit highlightCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PegMarkdownHighlighter::getFastParseBlockRange(int p_position,
|
||||||
|
int p_charsRemoved,
|
||||||
|
int p_charsAdded,
|
||||||
|
int &p_firstBlock,
|
||||||
|
int &p_lastBlock) const
|
||||||
|
{
|
||||||
|
const int maxNumOfBlocks = 50;
|
||||||
|
|
||||||
|
int charsChanged = p_charsRemoved + p_charsAdded;
|
||||||
|
QTextBlock firstBlock = m_doc->findBlock(p_position);
|
||||||
|
|
||||||
|
// May be an invalid block.
|
||||||
|
QTextBlock lastBlock = m_doc->findBlock(qMax(0, p_position + charsChanged));
|
||||||
|
if (!lastBlock.isValid()) {
|
||||||
|
lastBlock = m_doc->lastBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
int num = lastBlock.blockNumber() - firstBlock.blockNumber() + 1;
|
||||||
|
|
||||||
|
if (num >= maxNumOfBlocks) {
|
||||||
|
p_firstBlock = firstBlock.blockNumber();
|
||||||
|
p_lastBlock = p_firstBlock + maxNumOfBlocks - 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up.
|
||||||
|
// Find empty block.
|
||||||
|
if (!VEditUtils::isEmptyBlock(firstBlock)) {
|
||||||
|
while (firstBlock.isValid() && num < maxNumOfBlocks) {
|
||||||
|
QTextBlock block = firstBlock.previous();
|
||||||
|
if (block.isValid() && !VEditUtils::isEmptyBlock(block)) {
|
||||||
|
firstBlock = block;
|
||||||
|
++num;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cross code block.
|
||||||
|
while (firstBlock.isValid() && num < maxNumOfBlocks) {
|
||||||
|
int state = firstBlock.userState();
|
||||||
|
if (state == HighlightBlockState::CodeBlock
|
||||||
|
|| state == HighlightBlockState::CodeBlockEnd) {
|
||||||
|
QTextBlock block = firstBlock.previous();
|
||||||
|
if (block.isValid()) {
|
||||||
|
firstBlock = block;
|
||||||
|
++num;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look down.
|
||||||
|
// Find empty block.
|
||||||
|
if (!VEditUtils::isEmptyBlock(lastBlock)) {
|
||||||
|
while (lastBlock.isValid() && num < maxNumOfBlocks) {
|
||||||
|
QTextBlock block = lastBlock.next();
|
||||||
|
if (block.isValid() && !VEditUtils::isEmptyBlock(block)) {
|
||||||
|
lastBlock = block;
|
||||||
|
++num;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cross code block.
|
||||||
|
while (lastBlock.isValid() && num < maxNumOfBlocks) {
|
||||||
|
int state = lastBlock.userState();
|
||||||
|
if (state == HighlightBlockState::CodeBlock
|
||||||
|
|| state == HighlightBlockState::CodeBlockStart) {
|
||||||
|
QTextBlock block = lastBlock.next();
|
||||||
|
if (block.isValid()) {
|
||||||
|
lastBlock = block;
|
||||||
|
++num;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p_firstBlock = firstBlock.blockNumber();
|
||||||
|
p_lastBlock = lastBlock.blockNumber();
|
||||||
|
if (p_lastBlock < p_firstBlock) {
|
||||||
|
p_lastBlock = p_firstBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -74,6 +74,8 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
void startParse();
|
void startParse();
|
||||||
|
|
||||||
|
void startFastParse(int p_position, int p_charsRemoved, int p_charsAdded);
|
||||||
|
|
||||||
void updateCodeBlocks(QSharedPointer<PegHighlighterResult> p_result);
|
void updateCodeBlocks(QSharedPointer<PegHighlighterResult> p_result);
|
||||||
|
|
||||||
// Set the user data of currentBlock().
|
// Set the user data of currentBlock().
|
||||||
@ -99,6 +101,17 @@ private:
|
|||||||
|
|
||||||
bool isMathJaxEnabled() const;
|
bool isMathJaxEnabled() const;
|
||||||
|
|
||||||
|
void getFastParseBlockRange(int p_position,
|
||||||
|
int p_charsRemoved,
|
||||||
|
int p_charsAdded,
|
||||||
|
int &p_firstBlock,
|
||||||
|
int &p_lastBlock) const;
|
||||||
|
|
||||||
|
void processFastParseResult(const QSharedPointer<PegParseResult> &p_result);
|
||||||
|
|
||||||
|
void highlightBlockOne(const QVector<QVector<HLUnit>> &p_highlights,
|
||||||
|
int p_blockNum);
|
||||||
|
|
||||||
QTextDocument *m_doc;
|
QTextDocument *m_doc;
|
||||||
|
|
||||||
TimeStamp m_timeStamp;
|
TimeStamp m_timeStamp;
|
||||||
@ -113,6 +126,8 @@ private:
|
|||||||
|
|
||||||
QSharedPointer<PegHighlighterResult> m_result;
|
QSharedPointer<PegHighlighterResult> m_result;
|
||||||
|
|
||||||
|
QSharedPointer<PegHighlighterFastResult> m_fastResult;
|
||||||
|
|
||||||
// Block number of those blocks which possible contains previewed image.
|
// Block number of those blocks which possible contains previewed image.
|
||||||
QSet<int> m_possiblePreviewBlocks;
|
QSet<int> m_possiblePreviewBlocks;
|
||||||
|
|
||||||
@ -121,6 +136,8 @@ private:
|
|||||||
|
|
||||||
// Timer to trigger parse.
|
// Timer to trigger parse.
|
||||||
QTimer *m_timer;
|
QTimer *m_timer;
|
||||||
|
|
||||||
|
QTimer *m_fastParseTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const QVector<VElementRegion> &PegMarkdownHighlighter::getHeaderRegions() const
|
inline const QVector<VElementRegion> &PegMarkdownHighlighter::getHeaderRegions() const
|
||||||
|
@ -8,8 +8,12 @@ enum WorkerState
|
|||||||
Finished
|
Finished
|
||||||
};
|
};
|
||||||
|
|
||||||
void PegParseResult::parse(QAtomicInt &p_stop)
|
void PegParseResult::parse(QAtomicInt &p_stop, bool p_fast)
|
||||||
{
|
{
|
||||||
|
if (p_fast) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
parseImageRegions(p_stop);
|
parseImageRegions(p_stop);
|
||||||
|
|
||||||
parseHeaderRegions(p_stop);
|
parseHeaderRegions(p_stop);
|
||||||
@ -40,7 +44,7 @@ void PegParseResult::parseImageRegions(QAtomicInt &p_stop)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_imageRegions.push_back(VElementRegion(elem->pos, elem->end));
|
m_imageRegions.push_back(VElementRegion(m_offset + elem->pos, m_offset + elem->end));
|
||||||
elem = elem->next;
|
elem = elem->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,7 +70,7 @@ void PegParseResult::parseHeaderRegions(QAtomicInt &p_stop)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_headerRegions.push_back(VElementRegion(elem->pos, elem->end));
|
m_headerRegions.push_back(VElementRegion(m_offset + elem->pos, m_offset + elem->end));
|
||||||
elem = elem->next;
|
elem = elem->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,8 +100,9 @@ void PegParseResult::parseFencedCodeBlockRegions(QAtomicInt &p_stop)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_codeBlockRegions.contains(elem->pos)) {
|
if (!m_codeBlockRegions.contains(m_offset + elem->pos)) {
|
||||||
m_codeBlockRegions.insert(elem->pos, VElementRegion(elem->pos, elem->end));
|
m_codeBlockRegions.insert(m_offset + elem->pos,
|
||||||
|
VElementRegion(m_offset + elem->pos, m_offset + elem->end));
|
||||||
}
|
}
|
||||||
|
|
||||||
elem = elem->next;
|
elem = elem->next;
|
||||||
@ -122,7 +127,7 @@ void PegParseResult::parseInlineEquationRegions(QAtomicInt &p_stop)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_inlineEquationRegions.push_back(VElementRegion(elem->pos, elem->end));
|
m_inlineEquationRegions.push_back(VElementRegion(m_offset + elem->pos, m_offset + elem->end));
|
||||||
elem = elem->next;
|
elem = elem->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,7 +150,7 @@ void PegParseResult::parseDisplayFormulaRegions(QAtomicInt &p_stop)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_displayFormulaRegions.push_back(VElementRegion(elem->pos, elem->end));
|
m_displayFormulaRegions.push_back(VElementRegion(m_offset + elem->pos, m_offset + elem->end));
|
||||||
elem = elem->next;
|
elem = elem->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +219,7 @@ QSharedPointer<PegParseResult> PegParserWorker::parseMarkdown(const QSharedPoint
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result->parse(p_stop);
|
result->parse(p_stop, p_config->m_fast);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -228,13 +233,6 @@ PegParser::PegParser(QObject *p_parent)
|
|||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PegParser::parseAsync(const QSharedPointer<PegParseConfig> &p_config)
|
|
||||||
{
|
|
||||||
m_pendingWork = p_config;
|
|
||||||
|
|
||||||
pickWorker();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PegParser::init()
|
void PegParser::init()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUM_OF_THREADS; ++i) {
|
for (int i = 0; i < NUM_OF_THREADS; ++i) {
|
||||||
@ -267,6 +265,29 @@ PegParser::~PegParser()
|
|||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PegParser::parseAsync(const QSharedPointer<PegParseConfig> &p_config)
|
||||||
|
{
|
||||||
|
m_pendingWork = p_config;
|
||||||
|
|
||||||
|
pickWorker();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<PegParseResult> PegParser::parse(const QSharedPointer<PegParseConfig> &p_config)
|
||||||
|
{
|
||||||
|
QSharedPointer<PegParseResult> result(new PegParseResult(p_config));
|
||||||
|
|
||||||
|
if (p_config->m_data.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->m_pmhElements = PegParser::parseMarkdownToElements(p_config);
|
||||||
|
|
||||||
|
QAtomicInt stop(0);
|
||||||
|
result->parse(stop, p_config->m_fast);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void PegParser::handleWorkerFinished(PegParserWorker *p_worker)
|
void PegParser::handleWorkerFinished(PegParserWorker *p_worker)
|
||||||
{
|
{
|
||||||
QSharedPointer<PegParseResult> result;
|
QSharedPointer<PegParseResult> result;
|
||||||
@ -333,6 +354,7 @@ QVector<VElementRegion> PegParser::parseImageRegions(const QSharedPointer<PegPar
|
|||||||
return regs;
|
return regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int offset = p_config->m_offset;
|
||||||
pmh_element *elem = res[pmh_IMAGE];
|
pmh_element *elem = res[pmh_IMAGE];
|
||||||
while (elem != NULL) {
|
while (elem != NULL) {
|
||||||
if (elem->end <= elem->pos) {
|
if (elem->end <= elem->pos) {
|
||||||
@ -340,7 +362,7 @@ QVector<VElementRegion> PegParser::parseImageRegions(const QSharedPointer<PegPar
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
regs.push_back(VElementRegion(elem->pos, elem->end));
|
regs.push_back(VElementRegion(offset + elem->pos, offset + elem->end));
|
||||||
elem = elem->next;
|
elem = elem->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,9 @@ struct PegParseConfig
|
|||||||
PegParseConfig()
|
PegParseConfig()
|
||||||
: m_timeStamp(0),
|
: m_timeStamp(0),
|
||||||
m_numOfBlocks(0),
|
m_numOfBlocks(0),
|
||||||
m_extensions(pmh_EXT_NONE)
|
m_offset(0),
|
||||||
|
m_extensions(pmh_EXT_NONE),
|
||||||
|
m_fast(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,8 +28,14 @@ struct PegParseConfig
|
|||||||
|
|
||||||
int m_numOfBlocks;
|
int m_numOfBlocks;
|
||||||
|
|
||||||
|
// Offset of m_data in the document.
|
||||||
|
int m_offset;
|
||||||
|
|
||||||
int m_extensions;
|
int m_extensions;
|
||||||
|
|
||||||
|
// Fast parse.
|
||||||
|
bool m_fast;
|
||||||
|
|
||||||
QString toString() const
|
QString toString() const
|
||||||
{
|
{
|
||||||
return QString("PegParseConfig ts %1 data %2 blocks %3").arg(m_timeStamp)
|
return QString("PegParseConfig ts %1 data %2 blocks %3").arg(m_timeStamp)
|
||||||
@ -41,6 +49,7 @@ struct PegParseResult
|
|||||||
PegParseResult(const QSharedPointer<PegParseConfig> &p_config)
|
PegParseResult(const QSharedPointer<PegParseConfig> &p_config)
|
||||||
: m_timeStamp(p_config->m_timeStamp),
|
: m_timeStamp(p_config->m_timeStamp),
|
||||||
m_numOfBlocks(p_config->m_numOfBlocks),
|
m_numOfBlocks(p_config->m_numOfBlocks),
|
||||||
|
m_offset(p_config->m_offset),
|
||||||
m_pmhElements(NULL)
|
m_pmhElements(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -74,12 +83,14 @@ struct PegParseResult
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse m_pmhElements.
|
// Parse m_pmhElements.
|
||||||
void parse(QAtomicInt &p_stop);
|
void parse(QAtomicInt &p_stop, bool p_fast);
|
||||||
|
|
||||||
TimeStamp m_timeStamp;
|
TimeStamp m_timeStamp;
|
||||||
|
|
||||||
int m_numOfBlocks;
|
int m_numOfBlocks;
|
||||||
|
|
||||||
|
int m_offset;
|
||||||
|
|
||||||
pmh_element **m_pmhElements;
|
pmh_element **m_pmhElements;
|
||||||
|
|
||||||
// All image link regions.
|
// All image link regions.
|
||||||
@ -178,6 +189,8 @@ public:
|
|||||||
|
|
||||||
~PegParser();
|
~PegParser();
|
||||||
|
|
||||||
|
QSharedPointer<PegParseResult> parse(const QSharedPointer<PegParseConfig> &p_config);
|
||||||
|
|
||||||
void parseAsync(const QSharedPointer<PegParseConfig> &p_config);
|
void parseAsync(const QSharedPointer<PegParseConfig> &p_config);
|
||||||
|
|
||||||
static QVector<VElementRegion> parseImageRegions(const QSharedPointer<PegParseConfig> &p_config);
|
static QVector<VElementRegion> parseImageRegions(const QSharedPointer<PegParseConfig> &p_config);
|
||||||
|
@ -290,10 +290,10 @@ void VCodeBlockHighlightHelper::addToHighlightCache(const QString &p_text,
|
|||||||
const QVector<HLUnitPos> &p_units)
|
const QVector<HLUnitPos> &p_units)
|
||||||
{
|
{
|
||||||
const int c_maxEntries = 100;
|
const int c_maxEntries = 100;
|
||||||
const int c_maxTimeStampSpan = 3;
|
const TimeStamp c_maxTimeStampSpan = 3;
|
||||||
if (m_cache.size() >= c_maxEntries) {
|
if (m_cache.size() >= c_maxEntries) {
|
||||||
// Remove the oldest one.
|
// Remove the oldest one.
|
||||||
int ts = p_timeStamp - c_maxTimeStampSpan;
|
TimeStamp ts = p_timeStamp - c_maxTimeStampSpan;
|
||||||
for (auto it = m_cache.begin(); it != m_cache.end();) {
|
for (auto it = m_cache.begin(); it != m_cache.end();) {
|
||||||
if (it.value().m_timeStamp < ts) {
|
if (it.value().m_timeStamp < ts) {
|
||||||
it = m_cache.erase(it);
|
it = m_cache.erase(it);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "vpreviewmanager.h"
|
#include "vpreviewmanager.h"
|
||||||
|
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
#include <QDebug>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
@ -63,7 +62,6 @@ void VPreviewManager::imageDownloaded(const QByteArray &p_data, const QString &p
|
|||||||
|
|
||||||
if (!image.isNull()) {
|
if (!image.isNull()) {
|
||||||
m_editor->addImage(name, image);
|
m_editor->addImage(name, image);
|
||||||
qDebug() << "downloaded image inserted in resource manager" << p_url << name;
|
|
||||||
emit requestUpdateImageLinks();
|
emit requestUpdateImageLinks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,8 +170,6 @@ void VPreviewManager::fetchImageLinksFromRegions(QVector<VElementRegion> p_image
|
|||||||
}
|
}
|
||||||
|
|
||||||
p_imageLinks.append(info);
|
p_imageLinks.append(info);
|
||||||
|
|
||||||
qDebug() << "image region" << i << info.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,10 +400,6 @@ void VPreviewManager::updateBlockPreviewInfo(TS p_timeStamp,
|
|||||||
affectedBlocks.insert(link.m_blockNumber, QMapDummyValue());
|
affectedBlocks.insert(link.m_blockNumber, QMapDummyValue());
|
||||||
m_highlighter->addPossiblePreviewBlock(link.m_blockNumber);
|
m_highlighter->addPossiblePreviewBlock(link.m_blockNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "block" << link.m_blockNumber
|
|
||||||
<< imageCache(PreviewSource::ImageLink).size()
|
|
||||||
<< blockData->toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
relayoutEditor(affectedBlocks);
|
relayoutEditor(affectedBlocks);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user