LivePreview: smart live preview for sequence diagram

This commit is contained in:
Le Tan 2018-08-30 19:53:06 +08:00
parent bf51b7b117
commit 2bf36319d1
2 changed files with 194 additions and 35 deletions

View File

@ -1421,6 +1421,8 @@ var setPreviewEnabled = function(enabled) {
previewDiv.style.display = 'none'; previewDiv.style.display = 'none';
previewDiv.innerHTML = ''; previewDiv.innerHTML = '';
} }
clearMarkRectDivs();
}; };
var previewCodeBlock = function(id, lang, text, isLivePreview) { var previewCodeBlock = function(id, lang, text, isLivePreview) {
@ -1737,17 +1739,12 @@ var findNodeWithText = function(node, text, isMatched) {
// Draw a rectangle to mark @rect. // Draw a rectangle to mark @rect.
var markNode = function(rect) { var markNode = function(rect) {
clearMarkRectDivs();
if (!rect) { if (!rect) {
return; return;
} }
var nodes = document.getElementsByClassName(VMarkRectDivClass);
while (nodes.length > 0) {
var n = nodes[0];
n.outerHTML = '';
delete n;
}
var div = document.createElement('div'); var div = document.createElement('div');
div.id = 'markrect_' + Date.now(); div.id = 'markrect_' + Date.now();
div.classList.add(VMarkRectDivClass); div.classList.add(VMarkRectDivClass);
@ -1765,3 +1762,12 @@ var markNode = function(rect) {
+ 'if (node) { node.outerHTML = ""; delete node; }', + 'if (node) { node.outerHTML = ""; delete node; }',
3000); 3000);
}; };
var clearMarkRectDivs = function() {
var nodes = document.getElementsByClassName(VMarkRectDivClass);
while (nodes.length > 0) {
var n = nodes[0];
n.outerHTML = '';
delete n;
}
};

View File

@ -193,21 +193,21 @@ static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRege
{ {
Q_UNUSED(p_isRegex); Q_UNUSED(p_isRegex);
// class ABC #Pink { // class ABC #Pink
static QRegExp classDef1("^\\s*(?:class|(?:abstract(?:\\s+class)?)|interface|annotation|enum)\\s*" static QRegExp classDef1("^\\s*(?:class|(?:abstract(?:\\s+class)?)|interface|annotation|enum)\\s+"
"(?!class)(\\w+)\\s*.*"); "(?!class)(\\w+)");
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"; p_hints = "id";
return true; return true;
} }
// class "ABC DEF" as AD #Pink { // class "ABC DEF" as AD #Pink
static QRegExp classDef2("^\\s*(?:class|(?:abstract(?:\\s+class)?)|interface|annotation|enum)\\s*" static QRegExp classDef2("^\\s*(?:class|(?:abstract(?:\\s+class)?)|interface|annotation|enum)\\s+"
"\"([^\"]+)\"\\s*(?:\\bas (\\w+))?.*"); "\"([^\"]+)\"\\s*(?:\\bas\\s+(\\w+))?");
if (classDef2.indexIn(p_keyword) >= 0) { if (classDef2.indexIn(p_keyword) >= 0) {
if (classDef2.cap(2).isEmpty()) { if (classDef2.cap(2).isEmpty()) {
p_keyword = classDef2.cap(1); p_keyword = classDef2.cap(1).trimmed();
} else { } else {
p_keyword = classDef2.cap(2); p_keyword = classDef2.cap(2);
} }
@ -216,24 +216,23 @@ static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRege
} }
// class01 "1" *-- "many" class02 : contains 4 > // class01 "1" *-- "many" class02 : contains 4 >
static QRegExp relation("^\\s*(?:(\\w+)|\"([^\"]+)\")\\s+" static QRegExp relation("^\\s*(?:(\\w+)|\"([^\"]+)\")\\s*"
"(?:\"[^\"]+\"\\s+)?" "(?:\"[^\"]+\"\\s*)?"
"(?:<\\||[*o<#x}+^])?" "(?:-+|\\.+)" "(?:\\|>|[*o>#x{+^])?\\s+" "(?:<\\||[*o<#x}+^])?" "(?:-+|\\.+)" "(?:\\|>|[*o>#x{+^])?\\s*"
"(?:\"[^\"]+\"\\s+)?" "(?:\"[^\"]+\"\\s*)?"
"(?:(\\w+)|\"([^\"]+)\")\\s*" "(?:(\\w+)|\"([^\"]+)\")\\s*"
"(?::(.+))?"); "(?::(.+))?");
if (relation.indexIn(p_keyword) >= 0) { if (relation.indexIn(p_keyword) >= 0) {
QString note(relation.cap(5)); if (relation.cap(5).isEmpty()) {
if (note.isEmpty()) {
QString class2 = relation.cap(3); QString class2 = relation.cap(3);
if (class2.isEmpty()) { if (class2.isEmpty()) {
class2 = relation.cap(4); class2 = relation.cap(4).trimmed();
} }
p_keyword = class2; p_keyword = class2;
p_hints = "id"; p_hints = "id";
} else { } else {
p_keyword = note.trimmed(); p_keyword = relation.cap(5).trimmed();
} }
return true; return true;
@ -257,7 +256,7 @@ static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRege
return true; return true;
} }
// note left on link: message // note left on link #Pink : message
// note left on link // note left on link
// node on link: message // node on link: message
// MUST before next rule "note". // MUST before next rule "note".
@ -270,11 +269,13 @@ static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRege
return true; return true;
} }
// note top of Object: message // note top of Object #Pink : message
// note top of Object // note top of Object
// note top: message // note top: message
static QRegExp note("^\\s*note\\s+(?:left|top|right|bottom)" // hnote and rnote for sequence diagram.
"(?:\\s+of\\s+(\\w+))?\\s*" static QRegExp note("^\\s*[hr]?note\\s+(?:left|top|right|bottom)"
"(?:\\s+of\\s+(\\w+))?"
"[^:]*"
"(?::(.*))?"); "(?::(.*))?");
if (note.indexIn(p_keyword) >= 0) { if (note.indexIn(p_keyword) >= 0) {
p_keyword = note.cap(2).trimmed(); p_keyword = note.cap(2).trimmed();
@ -288,16 +289,16 @@ static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRege
return true; return true;
} }
// note "a floating note" as N1 // note "a floating note" as N1 #Pink
// note as N1 // note as N1
static QRegExp note2("^\\s*note\\s+(?:\"([^\"]*)\"\\s+)?as\\s+\\w+\\s*"); static QRegExp note2("^\\s*note\\s+(?:\"([^\"]*)\"\\s+)?as\\s+\\w+");
if (note2.indexIn(p_keyword) >= 0) { if (note2.indexIn(p_keyword) >= 0) {
p_keyword = note2.cap(1); p_keyword = note2.cap(1).trimmed();
return true; return true;
} }
// end note // end note
static QRegExp note3("^\\s*end note\\s*$"); static QRegExp note3("^\\s*end ?note\\s*$");
if (note3.indexIn(p_keyword) >= 0) { if (note3.indexIn(p_keyword) >= 0) {
p_keyword.clear(); p_keyword.clear();
return true; return true;
@ -355,17 +356,26 @@ static bool tryActivityDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
// Activity. // Activity.
// multiple lines; // multiple lines;
static QRegExp activity2("^\\s*(.+)[;|<>/\\]}]\\s*$"); static QRegExp activity2("^\\s*(.+)([;|<>/\\]}])\\s*$");
if (activity2.indexIn(p_keyword) >= 0) { if (activity2.indexIn(p_keyword) >= 0) {
p_keyword = activity2.cap(1).trimmed(); QString word = activity2.cap(1);
QChar end = activity2.cap(2)[0];
if (end != ';' && !word.isEmpty()) {
// || << >> // ]] }} are not legal.
if (word[word.size() - 1] == end) {
return false;
}
}
p_keyword = word.trimmed();
return true; return true;
} }
// start, stop, end, endif, repeat, fork, fork again, end fork, }, // start, stop, end, endif, repeat, fork, fork again, end fork, },
// detach // detach
static QRegExp start("^\\s*(?:start|stop|end|endif|repeat|" static QRegExp keywords("^\\s*(?:start|stop|end|endif|repeat|"
"fork(?:\\s+again)?|end\\s+fork|\\}|detach)\\s*$"); "fork(?:\\s+again)?|end\\s+fork|\\}|detach)\\s*$");
if (start.indexIn(p_keyword) >= 0) { if (keywords.indexIn(p_keyword) >= 0) {
p_keyword.clear(); p_keyword.clear();
return true; return true;
} }
@ -426,6 +436,143 @@ static bool tryActivityDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
return false; return false;
} }
static bool trySequenceDiagram(QString &p_keyword, QString &p_hints, bool &p_isRegex)
{
Q_UNUSED(p_isRegex);
Q_UNUSED(p_hints);
// participant ABC #Pink
// participant "ABC DEF" as AD #Pink
static QRegExp participant1("^\\s*(?:participant|actor|boundary|control|entity|database)\\s+"
"(?:(\\w+)|\"([^\"]+)\"\\s*(?:\\bas\\s+\\w+)?)");
if (participant1.indexIn(p_keyword) >= 0) {
p_keyword = participant1.cap(1);
if (p_keyword.isEmpty()) {
p_keyword = participant1.cap(2).trimmed();
}
return true;
}
// "abc" ->> "def" : Authentication
static QRegExp message("^\\s*(?:\\w+|\"[^\"]+\")\\s*"
"[-<>x\\\\/o]+\\s*"
"(?:\\w+|\"[^\"]+\")\\s*"
":\\s*(.+)");
if (message.indexIn(p_keyword) >= 0) {
p_keyword = message.cap(1).trimmed();
return true;
}
// autonumber
static QRegExp autonum("^\\s*autonumber\\s+");
if (autonum.indexIn(p_keyword) >= 0) {
p_keyword.clear();
return true;
}
// newpage
static QRegExp newpage("^\\s*newpage\\s+(.+)");
if (newpage.indexIn(p_keyword) >= 0) {
p_keyword = newpage.cap(1).trimmed();
return true;
}
// alt, else, group, loop ABCDEFG
static QRegExp group1("^\\s*(?:alt|else|group|loop)\\s+(.*)");
if (group1.indexIn(p_keyword) >= 0) {
p_keyword = group1.cap(1).trimmed();
return true;
}
// note over bob, alice #Pink:
// ret over bob, alice : init
static QRegExp noteon("^\\s*(?:[hr]?note|ref)\\s+over\\s+"
"(\\w+)[^:]*"
"(?::(.+))?");
if (noteon.indexIn(p_keyword) >= 0) {
p_keyword = noteon.cap(2).trimmed();
if (p_keyword.isEmpty()) {
p_keyword = noteon.cap(1);
}
return true;
}
// Divider.
// == Initialization ==
static QRegExp divider("^\\s*==\\s*([^=]*)==\\s*$");
if (divider.indexIn(p_keyword) >= 0) {
p_keyword = divider.cap(1).trimmed();
return true;
}
// Delay.
// ... 5 minutes latter ...
static QRegExp delay("^\\s*\\.\\.\\.(?:(.+)\\.\\.\\.)?\\s*$");
if (delay.indexIn(p_keyword) >= 0) {
p_keyword = delay.cap(1).trimmed();
return true;
}
// activate A
static QRegExp activate("^\\s*(?:(?:de)?activate|destroy)\\s+"
"(?:(\\w+)|\"([^\"]+)\")");
if (activate.indexIn(p_keyword) >= 0) {
p_keyword = activate.cap(1);
if (p_keyword.isEmpty()) {
p_keyword = activate.cap(2).trimmed();
}
return true;
}
// create control ABC
static QRegExp create("^\\s*create\\s+(?:\\w+\\s+)?"
"(?:(\\w+)|\"([^\"]+)\")");
if (create.indexIn(p_keyword) >= 0) {
p_keyword = create.cap(1);
if (p_keyword.isEmpty()) {
p_keyword = create.cap(2).trimmed();
}
return true;
}
// Incoming and outgoing message.
static QRegExp incoming("^\\s*\\[[-<>ox]+\\s*"
"(?:\\w+|\"[^\"]+\")\\s*"
":\\s*(.+)");
if (incoming.indexIn(p_keyword) >= 0) {
p_keyword = incoming.cap(1).trimmed();
return true;
}
static QRegExp outgoing("^\\s*(?:\\w+|\"[^\"]+\")\\s*"
"[-<>ox]+\\]\\s*"
":\\s*(.+)");
if (outgoing.indexIn(p_keyword) >= 0) {
p_keyword = outgoing.cap(1).trimmed();
return true;
}
// box "Internal Service" #Pink
static QRegExp box("^\\s*box(?:\\s+\"([^\"]+)\")?\\s*");
if (box.indexIn(p_keyword) >= 0) {
p_keyword = box.cap(1).trimmed();
return true;
}
// end box
static QRegExp endbox("^\\s*end ?box\\s*$");
if (endbox.indexIn(p_keyword) >= 0) {
p_keyword.clear();
return true;
}
return false;
}
QString VPlantUMLHelper::keywordForSmartLivePreview(const QString &p_text, QString VPlantUMLHelper::keywordForSmartLivePreview(const QString &p_text,
QString &p_hints, QString &p_hints,
bool &p_isRegex) bool &p_isRegex)
@ -449,6 +596,12 @@ QString VPlantUMLHelper::keywordForSmartLivePreview(const QString &p_text,
return kw; return kw;
} }
qDebug() << "trySequenceDiagram" << kw;
if (trySequenceDiagram(kw, p_hints, p_isRegex)) {
return kw;
}
qDebug() << "tryCommonElements" << kw; qDebug() << "tryCommonElements" << kw;
if (tryCommonElements(kw, p_hints, p_isRegex)) { if (tryCommonElements(kw, p_hints, p_isRegex)) {