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();
|
m_codeBlockHighlights[i].clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<VCodeBlock> codeBlocks;
|
QVector<VCodeBlock> codeBlocks;
|
||||||
|
|
||||||
VCodeBlock item;
|
VCodeBlock item;
|
||||||
bool inBlock = false;
|
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()) {
|
if (p_units.isEmpty()) {
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include <QSyntaxHighlighter>
|
#include <QSyntaxHighlighter>
|
||||||
#include <QAtomicInt>
|
#include <QAtomicInt>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QList>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
|
||||||
@ -120,13 +119,13 @@ public:
|
|||||||
QTextDocument *parent = 0);
|
QTextDocument *parent = 0);
|
||||||
~HGMarkdownHighlighter();
|
~HGMarkdownHighlighter();
|
||||||
// Request to update highlihgt (re-parse and re-highlight)
|
// Request to update highlihgt (re-parse and re-highlight)
|
||||||
void setCodeBlockHighlights(const QList<HLUnitPos> &p_units);
|
void setCodeBlockHighlights(const QVector<HLUnitPos> &p_units);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void highlightCompleted();
|
void highlightCompleted();
|
||||||
|
|
||||||
// QList is implicitly shared.
|
// QVector is implicitly shared.
|
||||||
void codeBlocksUpdated(const QList<VCodeBlock> &p_codeBlocks);
|
void codeBlocksUpdated(const QVector<VCodeBlock> &p_codeBlocks);
|
||||||
|
|
||||||
// Emitted when image regions have been fetched from a new parsing result.
|
// Emitted when image regions have been fetched from a new parsing result.
|
||||||
void imageLinksUpdated(const QVector<VElementRegion> &p_imageRegions);
|
void imageLinksUpdated(const QVector<VElementRegion> &p_imageRegions);
|
||||||
|
@ -15,6 +15,8 @@ VCodeBlockHighlightHelper::VCodeBlockHighlightHelper(HGMarkdownHighlighter *p_hi
|
|||||||
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.
|
||||||
connect(m_vdocument, &VDocument::readyToHighlightText,
|
connect(m_vdocument, &VDocument::readyToHighlightText,
|
||||||
m_highlighter, &HGMarkdownHighlighter::updateHighlight);
|
m_highlighter, &HGMarkdownHighlighter::updateHighlight);
|
||||||
}
|
}
|
||||||
@ -52,14 +54,23 @@ QString VCodeBlockHighlightHelper::unindentCodeBlock(const QString &p_text)
|
|||||||
return res;
|
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;
|
int curStamp = m_timeStamp.fetchAndAddRelaxed(1) + 1;
|
||||||
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) {
|
||||||
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);
|
m_vdocument->highlightTextAsync(unindentedText, i, curStamp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCodeBlockHighlightHelper::handleTextHighlightResult(const QString &p_html,
|
void VCodeBlockHighlightHelper::handleTextHighlightResult(const QString &p_html,
|
||||||
@ -109,7 +120,7 @@ void VCodeBlockHighlightHelper::parseHighlightResult(int p_timeStamp,
|
|||||||
int startPos = block.m_startPos;
|
int startPos = block.m_startPos;
|
||||||
QString text = block.m_text;
|
QString text = block.m_text;
|
||||||
|
|
||||||
QList<HLUnitPos> hlUnits;
|
QVector<HLUnitPos> hlUnits;
|
||||||
|
|
||||||
bool failed = true;
|
bool failed = true;
|
||||||
|
|
||||||
@ -153,7 +164,7 @@ void VCodeBlockHighlightHelper::parseHighlightResult(int p_timeStamp,
|
|||||||
failed = true;
|
failed = true;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
if (!parseSpanElement(xml, startPos, text, textIndex, hlUnits)) {
|
if (!parseSpanElement(xml, text, textIndex, hlUnits)) {
|
||||||
failed = true;
|
failed = true;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@ -185,15 +196,27 @@ exit:
|
|||||||
hlUnits.clear();
|
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.
|
// 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,
|
bool VCodeBlockHighlightHelper::parseSpanElement(QXmlStreamReader &p_xml,
|
||||||
int p_startPos,
|
|
||||||
const QString &p_text,
|
const QString &p_text,
|
||||||
int &p_index,
|
int &p_index,
|
||||||
QList<HLUnitPos> &p_units)
|
QVector<HLUnitPos> &p_units)
|
||||||
{
|
{
|
||||||
int unitStart = p_index;
|
int unitStart = p_index;
|
||||||
QString style = p_xml.attributes().value("class").toString();
|
QString style = p_xml.attributes().value("class").toString();
|
||||||
@ -215,7 +238,7 @@ bool VCodeBlockHighlightHelper::parseSpanElement(QXmlStreamReader &p_xml,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sub-span.
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (p_xml.isEndElement()) {
|
} else if (p_xml.isEndElement()) {
|
||||||
@ -223,8 +246,8 @@ bool VCodeBlockHighlightHelper::parseSpanElement(QXmlStreamReader &p_xml,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Got a complete span.
|
// Got a complete span. Use relative position here.
|
||||||
HLUnitPos unit(unitStart + p_startPos, p_index - unitStart, style);
|
HLUnitPos unit(unitStart, p_index - unitStart, style);
|
||||||
p_units.append(unit);
|
p_units.append(unit);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -233,3 +256,24 @@ bool VCodeBlockHighlightHelper::parseSpanElement(QXmlStreamReader &p_xml,
|
|||||||
}
|
}
|
||||||
return false;
|
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
|
#define VCODEBLOCKHIGHLIGHTHELPER_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QList>
|
#include <QVector>
|
||||||
#include <QAtomicInteger>
|
#include <QAtomicInteger>
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
|
#include <QHash>
|
||||||
#include "vconfigmanager.h"
|
#include "vconfigmanager.h"
|
||||||
|
|
||||||
class VDocument;
|
class VDocument;
|
||||||
@ -16,22 +17,36 @@ public:
|
|||||||
VCodeBlockHighlightHelper(HGMarkdownHighlighter *p_highlighter,
|
VCodeBlockHighlightHelper(HGMarkdownHighlighter *p_highlighter,
|
||||||
VDocument *p_vdoc, MarkdownConverterType p_type);
|
VDocument *p_vdoc, MarkdownConverterType p_type);
|
||||||
|
|
||||||
signals:
|
|
||||||
|
|
||||||
private slots:
|
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);
|
void handleTextHighlightResult(const QString &p_html, int p_id, int p_timeStamp);
|
||||||
|
|
||||||
private:
|
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);
|
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_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;
|
||||||
// @p_units: all the highlight units of this code block;
|
// @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,
|
const QString &p_text, int &p_index,
|
||||||
QList<HLUnitPos> &p_units);
|
QVector<HLUnitPos> &p_units);
|
||||||
|
|
||||||
// @p_text: text of fenced code block.
|
// @p_text: text of fenced code block.
|
||||||
// Get the indent level of the first line (fence) and unindent the whole block
|
// Get the indent level of the first line (fence) and unindent the whole block
|
||||||
// to make the fence at the highest indent level.
|
// to make the fence at the highest indent level.
|
||||||
@ -39,11 +54,21 @@ private:
|
|||||||
// without any context.
|
// without any context.
|
||||||
QString unindentCodeBlock(const QString &p_text);
|
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;
|
HGMarkdownHighlighter *m_highlighter;
|
||||||
VDocument *m_vdocument;
|
VDocument *m_vdocument;
|
||||||
MarkdownConverterType m_type;
|
MarkdownConverterType m_type;
|
||||||
QAtomicInteger<int> m_timeStamp;
|
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
|
#endif // VCODEBLOCKHIGHLIGHTHELPER_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user