mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
PegMarkdownHighlighter: cache result for performance
This commit is contained in:
parent
24a20e60e9
commit
bfac189cb7
@ -4,7 +4,6 @@
|
|||||||
#include <QTextCharFormat>
|
#include <QTextCharFormat>
|
||||||
|
|
||||||
#include "vconstants.h"
|
#include "vconstants.h"
|
||||||
#include "vtextblockdata.h"
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <pmh_parser.h>
|
#include <pmh_parser.h>
|
||||||
@ -26,6 +25,18 @@ struct HLUnit
|
|||||||
unsigned long start;
|
unsigned long start;
|
||||||
unsigned long length;
|
unsigned long length;
|
||||||
unsigned int styleIndex;
|
unsigned int styleIndex;
|
||||||
|
|
||||||
|
bool operator==(const HLUnit &p_a) const
|
||||||
|
{
|
||||||
|
return start == p_a.start
|
||||||
|
&& length == p_a.length
|
||||||
|
&& styleIndex == p_a.styleIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toString() const
|
||||||
|
{
|
||||||
|
return QString("HLUnit %1 %2 %3").arg(start).arg(length).arg(styleIndex);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HLUnitStyle
|
struct HLUnitStyle
|
||||||
@ -33,6 +44,15 @@ struct HLUnitStyle
|
|||||||
unsigned long start;
|
unsigned long start;
|
||||||
unsigned long length;
|
unsigned long length;
|
||||||
QString style;
|
QString style;
|
||||||
|
|
||||||
|
bool operator==(const HLUnitStyle &p_a) const
|
||||||
|
{
|
||||||
|
if (start != p_a.start || length != p_a.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return style == p_a.style;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fenced code block only.
|
// Fenced code block only.
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef PEGHIGHLIGHTERRESULT_H
|
#ifndef PEGHIGHLIGHTERRESULT_H
|
||||||
#define PEGHIGHLIGHTERRESULT_H
|
#define PEGHIGHLIGHTERRESULT_H
|
||||||
|
|
||||||
|
#include <QSet>
|
||||||
|
|
||||||
#include "vconstants.h"
|
#include "vconstants.h"
|
||||||
#include "pegparser.h"
|
#include "pegparser.h"
|
||||||
|
|
||||||
|
@ -12,13 +12,14 @@
|
|||||||
|
|
||||||
extern VConfigManager *g_config;
|
extern VConfigManager *g_config;
|
||||||
|
|
||||||
#define LARGE_BLOCK_NUMBER 2000
|
#define LARGE_BLOCK_NUMBER 1000
|
||||||
|
|
||||||
PegMarkdownHighlighter::PegMarkdownHighlighter(QTextDocument *p_doc, VMdEditor *p_editor)
|
PegMarkdownHighlighter::PegMarkdownHighlighter(QTextDocument *p_doc, VMdEditor *p_editor)
|
||||||
: QSyntaxHighlighter(p_doc),
|
: QSyntaxHighlighter(p_doc),
|
||||||
m_doc(p_doc),
|
m_doc(p_doc),
|
||||||
m_editor(p_editor),
|
m_editor(p_editor),
|
||||||
m_timeStamp(0),
|
m_timeStamp(0),
|
||||||
|
m_codeBlockTimeStamp(0),
|
||||||
m_parser(NULL),
|
m_parser(NULL),
|
||||||
m_parserExts(pmh_EXT_NOTES | pmh_EXT_STRIKE | pmh_EXT_FRONTMATTER | pmh_EXT_MARK)
|
m_parserExts(pmh_EXT_NOTES | pmh_EXT_STRIKE | pmh_EXT_FRONTMATTER | pmh_EXT_MARK)
|
||||||
{
|
{
|
||||||
@ -114,39 +115,62 @@ void PegMarkdownHighlighter::highlightBlock(const QString &p_text)
|
|||||||
QTextBlock block = currentBlock();
|
QTextBlock block = currentBlock();
|
||||||
int blockNum = block.blockNumber();
|
int blockNum = block.blockNumber();
|
||||||
|
|
||||||
if (result->matched(m_timeStamp)) {
|
VTextBlockData *blockData = PegMarkdownHighlighter::getBlockData(block);
|
||||||
preHighlightSingleFormatBlock(result->m_blocksHighlights, blockNum, p_text);
|
QVector<HLUnit> *cache = NULL;
|
||||||
|
QVector<HLUnitStyle> *cbCache = NULL;
|
||||||
|
if (blockData) {
|
||||||
|
cache = &blockData->getBlockHighlightCache();
|
||||||
|
cbCache = &blockData->getCodeBlockHighlightCache();
|
||||||
|
|
||||||
highlightBlockOne(result->m_blocksHighlights, blockNum);
|
cache->clear();
|
||||||
|
cbCache->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cacheValid = true;
|
||||||
|
|
||||||
|
if (result->matched(m_timeStamp)) {
|
||||||
|
if (preHighlightSingleFormatBlock(result->m_blocksHighlights, blockNum, p_text)) {
|
||||||
|
cacheValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
highlightBlockOne(result->m_blocksHighlights, blockNum, cacheValid ? cache : NULL);
|
||||||
} else {
|
} else {
|
||||||
preHighlightSingleFormatBlock(m_fastResult->m_blocksHighlights, blockNum, p_text);
|
if (preHighlightSingleFormatBlock(m_fastResult->m_blocksHighlights, blockNum, p_text)) {
|
||||||
|
cacheValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
// If fast result cover this block, we do not need to use the outdated one.
|
// If fast result cover this block, we do not need to use the outdated one.
|
||||||
if (!highlightBlockOne(m_fastResult->m_blocksHighlights, blockNum)) {
|
if (highlightBlockOne(m_fastResult->m_blocksHighlights, blockNum, NULL)) {
|
||||||
highlightBlockOne(result->m_blocksHighlights, blockNum);
|
cacheValid = false;
|
||||||
|
} else {
|
||||||
|
highlightBlockOne(result->m_blocksHighlights, blockNum, cacheValid ? cache : NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentBlockState() == HighlightBlockState::CodeBlock) {
|
if (currentBlockState() == HighlightBlockState::CodeBlock) {
|
||||||
highlightCodeBlock(result, blockNum, p_text);
|
highlightCodeBlock(result, blockNum, p_text, cacheValid ? cbCache : NULL);
|
||||||
highlightCodeBlockColorColumn(p_text);
|
highlightCodeBlockColorColumn(p_text);
|
||||||
PegMarkdownHighlighter::updateBlockCodeBlockTimeStamp(block, result->m_codeBlockTimeStamp);
|
PegMarkdownHighlighter::updateBlockCodeBlockTimeStamp(block, result->m_codeBlockTimeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
PegMarkdownHighlighter::updateBlockTimeStamp(block, result->m_timeStamp);
|
PegMarkdownHighlighter::updateBlockTimeStamp(block, result->m_timeStamp);
|
||||||
|
|
||||||
|
if (blockData) {
|
||||||
|
blockData->setCacheValid(cacheValid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PegMarkdownHighlighter::preHighlightSingleFormatBlock(const QVector<QVector<HLUnit>> &p_highlights,
|
bool PegMarkdownHighlighter::preHighlightSingleFormatBlock(const QVector<QVector<HLUnit>> &p_highlights,
|
||||||
int p_blockNum,
|
int p_blockNum,
|
||||||
const QString &p_text)
|
const QString &p_text)
|
||||||
{
|
{
|
||||||
int sz = p_text.size();
|
int sz = p_text.size();
|
||||||
if (sz == 0) {
|
if (sz == 0) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_singleFormatBlocks.contains(p_blockNum)) {
|
if (!m_singleFormatBlocks.contains(p_blockNum)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_highlights.size() > p_blockNum) {
|
if (p_highlights.size() > p_blockNum) {
|
||||||
@ -155,13 +179,17 @@ void PegMarkdownHighlighter::preHighlightSingleFormatBlock(const QVector<QVector
|
|||||||
const HLUnit &unit = units[0];
|
const HLUnit &unit = units[0];
|
||||||
if (unit.start == 0 && (int)unit.length < sz) {
|
if (unit.start == 0 && (int)unit.length < sz) {
|
||||||
setFormat(unit.length, sz - unit.length, m_styles[unit.styleIndex].format);
|
setFormat(unit.length, sz - unit.length, m_styles[unit.styleIndex].format);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PegMarkdownHighlighter::highlightBlockOne(const QVector<QVector<HLUnit>> &p_highlights,
|
bool PegMarkdownHighlighter::highlightBlockOne(const QVector<QVector<HLUnit>> &p_highlights,
|
||||||
int p_blockNum)
|
int p_blockNum,
|
||||||
|
QVector<HLUnit> *p_cache)
|
||||||
{
|
{
|
||||||
bool highlighted = false;
|
bool highlighted = false;
|
||||||
if (p_highlights.size() > p_blockNum) {
|
if (p_highlights.size() > p_blockNum) {
|
||||||
@ -169,6 +197,10 @@ bool PegMarkdownHighlighter::highlightBlockOne(const QVector<QVector<HLUnit>> &p
|
|||||||
const QVector<HLUnit> &units = p_highlights[p_blockNum];
|
const QVector<HLUnit> &units = p_highlights[p_blockNum];
|
||||||
if (!units.isEmpty()) {
|
if (!units.isEmpty()) {
|
||||||
highlighted = true;
|
highlighted = true;
|
||||||
|
if (p_cache) {
|
||||||
|
p_cache->append(units);
|
||||||
|
}
|
||||||
|
|
||||||
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];
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
@ -357,7 +389,7 @@ void PegMarkdownHighlighter::setCodeBlockHighlights(TimeStamp p_timeStamp,
|
|||||||
|
|
||||||
exit:
|
exit:
|
||||||
if (--result->m_numOfCodeBlockHighlightsToRecv <= 0) {
|
if (--result->m_numOfCodeBlockHighlightsToRecv <= 0) {
|
||||||
++result->m_codeBlockTimeStamp;
|
result->m_codeBlockTimeStamp = nextCodeBlockTimeStamp();
|
||||||
rehighlightBlocks();
|
rehighlightBlocks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -383,6 +415,8 @@ void PegMarkdownHighlighter::handleParseResult(const QSharedPointer<PegParseResu
|
|||||||
|
|
||||||
m_result.reset(new PegHighlighterResult(this, p_result));
|
m_result.reset(new PegHighlighterResult(this, p_result));
|
||||||
|
|
||||||
|
m_result->m_codeBlockTimeStamp = nextCodeBlockTimeStamp();
|
||||||
|
|
||||||
m_singleFormatBlocks.clear();
|
m_singleFormatBlocks.clear();
|
||||||
updateSingleFormatBlocks(m_result->m_blocksHighlights);
|
updateSingleFormatBlocks(m_result->m_blocksHighlights);
|
||||||
|
|
||||||
@ -421,10 +455,14 @@ void PegMarkdownHighlighter::updateSingleFormatBlocks(const QVector<QVector<HLUn
|
|||||||
void PegMarkdownHighlighter::updateCodeBlocks(const QSharedPointer<PegHighlighterResult> &p_result)
|
void PegMarkdownHighlighter::updateCodeBlocks(const QSharedPointer<PegHighlighterResult> &p_result)
|
||||||
{
|
{
|
||||||
// Only need to receive code block highlights when it is empty.
|
// Only need to receive code block highlights when it is empty.
|
||||||
if (g_config->getEnableCodeBlockHighlight()
|
if (g_config->getEnableCodeBlockHighlight()) {
|
||||||
&& PegMarkdownHighlighter::isEmptyCodeBlockHighlights(p_result->m_codeBlocksHighlights)) {
|
int cbSz = p_result->m_codeBlocks.size();
|
||||||
|
if (cbSz > 0) {
|
||||||
|
if (PegMarkdownHighlighter::isEmptyCodeBlockHighlights(p_result->m_codeBlocksHighlights)) {
|
||||||
p_result->m_codeBlocksHighlights.resize(p_result->m_numOfBlocks);
|
p_result->m_codeBlocksHighlights.resize(p_result->m_numOfBlocks);
|
||||||
p_result->m_numOfCodeBlockHighlightsToRecv = p_result->m_codeBlocks.size();
|
p_result->m_numOfCodeBlockHighlightsToRecv = cbSz;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit codeBlocksUpdated(p_result->m_timeStamp, p_result->m_codeBlocks);
|
emit codeBlocksUpdated(p_result->m_timeStamp, p_result->m_codeBlocks);
|
||||||
@ -530,7 +568,8 @@ void PegMarkdownHighlighter::updateAllBlocksUserState(const QSharedPointer<PegHi
|
|||||||
|
|
||||||
void PegMarkdownHighlighter::highlightCodeBlock(const QSharedPointer<PegHighlighterResult> &p_result,
|
void PegMarkdownHighlighter::highlightCodeBlock(const QSharedPointer<PegHighlighterResult> &p_result,
|
||||||
int p_blockNum,
|
int p_blockNum,
|
||||||
const QString &p_text)
|
const QString &p_text,
|
||||||
|
QVector<HLUnitStyle> *p_cache)
|
||||||
{
|
{
|
||||||
// Brush the indentation spaces.
|
// Brush the indentation spaces.
|
||||||
if (currentBlockState() == HighlightBlockState::CodeBlock) {
|
if (currentBlockState() == HighlightBlockState::CodeBlock) {
|
||||||
@ -544,6 +583,10 @@ void PegMarkdownHighlighter::highlightCodeBlock(const QSharedPointer<PegHighligh
|
|||||||
const QVector<HLUnitStyle> &units = p_result->m_codeBlocksHighlights[p_blockNum];
|
const QVector<HLUnitStyle> &units = p_result->m_codeBlocksHighlights[p_blockNum];
|
||||||
if (!units.isEmpty()) {
|
if (!units.isEmpty()) {
|
||||||
QVector<QTextCharFormat *> formats(units.size(), NULL);
|
QVector<QTextCharFormat *> formats(units.size(), NULL);
|
||||||
|
if (p_cache) {
|
||||||
|
p_cache->append(units);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < units.size(); ++i) {
|
for (int i = 0; i < units.size(); ++i) {
|
||||||
const HLUnitStyle &unit = units[i];
|
const HLUnitStyle &unit = units[i];
|
||||||
auto it = m_codeBlockStyles.find(unit.style);
|
auto it = m_codeBlockStyles.find(unit.style);
|
||||||
@ -753,7 +796,10 @@ bool PegMarkdownHighlighter::rehighlightBlockRange(int p_first, int p_last)
|
|||||||
{
|
{
|
||||||
bool highlighted = false;
|
bool highlighted = false;
|
||||||
const QHash<int, HighlightBlockState> &cbStates = m_result->m_codeBlocksState;
|
const QHash<int, HighlightBlockState> &cbStates = m_result->m_codeBlocksState;
|
||||||
|
const QVector<QVector<HLUnit>> &hls = m_result->m_blocksHighlights;
|
||||||
|
const QVector<QVector<HLUnitStyle>> &cbHls = m_result->m_codeBlocksHighlights;
|
||||||
|
|
||||||
|
int nr = 0;
|
||||||
QTextBlock block = m_doc->findBlockByNumber(p_first);
|
QTextBlock block = m_doc->findBlockByNumber(p_first);
|
||||||
while (block.isValid()) {
|
while (block.isValid()) {
|
||||||
int blockNum = block.blockNumber();
|
int blockNum = block.blockNumber();
|
||||||
@ -761,23 +807,53 @@ bool PegMarkdownHighlighter::rehighlightBlockRange(int p_first, int p_last)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needHL = PegMarkdownHighlighter::blockTimeStamp(block) != m_result->m_timeStamp;
|
bool needHL = false;
|
||||||
if (!needHL) {
|
bool updateTS = false;
|
||||||
auto it = cbStates.find(blockNum);
|
VTextBlockData *data = PegMarkdownHighlighter::getBlockData(block);
|
||||||
if (it != cbStates.end()
|
if (PegMarkdownHighlighter::blockTimeStamp(block) != m_result->m_timeStamp) {
|
||||||
&& it.value() == HighlightBlockState::CodeBlock
|
|
||||||
&& PegMarkdownHighlighter::blockCodeBlockTimeStamp(block) != m_result->m_codeBlockTimeStamp) {
|
|
||||||
needHL = true;
|
needHL = true;
|
||||||
|
// Try to find cache.
|
||||||
|
if (data && blockNum < hls.size()) {
|
||||||
|
if (data->isBlockHighlightCacheMatched(hls[blockNum])) {
|
||||||
|
needHL = false;
|
||||||
|
updateTS = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needHL) {
|
||||||
|
// FIXME: what about a previous code block turn into a non-code block? For now,
|
||||||
|
// they can be distinguished by block highlights.
|
||||||
|
auto it = cbStates.find(blockNum);
|
||||||
|
if (it != cbStates.end() && it.value() == HighlightBlockState::CodeBlock) {
|
||||||
|
if (PegMarkdownHighlighter::blockCodeBlockTimeStamp(block) != m_result->m_codeBlockTimeStamp) {
|
||||||
|
needHL = true;
|
||||||
|
// Try to find cache.
|
||||||
|
if (updateTS && data && blockNum < cbHls.size()) {
|
||||||
|
if (data->isCodeBlockHighlightCacheMatched(cbHls[blockNum])) {
|
||||||
|
needHL = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needHL && data && !data->getPreviews().isEmpty()) {
|
||||||
|
needHL = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (needHL) {
|
if (needHL) {
|
||||||
highlighted = true;
|
highlighted = true;
|
||||||
rehighlightBlock(block);
|
rehighlightBlock(block);
|
||||||
|
++nr;
|
||||||
|
} else if (updateTS) {
|
||||||
|
data->setTimeStamp(m_result->m_timeStamp);
|
||||||
|
data->setCodeBlockTimeStamp(m_result->m_codeBlockTimeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
block = block.next();
|
block = block.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qDebug() << "rehighlightBlockRange" << p_first << p_last << nr;
|
||||||
return highlighted;
|
return highlighted;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,8 @@ private:
|
|||||||
// Highlight fenced code block according to VCodeBlockHighlightHelper result.
|
// Highlight fenced code block according to VCodeBlockHighlightHelper result.
|
||||||
void highlightCodeBlock(const QSharedPointer<PegHighlighterResult> &p_result,
|
void highlightCodeBlock(const QSharedPointer<PegHighlighterResult> &p_result,
|
||||||
int p_blockNum,
|
int p_blockNum,
|
||||||
const QString &p_text);
|
const QString &p_text,
|
||||||
|
QVector<HLUnitStyle> *p_cache);
|
||||||
|
|
||||||
// Highlight color column in code block.
|
// Highlight color column in code block.
|
||||||
void highlightCodeBlockColorColumn(const QString &p_text);
|
void highlightCodeBlockColorColumn(const QString &p_text);
|
||||||
@ -114,10 +115,11 @@ private:
|
|||||||
void processFastParseResult(const QSharedPointer<PegParseResult> &p_result);
|
void processFastParseResult(const QSharedPointer<PegParseResult> &p_result);
|
||||||
|
|
||||||
bool highlightBlockOne(const QVector<QVector<HLUnit>> &p_highlights,
|
bool highlightBlockOne(const QVector<QVector<HLUnit>> &p_highlights,
|
||||||
int p_blockNum);
|
int p_blockNum,
|
||||||
|
QVector<HLUnit> *p_cache);
|
||||||
|
|
||||||
// To avoid line height jitter.
|
// To avoid line height jitter.
|
||||||
void preHighlightSingleFormatBlock(const QVector<QVector<HLUnit>> &p_highlights,
|
bool preHighlightSingleFormatBlock(const QVector<QVector<HLUnit>> &p_highlights,
|
||||||
int p_blockNum,
|
int p_blockNum,
|
||||||
const QString &p_text);
|
const QString &p_text);
|
||||||
|
|
||||||
@ -127,6 +129,10 @@ private:
|
|||||||
|
|
||||||
bool rehighlightBlockRange(int p_first, int p_last);
|
bool rehighlightBlockRange(int p_first, int p_last);
|
||||||
|
|
||||||
|
TimeStamp nextCodeBlockTimeStamp();
|
||||||
|
|
||||||
|
static VTextBlockData *getBlockData(const QTextBlock &p_block);
|
||||||
|
|
||||||
static bool isEmptyCodeBlockHighlights(const QVector<QVector<HLUnitStyle>> &p_highlights);
|
static bool isEmptyCodeBlockHighlights(const QVector<QVector<HLUnitStyle>> &p_highlights);
|
||||||
|
|
||||||
static TimeStamp blockTimeStamp(const QTextBlock &p_block);
|
static TimeStamp blockTimeStamp(const QTextBlock &p_block);
|
||||||
@ -143,6 +149,8 @@ private:
|
|||||||
|
|
||||||
TimeStamp m_timeStamp;
|
TimeStamp m_timeStamp;
|
||||||
|
|
||||||
|
TimeStamp m_codeBlockTimeStamp;
|
||||||
|
|
||||||
QVector<HighlightingStyle> m_styles;
|
QVector<HighlightingStyle> m_styles;
|
||||||
QHash<QString, QTextCharFormat> m_codeBlockStyles;
|
QHash<QString, QTextCharFormat> m_codeBlockStyles;
|
||||||
|
|
||||||
@ -300,4 +308,14 @@ inline bool PegMarkdownHighlighter::isEmptyCodeBlockHighlights(const QVector<QVe
|
|||||||
|
|
||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline VTextBlockData *PegMarkdownHighlighter::getBlockData(const QTextBlock &p_block)
|
||||||
|
{
|
||||||
|
return static_cast<VTextBlockData *>(p_block.userData());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TimeStamp PegMarkdownHighlighter::nextCodeBlockTimeStamp()
|
||||||
|
{
|
||||||
|
return ++m_codeBlockTimeStamp;
|
||||||
|
}
|
||||||
#endif // PEGMARKDOWNHIGHLIGHTER_H
|
#endif // PEGMARKDOWNHIGHLIGHTER_H
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <QTreeWidgetItem>
|
#include <QTreeWidgetItem>
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
|
#include <QFontDatabase>
|
||||||
|
|
||||||
#include "vorphanfile.h"
|
#include "vorphanfile.h"
|
||||||
#include "vnote.h"
|
#include "vnote.h"
|
||||||
|
@ -55,7 +55,7 @@ VMdEditor::VMdEditor(VFile *p_file,
|
|||||||
connect(document(), &QTextDocument::contentsChange,
|
connect(document(), &QTextDocument::contentsChange,
|
||||||
this, [this](int p_position, int p_charsRemoved, int p_charsAdded) {
|
this, [this](int p_position, int p_charsRemoved, int p_charsAdded) {
|
||||||
Q_UNUSED(p_position);
|
Q_UNUSED(p_position);
|
||||||
if (p_charsAdded > 0 || p_charsAdded > 0) {
|
if (p_charsRemoved > 0 || p_charsAdded > 0) {
|
||||||
updateTimeStamp();
|
updateTimeStamp();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStyleFactory>
|
#include <QStyleFactory>
|
||||||
#include <QWidgetAction>
|
#include <QWidgetAction>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
#include "veditwindow.h"
|
#include "veditwindow.h"
|
||||||
#include "vnotefile.h"
|
#include "vnotefile.h"
|
||||||
|
@ -4,6 +4,7 @@ VTextBlockData::VTextBlockData()
|
|||||||
: QTextBlockUserData(),
|
: QTextBlockUserData(),
|
||||||
m_timeStamp(0),
|
m_timeStamp(0),
|
||||||
m_codeBlockTimeStamp(0),
|
m_codeBlockTimeStamp(0),
|
||||||
|
m_cacheValid(false),
|
||||||
m_codeBlockIndentation(-1)
|
m_codeBlockIndentation(-1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
#include <QTextBlockUserData>
|
#include <QTextBlockUserData>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include "vconstants.h"
|
#include "vconstants.h"
|
||||||
|
#include "markdownhighlighterdata.h"
|
||||||
|
|
||||||
// Sources of the preview.
|
// Sources of the preview.
|
||||||
enum class PreviewSource
|
enum class PreviewSource
|
||||||
@ -173,6 +175,22 @@ public:
|
|||||||
|
|
||||||
void setCodeBlockTimeStamp(TimeStamp p_ts);
|
void setCodeBlockTimeStamp(TimeStamp p_ts);
|
||||||
|
|
||||||
|
bool isBlockHighlightCacheMatched(const QVector<HLUnit> &p_highlight) const;
|
||||||
|
|
||||||
|
QVector<HLUnit> &getBlockHighlightCache();
|
||||||
|
|
||||||
|
void setBlockHighlightCache(const QVector<HLUnit> &p_highlight);
|
||||||
|
|
||||||
|
bool isCodeBlockHighlightCacheMatched(const QVector<HLUnitStyle> &p_highlight) const;
|
||||||
|
|
||||||
|
QVector<HLUnitStyle> &getCodeBlockHighlightCache();
|
||||||
|
|
||||||
|
void setCodeBlockHighlightCache(const QVector<HLUnitStyle> &p_highlight);
|
||||||
|
|
||||||
|
bool isCacheValid() const;
|
||||||
|
|
||||||
|
void setCacheValid(bool p_valid);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Check the order of elements.
|
// Check the order of elements.
|
||||||
bool checkOrder() const;
|
bool checkOrder() const;
|
||||||
@ -183,6 +201,15 @@ private:
|
|||||||
// TimeStamp of the code block highlight result which has been applied to this block.
|
// TimeStamp of the code block highlight result which has been applied to this block.
|
||||||
TimeStamp m_codeBlockTimeStamp;
|
TimeStamp m_codeBlockTimeStamp;
|
||||||
|
|
||||||
|
// Block highlight cache.
|
||||||
|
QVector<HLUnit> m_blockHighlightCache;
|
||||||
|
|
||||||
|
// Code block highlight cache.
|
||||||
|
QVector<HLUnitStyle> m_codeBlockHighlightCache;
|
||||||
|
|
||||||
|
// Whether the above two cahces are valid.
|
||||||
|
bool m_cacheValid;
|
||||||
|
|
||||||
// Sorted by m_imageInfo.m_startPos, with no two element's position intersected.
|
// Sorted by m_imageInfo.m_startPos, with no two element's position intersected.
|
||||||
QVector<VPreviewInfo *> m_previews;
|
QVector<VPreviewInfo *> m_previews;
|
||||||
|
|
||||||
@ -224,4 +251,70 @@ inline void VTextBlockData::setCodeBlockTimeStamp(TimeStamp p_ts)
|
|||||||
{
|
{
|
||||||
m_codeBlockTimeStamp = p_ts;
|
m_codeBlockTimeStamp = p_ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool VTextBlockData::isBlockHighlightCacheMatched(const QVector<HLUnit> &p_highlight) const
|
||||||
|
{
|
||||||
|
if (!m_cacheValid
|
||||||
|
|| p_highlight.size() != m_blockHighlightCache.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sz = p_highlight.size();
|
||||||
|
for (int i = 0; i < sz; ++i)
|
||||||
|
{
|
||||||
|
if (!(p_highlight[i] == m_blockHighlightCache[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QVector<HLUnit> &VTextBlockData::getBlockHighlightCache()
|
||||||
|
{
|
||||||
|
return m_blockHighlightCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void VTextBlockData::setBlockHighlightCache(const QVector<HLUnit> &p_highlight)
|
||||||
|
{
|
||||||
|
m_blockHighlightCache = p_highlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VTextBlockData::isCodeBlockHighlightCacheMatched(const QVector<HLUnitStyle> &p_highlight) const
|
||||||
|
{
|
||||||
|
if (!m_cacheValid
|
||||||
|
|| p_highlight.size() != m_codeBlockHighlightCache.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sz = p_highlight.size();
|
||||||
|
for (int i = 0; i < sz; ++i)
|
||||||
|
{
|
||||||
|
if (!(p_highlight[i] == m_codeBlockHighlightCache[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QVector<HLUnitStyle> &VTextBlockData::getCodeBlockHighlightCache()
|
||||||
|
{
|
||||||
|
return m_codeBlockHighlightCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void VTextBlockData::setCodeBlockHighlightCache(const QVector<HLUnitStyle> &p_highlight)
|
||||||
|
{
|
||||||
|
m_codeBlockHighlightCache = p_highlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool VTextBlockData::isCacheValid() const
|
||||||
|
{
|
||||||
|
return m_cacheValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void VTextBlockData::setCacheValid(bool p_valid)
|
||||||
|
{
|
||||||
|
m_cacheValid = p_valid;
|
||||||
|
}
|
||||||
#endif // VTEXTBLOCKDATA_H
|
#endif // VTEXTBLOCKDATA_H
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <QInputMethod>
|
#include <QInputMethod>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
#include "vpalette.h"
|
#include "vpalette.h"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user