mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 22:09:52 +08:00
LivePreview: refine smart live preview
- Support class diagram. - Support activity diagram.
This commit is contained in:
parent
28d5954bc3
commit
126600dbb1
@ -1622,7 +1622,7 @@ var htmlToText = function(identifier, id, timeStamp, html) {
|
|||||||
content.htmlToTextCB(identifier, id, timeStamp, markdown);
|
content.htmlToTextCB(identifier, id, timeStamp, markdown);
|
||||||
};
|
};
|
||||||
|
|
||||||
var performSmartLivePreview = function(lang, text) {
|
var performSmartLivePreview = function(lang, text, hints, isRegex) {
|
||||||
if (previewDiv.style.display == 'none') {
|
if (previewDiv.style.display == 'none') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1632,7 +1632,35 @@ var performSmartLivePreview = function(lang, text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PlantUML.
|
// PlantUML.
|
||||||
var targetNode = findNodeWithText(previewDiv, new RegExp(text));
|
var targetNode = null;
|
||||||
|
if (hints.indexOf('id') >= 0) {
|
||||||
|
// isRegex is ignored.
|
||||||
|
targetNode = findNodeWithText(previewDiv,
|
||||||
|
text,
|
||||||
|
function (node, text) {
|
||||||
|
if (!node.id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.id == text;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (isRegex) {
|
||||||
|
var nodeReg = new RegExp(text);
|
||||||
|
targetNode = findNodeWithText(previewDiv,
|
||||||
|
text,
|
||||||
|
function(node, text) {
|
||||||
|
return nodeReg.test(node.textContent);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
targetNode = findNodeWithText(previewDiv,
|
||||||
|
text,
|
||||||
|
function(node, text) {
|
||||||
|
return node.textContent.indexOf(text) >= 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!targetNode) {
|
if (!targetNode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1665,17 +1693,17 @@ var performSmartLivePreview = function(lang, text) {
|
|||||||
if (trect.height >= vrect.height) {
|
if (trect.height >= vrect.height) {
|
||||||
dy = trect.top;
|
dy = trect.top;
|
||||||
} else {
|
} else {
|
||||||
dy = trect.top - (vrect.height - trect.width) / 2;
|
dy = trect.top - (vrect.height - trect.height) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.scrollBy(dx, dy);
|
window.scrollBy(dx, dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
var findNodeWithText = function(node, reg) {
|
var findNodeWithText = function(node, text, isMatched) {
|
||||||
var children = node.children;
|
var children = node.children;
|
||||||
if (children.length == 0) {
|
if (children.length == 0) {
|
||||||
if (reg.test(node.textContent)) {
|
if (isMatched(node, text)) {
|
||||||
return node;
|
return node;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
@ -1683,13 +1711,13 @@ var findNodeWithText = function(node, reg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < children.length; ++i) {
|
for (var i = 0; i < children.length; ++i) {
|
||||||
var ret = findNodeWithText(children[i], reg);
|
var ret = findNodeWithText(children[i], text, isMatched);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reg.test(node.textContent)) {
|
if (isMatched(node, text)) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,9 +203,13 @@ void VDocument::previewCodeBlockCB(int p_id, const QString &p_lang, const QStrin
|
|||||||
emit codeBlockPreviewReady(p_id, p_lang, p_html);
|
emit codeBlockPreviewReady(p_id, p_lang, p_html);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VDocument::performSmartLivePreview(const QString &p_lang, const QString &p_text)
|
void VDocument::performSmartLivePreview(const QString &p_lang,
|
||||||
|
const QString &p_text,
|
||||||
|
const QString &p_hints,
|
||||||
|
bool p_isRegex)
|
||||||
{
|
{
|
||||||
if (!p_text.isEmpty()) {
|
if (!p_text.isEmpty()) {
|
||||||
emit requestPerformSmartLivePreview(p_lang, p_text);
|
qDebug() << "performSmartLivePreview" << p_lang << p_text << p_hints << p_isRegex;
|
||||||
|
emit requestPerformSmartLivePreview(p_lang, p_text, p_hints, p_isRegex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,10 @@ public:
|
|||||||
|
|
||||||
void muteWebView(bool p_muted);
|
void muteWebView(bool p_muted);
|
||||||
|
|
||||||
void performSmartLivePreview(const QString &p_lang, const QString &p_text);
|
void performSmartLivePreview(const QString &p_lang,
|
||||||
|
const QString &p_text,
|
||||||
|
const QString &p_hints,
|
||||||
|
bool p_isRegex);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
// Will be called in the HTML side
|
// Will be called in the HTML side
|
||||||
@ -194,7 +197,10 @@ signals:
|
|||||||
|
|
||||||
void requestMuted(bool p_muted);
|
void requestMuted(bool p_muted);
|
||||||
|
|
||||||
void requestPerformSmartLivePreview(const QString &p_lang, const QString &p_text);
|
void requestPerformSmartLivePreview(const QString &p_lang,
|
||||||
|
const QString &p_text,
|
||||||
|
const QString &p_hints,
|
||||||
|
bool p_isRegex);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_toc;
|
QString m_toc;
|
||||||
|
@ -535,6 +535,10 @@ void VLivePreviewHelper::performSmartLivePreview()
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CodeBlockPreviewInfo &cb = m_codeBlocks[m_cbIndex];
|
const CodeBlockPreviewInfo &cb = m_codeBlocks[m_cbIndex];
|
||||||
|
if (!cb.hasImageData()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const VCodeBlock &vcb = cb.codeBlock();
|
const VCodeBlock &vcb = cb.codeBlock();
|
||||||
const QTextBlock block = m_editor->textCursorW().block();
|
const QTextBlock block = m_editor->textCursorW().block();
|
||||||
if (block.blockNumber() <= vcb.m_startBlock
|
if (block.blockNumber() <= vcb.m_startBlock
|
||||||
@ -542,10 +546,13 @@ void VLivePreviewHelper::performSmartLivePreview()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString keyword;
|
QString keyword, hints;
|
||||||
|
bool isRegex = false;
|
||||||
if (vcb.m_lang == "puml" && m_plantUMLMode == PlantUMLMode::LocalPlantUML) {
|
if (vcb.m_lang == "puml" && m_plantUMLMode == PlantUMLMode::LocalPlantUML) {
|
||||||
keyword = VPlantUMLHelper::keywordForSmartLivePreview(block.text());
|
keyword = VPlantUMLHelper::keywordForSmartLivePreview(block.text(),
|
||||||
|
hints,
|
||||||
|
isRegex);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_document->performSmartLivePreview(vcb.m_lang, keyword);
|
m_document->performSmartLivePreview(vcb.m_lang, keyword, hints, isRegex);
|
||||||
}
|
}
|
||||||
|
@ -189,37 +189,269 @@ QByteArray VPlantUMLHelper::process(const QString &p_format, const QString &p_te
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool tryClassDiagram(QString &p_keyword)
|
static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRegex)
|
||||||
{
|
{
|
||||||
{
|
Q_UNUSED(p_isRegex);
|
||||||
|
|
||||||
// class ABC #Pink {
|
// class ABC #Pink {
|
||||||
QRegExp classDef1("class\\s*(\\w+)\\s*.*");
|
static QRegExp classDef1("^\\s*(?:class|(?:abstract(?:\\s+class)?)|interface|annotation|enum)\\s*"
|
||||||
|
"(?!class)(\\w+)\\s*.*");
|
||||||
if (classDef1.indexIn(p_keyword) >= 0) {
|
if (classDef1.indexIn(p_keyword) >= 0) {
|
||||||
p_keyword = classDef1.cap(1);
|
p_keyword = classDef1.cap(1);
|
||||||
|
p_hints = "id";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// class "ABC DEF" as AD #Pink {
|
||||||
|
static QRegExp classDef2("^\\s*(?:class|(?:abstract(?:\\s+class)?)|interface|annotation|enum)\\s*"
|
||||||
|
"\"([^\"]+)\"\\s*(?:\\bas (\\w+))?.*");
|
||||||
|
if (classDef2.indexIn(p_keyword) >= 0) {
|
||||||
|
if (classDef2.cap(2).isEmpty()) {
|
||||||
|
p_keyword = classDef2.cap(1);
|
||||||
|
} else {
|
||||||
|
p_keyword = classDef2.cap(2);
|
||||||
|
}
|
||||||
|
p_hints = "id";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// class01 "1" *-- "many" class02 : contains 4 >
|
||||||
|
static QRegExp relation("^\\s*(?:(\\w+)|\"([^\"]+)\")\\s+"
|
||||||
|
"(?:\"[^\"]+\"\\s+)?"
|
||||||
|
"(?:<\\||[*o<#x}+^])?" "(?:-+|\\.+)" "(?:\\|>|[*o>#x{+^])?\\s+"
|
||||||
|
"(?:\"[^\"]+\"\\s+)?"
|
||||||
|
"(?:(\\w+)|\"([^\"]+)\")\\s*"
|
||||||
|
"(?::(.+))?");
|
||||||
|
if (relation.indexIn(p_keyword) >= 0) {
|
||||||
|
QString note(relation.cap(5));
|
||||||
|
if (note.isEmpty()) {
|
||||||
|
QString class2 = relation.cap(3);
|
||||||
|
if (class2.isEmpty()) {
|
||||||
|
class2 = relation.cap(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
p_keyword = class2;
|
||||||
|
p_hints = "id";
|
||||||
|
} else {
|
||||||
|
p_keyword = note.trimmed();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// {static} field : String
|
||||||
|
bool containsModifier = false;
|
||||||
|
static QRegExp modifier("\\{(?:static|abstract|classifier)\\}");
|
||||||
|
if (modifier.indexIn(p_keyword) >= 0) {
|
||||||
|
containsModifier = true;
|
||||||
|
p_keyword.remove(modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
// + field
|
||||||
|
static QRegExp member("^\\s*[-#~+]\\s*(.*)");
|
||||||
|
if (member.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = member.cap(1).trimmed();
|
||||||
|
return true;
|
||||||
|
} else if (containsModifier) {
|
||||||
|
p_keyword = p_keyword.trimmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// note left on link: message
|
||||||
|
// note left on link
|
||||||
|
// node on link: message
|
||||||
|
// MUST before next rule "note".
|
||||||
|
static QRegExp note4("^\\s*note\\s+(?:(?:left|top|right|bottom)\\s+)?"
|
||||||
|
"on\\s+link"
|
||||||
|
"[^:]*"
|
||||||
|
"(?::(.*))?");
|
||||||
|
if (note4.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = note4.cap(1).trimmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// note top of Object: message
|
||||||
|
// note top of Object
|
||||||
|
// note top: message
|
||||||
|
static QRegExp note("^\\s*note\\s+(?:left|top|right|bottom)"
|
||||||
|
"(?:\\s+of\\s+(\\w+))?\\s*"
|
||||||
|
"(?::(.*))?");
|
||||||
|
if (note.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = note.cap(2).trimmed();
|
||||||
|
if (p_keyword.isEmpty()) {
|
||||||
|
p_keyword = note.cap(1);
|
||||||
|
if (!p_keyword.isEmpty()) {
|
||||||
|
p_hints = "id";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
// class "ABC DEF" as AD #Pink {
|
|
||||||
QRegExp classDef2("class\\s*\"([^\"]+)\"\\s*.*");
|
|
||||||
if (classDef2.indexIn(p_keyword) >= 0) {
|
|
||||||
p_keyword = classDef2.cap(1);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// note "a floating note" as N1
|
||||||
|
// note as N1
|
||||||
|
static QRegExp note2("^\\s*note\\s+(?:\"([^\"]*)\"\\s+)?as\\s+\\w+\\s*");
|
||||||
|
if (note2.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = note2.cap(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// end note
|
||||||
|
static QRegExp note3("^\\s*end note\\s*$");
|
||||||
|
if (note3.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword.clear();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString VPlantUMLHelper::keywordForSmartLivePreview(const QString &p_text)
|
static bool tryCommonElements(QString &p_keyword, QString &p_hints, bool &p_isRegex)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_isRegex);
|
||||||
|
Q_UNUSED(p_hints);
|
||||||
|
|
||||||
|
// List.
|
||||||
|
// ** list
|
||||||
|
// # list
|
||||||
|
static QRegExp listMark("^\\s*(?:\\*+|#+)\\s+(.+)$");
|
||||||
|
if (listMark.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = listMark.cap(1).trimmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Words in quotes.
|
||||||
|
// cmf("abc")
|
||||||
|
static QRegExp quote("^[^\"]*\"([^\"]+)\"[^\"]*$");
|
||||||
|
if (quote.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = quote.cap(1).trimmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool tryActivityDiagram(QString &p_keyword, QString &p_hints, bool &p_isRegex)
|
||||||
|
{
|
||||||
|
Q_UNUSED(p_isRegex);
|
||||||
|
Q_UNUSED(p_hints);
|
||||||
|
|
||||||
|
// Activity. (Do not support color.)
|
||||||
|
// :Hello world;
|
||||||
|
// :Across multiple lines
|
||||||
|
static QRegExp activity1("^\\s*:(.+)\\s*$");
|
||||||
|
if (activity1.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = activity1.cap(1).trimmed();
|
||||||
|
if (!p_keyword.isEmpty()) {
|
||||||
|
QChar ch = p_keyword[p_keyword.size() - 1];
|
||||||
|
if (ch == ';' || ch == '|' || ch == '<' || ch == '>'
|
||||||
|
|| ch == '/' || ch == ']' || ch == '}') {
|
||||||
|
p_keyword = p_keyword.left(p_keyword.size() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activity.
|
||||||
|
// multiple lines;
|
||||||
|
static QRegExp activity2("^\\s*(.+)[;|<>/\\]}]\\s*$");
|
||||||
|
if (activity2.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = activity2.cap(1).trimmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start, stop, end, endif, repeat, fork, fork again, end fork, },
|
||||||
|
// detach
|
||||||
|
static QRegExp start("^\\s*(?:start|stop|end|endif|repeat|"
|
||||||
|
"fork(?:\\s+again)?|end\\s+fork|\\}|detach)\\s*$");
|
||||||
|
if (start.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conditionals.
|
||||||
|
// if (Graphviz) then (yes)
|
||||||
|
// else if (Graphviz) then (yes)
|
||||||
|
static QRegExp conIf("^\\s*(?:else)?if\\s+\\(([^\\)]+)\\)\\s+then(?:\\s+\\([^\\)]+\\))?\\s*$");
|
||||||
|
if (conIf.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = conIf.cap(1).trimmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// else (no)
|
||||||
|
static QRegExp conElse("^\\s*else(?:\\s+\\(([^\\)]+)\\))?\\s*$");
|
||||||
|
if (conElse.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = conElse.cap(1).trimmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeat loop.
|
||||||
|
// repeat while (more data?)
|
||||||
|
static QRegExp repeat("^\\s*repeat\\s+while\\s+\\(([^\\)]+)\\)\\s*$");
|
||||||
|
if (repeat.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = repeat.cap(1).trimmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// while (check?) is (not empty)
|
||||||
|
static QRegExp whileLoop("^\\s*while\\s+\\(([^\\)]+)\\)(?:\\s+is\\s+\\([^\\)]+\\))?\\s*$");
|
||||||
|
if (whileLoop.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = whileLoop.cap(1).trimmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// endwhile (empty)
|
||||||
|
static QRegExp endWhile("^\\s*endwhile(?:\\s+\\(([^\\)]+)\\))?\\s*$");
|
||||||
|
if (endWhile.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = endWhile.cap(1).trimmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// partition Running {
|
||||||
|
static QRegExp partition("^\\s*partition\\s+(\\w+)\\s+\\{\\s*$");
|
||||||
|
if (partition.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = partition.cap(1).trimmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// |Swimlane1|
|
||||||
|
// |#Pink|Swimlane1|
|
||||||
|
static QRegExp swimline("^\\s*(?:\\|[^\\|]+)?\\|([^|]+)\\|\\s*$");
|
||||||
|
if (swimline.indexIn(p_keyword) >= 0) {
|
||||||
|
p_keyword = swimline.cap(1).trimmed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VPlantUMLHelper::keywordForSmartLivePreview(const QString &p_text,
|
||||||
|
QString &p_hints,
|
||||||
|
bool &p_isRegex)
|
||||||
{
|
{
|
||||||
QString kw = p_text.trimmed();
|
QString kw = p_text.trimmed();
|
||||||
if (kw.isEmpty()) {
|
if (kw.isEmpty()) {
|
||||||
return kw;
|
return kw;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tryClassDiagram(kw)) {
|
p_isRegex = false;
|
||||||
|
|
||||||
|
qDebug() << "tryClassDiagram" << kw;
|
||||||
|
|
||||||
|
if (tryClassDiagram(kw, p_hints, p_isRegex)) {
|
||||||
|
return kw;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "tryActivityDiagram" << kw;
|
||||||
|
|
||||||
|
if (tryActivityDiagram(kw, p_hints, p_isRegex)) {
|
||||||
|
return kw;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "tryCommonElements" << kw;
|
||||||
|
|
||||||
|
if (tryCommonElements(kw, p_hints, p_isRegex)) {
|
||||||
return kw;
|
return kw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,9 @@ public:
|
|||||||
|
|
||||||
static QByteArray process(const QString &p_format, const QString &p_text);
|
static QByteArray process(const QString &p_format, const QString &p_text);
|
||||||
|
|
||||||
static QString keywordForSmartLivePreview(const QString &p_text);
|
static QString keywordForSmartLivePreview(const QString &p_text,
|
||||||
|
QString &p_hints,
|
||||||
|
bool &p_isRegex);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void resultReady(int p_id,
|
void resultReady(int p_id,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user