mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 22:09:52 +08:00
refactor VCodeBlockHighlightHelper
1. Use QVector instead of QList; 2. Use cache for highlight result;
This commit is contained in:
parent
c3408769b0
commit
639d1cb9e9
@ -446,7 +446,7 @@ bool HGMarkdownHighlighter::updateCodeBlocks()
|
||||
m_codeBlockHighlights[i].clear();
|
||||
}
|
||||
|
||||
QList<VCodeBlock> codeBlocks;
|
||||
QVector<VCodeBlock> codeBlocks;
|
||||
|
||||
VCodeBlock item;
|
||||
bool inBlock = false;
|
||||
@ -509,7 +509,7 @@ static bool HLUnitStyleComp(const HLUnitStyle &a, const HLUnitStyle &b)
|
||||
}
|
||||
}
|
||||
|
||||
void HGMarkdownHighlighter::setCodeBlockHighlights(const QList<HLUnitPos> &p_units)
|
||||
void HGMarkdownHighlighter::setCodeBlockHighlights(const QVector<HLUnitPos> &p_units)
|
||||
{
|
||||
if (p_units.isEmpty()) {
|
||||
goto exit;
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <QSyntaxHighlighter>
|
||||
#include <QAtomicInt>
|
||||
#include <QSet>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
|
||||
@ -120,13 +119,13 @@ public:
|
||||
QTextDocument *parent = 0);
|
||||
~HGMarkdownHighlighter();
|
||||
// Request to update highlihgt (re-parse and re-highlight)
|
||||
void setCodeBlockHighlights(const QList<HLUnitPos> &p_units);
|
||||
void setCodeBlockHighlights(const QVector<HLUnitPos> &p_units);
|
||||
|
||||
signals:
|
||||
void highlightCompleted();
|
||||
|
||||
// QList is implicitly shared.
|
||||
void codeBlocksUpdated(const QList<VCodeBlock> &p_codeBlocks);
|
||||
// QVector is implicitly shared.
|
||||
void codeBlocksUpdated(const QVector<VCodeBlock> &p_codeBlocks);
|
||||
|
||||
// Emitted when image regions have been fetched from a new parsing result.
|
||||
void imageLinksUpdated(const QVector<VElementRegion> &p_imageRegions);
|
||||
|
@ -15,6 +15,8 @@ VCodeBlockHighlightHelper::VCodeBlockHighlightHelper(HGMarkdownHighlighter *p_hi
|
||||
this, &VCodeBlockHighlightHelper::handleCodeBlocksUpdated);
|
||||
connect(m_vdocument, &VDocument::textHighlighted,
|
||||
this, &VCodeBlockHighlightHelper::handleTextHighlightResult);
|
||||
|
||||
// Web side is ready for code block highlight.
|
||||
connect(m_vdocument, &VDocument::readyToHighlightText,
|
||||
m_highlighter, &HGMarkdownHighlighter::updateHighlight);
|
||||
}
|
||||
@ -52,14 +54,23 @@ QString VCodeBlockHighlightHelper::unindentCodeBlock(const QString &p_text)
|
||||
return res;
|
||||
}
|
||||
|
||||
void VCodeBlockHighlightHelper::handleCodeBlocksUpdated(const QList<VCodeBlock> &p_codeBlocks)
|
||||
void VCodeBlockHighlightHelper::handleCodeBlocksUpdated(const QVector<VCodeBlock> &p_codeBlocks)
|
||||
{
|
||||
int curStamp = m_timeStamp.fetchAndAddRelaxed(1) + 1;
|
||||
m_codeBlocks = p_codeBlocks;
|
||||
for (int i = 0; i < m_codeBlocks.size(); ++i) {
|
||||
QString unindentedText = unindentCodeBlock(m_codeBlocks[i].m_text);
|
||||
const VCodeBlock &block = m_codeBlocks[i];
|
||||
auto it = m_cache.find(block.m_text);
|
||||
if (it != m_cache.end()) {
|
||||
// Hit cache.
|
||||
qDebug() << "code block highlight hit cache" << curStamp << i;
|
||||
it.value().m_timeStamp = curStamp;
|
||||
updateHighlightResults(block.m_startPos, it.value().m_units);
|
||||
} else {
|
||||
QString unindentedText = unindentCodeBlock(block.m_text);
|
||||
m_vdocument->highlightTextAsync(unindentedText, i, curStamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VCodeBlockHighlightHelper::handleTextHighlightResult(const QString &p_html,
|
||||
@ -109,7 +120,7 @@ void VCodeBlockHighlightHelper::parseHighlightResult(int p_timeStamp,
|
||||
int startPos = block.m_startPos;
|
||||
QString text = block.m_text;
|
||||
|
||||
QList<HLUnitPos> hlUnits;
|
||||
QVector<HLUnitPos> hlUnits;
|
||||
|
||||
bool failed = true;
|
||||
|
||||
@ -153,7 +164,7 @@ void VCodeBlockHighlightHelper::parseHighlightResult(int p_timeStamp,
|
||||
failed = true;
|
||||
goto exit;
|
||||
}
|
||||
if (!parseSpanElement(xml, startPos, text, textIndex, hlUnits)) {
|
||||
if (!parseSpanElement(xml, text, textIndex, hlUnits)) {
|
||||
failed = true;
|
||||
goto exit;
|
||||
}
|
||||
@ -185,15 +196,27 @@ exit:
|
||||
hlUnits.clear();
|
||||
}
|
||||
|
||||
// Add it to cache.
|
||||
addToHighlightCache(text, p_timeStamp, hlUnits);
|
||||
|
||||
updateHighlightResults(startPos, hlUnits);
|
||||
}
|
||||
|
||||
void VCodeBlockHighlightHelper::updateHighlightResults(int p_startPos,
|
||||
QVector<HLUnitPos> p_units)
|
||||
{
|
||||
for (int i = 0; i < p_units.size(); ++i) {
|
||||
p_units[i].m_position += p_startPos;
|
||||
}
|
||||
|
||||
// We need to call this function anyway to trigger the rehighlight.
|
||||
m_highlighter->setCodeBlockHighlights(hlUnits);
|
||||
m_highlighter->setCodeBlockHighlights(p_units);
|
||||
}
|
||||
|
||||
bool VCodeBlockHighlightHelper::parseSpanElement(QXmlStreamReader &p_xml,
|
||||
int p_startPos,
|
||||
const QString &p_text,
|
||||
int &p_index,
|
||||
QList<HLUnitPos> &p_units)
|
||||
QVector<HLUnitPos> &p_units)
|
||||
{
|
||||
int unitStart = p_index;
|
||||
QString style = p_xml.attributes().value("class").toString();
|
||||
@ -215,7 +238,7 @@ bool VCodeBlockHighlightHelper::parseSpanElement(QXmlStreamReader &p_xml,
|
||||
}
|
||||
|
||||
// Sub-span.
|
||||
if (!parseSpanElement(p_xml, p_startPos, p_text, p_index, p_units)) {
|
||||
if (!parseSpanElement(p_xml, p_text, p_index, p_units)) {
|
||||
return false;
|
||||
}
|
||||
} else if (p_xml.isEndElement()) {
|
||||
@ -223,8 +246,8 @@ bool VCodeBlockHighlightHelper::parseSpanElement(QXmlStreamReader &p_xml,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Got a complete span.
|
||||
HLUnitPos unit(unitStart + p_startPos, p_index - unitStart, style);
|
||||
// Got a complete span. Use relative position here.
|
||||
HLUnitPos unit(unitStart, p_index - unitStart, style);
|
||||
p_units.append(unit);
|
||||
return true;
|
||||
} else {
|
||||
@ -233,3 +256,24 @@ bool VCodeBlockHighlightHelper::parseSpanElement(QXmlStreamReader &p_xml,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void VCodeBlockHighlightHelper::addToHighlightCache(const QString &p_text,
|
||||
int p_timeStamp,
|
||||
const QVector<HLUnitPos> &p_units)
|
||||
{
|
||||
const int c_maxEntries = 100;
|
||||
const int c_maxTimeStampSpan = 3;
|
||||
if (m_cache.size() >= c_maxEntries) {
|
||||
// Remove the oldest one.
|
||||
int ts = p_timeStamp - c_maxTimeStampSpan;
|
||||
for (auto it = m_cache.begin(); it != m_cache.end();) {
|
||||
if (it.value().m_timeStamp < ts) {
|
||||
it = m_cache.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_cache.insert(p_text, HLResult(p_timeStamp, p_units));
|
||||
}
|
||||
|
@ -2,9 +2,10 @@
|
||||
#define VCODEBLOCKHIGHLIGHTHELPER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVector>
|
||||
#include <QAtomicInteger>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QHash>
|
||||
#include "vconfigmanager.h"
|
||||
|
||||
class VDocument;
|
||||
@ -16,22 +17,36 @@ public:
|
||||
VCodeBlockHighlightHelper(HGMarkdownHighlighter *p_highlighter,
|
||||
VDocument *p_vdoc, MarkdownConverterType p_type);
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
void handleCodeBlocksUpdated(const QList<VCodeBlock> &p_codeBlocks);
|
||||
void handleCodeBlocksUpdated(const QVector<VCodeBlock> &p_codeBlocks);
|
||||
|
||||
void handleTextHighlightResult(const QString &p_html, int p_id, int p_timeStamp);
|
||||
|
||||
private:
|
||||
struct HLResult
|
||||
{
|
||||
HLResult() : m_timeStamp(-1)
|
||||
{
|
||||
}
|
||||
|
||||
HLResult(int p_timeStamp, const QVector<HLUnitPos> &p_units)
|
||||
: m_timeStamp(p_timeStamp), m_units(p_units)
|
||||
{
|
||||
}
|
||||
|
||||
int m_timeStamp;
|
||||
QVector<HLUnitPos> m_units;
|
||||
};
|
||||
|
||||
void parseHighlightResult(int p_timeStamp, int p_idx, const QString &p_html);
|
||||
|
||||
// @p_startPos: the global position of the start 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_units: all the highlight units of this code block;
|
||||
bool parseSpanElement(QXmlStreamReader &p_xml, int p_startPos,
|
||||
bool parseSpanElement(QXmlStreamReader &p_xml,
|
||||
const QString &p_text, int &p_index,
|
||||
QList<HLUnitPos> &p_units);
|
||||
QVector<HLUnitPos> &p_units);
|
||||
|
||||
// @p_text: text of fenced code block.
|
||||
// Get the indent level of the first line (fence) and unindent the whole block
|
||||
// to make the fence at the highest indent level.
|
||||
@ -39,11 +54,21 @@ private:
|
||||
// without any context.
|
||||
QString unindentCodeBlock(const QString &p_text);
|
||||
|
||||
void updateHighlightResults(int p_startPos, QVector<HLUnitPos> p_units);
|
||||
|
||||
void addToHighlightCache(const QString &p_text,
|
||||
int p_timeStamp,
|
||||
const QVector<HLUnitPos> &p_units);
|
||||
|
||||
HGMarkdownHighlighter *m_highlighter;
|
||||
VDocument *m_vdocument;
|
||||
MarkdownConverterType m_type;
|
||||
QAtomicInteger<int> m_timeStamp;
|
||||
QList<VCodeBlock> m_codeBlocks;
|
||||
QVector<VCodeBlock> m_codeBlocks;
|
||||
|
||||
// Cache for highlight result, using the code block text as key.
|
||||
// The HLResult has relative position only.
|
||||
QHash<QString, HLResult> m_cache;
|
||||
};
|
||||
|
||||
#endif // VCODEBLOCKHIGHLIGHTHELPER_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user