LivePreview: search for multiple tokens and select the best match

This commit is contained in:
Le Tan 2018-08-30 19:53:20 +08:00
parent 2bf36319d1
commit 74ec3884d0
2 changed files with 131 additions and 49 deletions

View File

@ -1638,30 +1638,61 @@ var performSmartLivePreview = function(lang, text, hints, isRegex) {
var targetNode = null; var targetNode = null;
if (hints.indexOf('id') >= 0) { if (hints.indexOf('id') >= 0) {
// isRegex is ignored. // isRegex is ignored.
targetNode = findNodeWithText(previewDiv, var result = findNodeWithText(previewDiv,
text, text,
function (node, text) { function (node, text) {
if (!node.id) { if (node.id && node.id == text) {
return false; var res = { stop: true,
node: { node: node,
diff: 0
}
};
return res;
} }
return node.id == text; return null;
}); });
targetNode = result.node;
} else { } else {
var result;
if (isRegex) { if (isRegex) {
var nodeReg = new RegExp(text); var nodeReg = new RegExp(text);
targetNode = findNodeWithText(previewDiv, result = findNodeWithText(previewDiv,
text, text,
function(node, text) { function(node, text) {
return nodeReg.test(node.textContent); var se = nodeReg.exec(node.textContent);
}); if (!se) {
return null;
}
var diff = node.textContent.length - se[0].length;
var res = { stop: diff == 0,
node: { node: node,
diff: diff
}
};
return res;
});
} else { } else {
targetNode = findNodeWithText(previewDiv, result = findNodeWithText(previewDiv,
text, text,
function(node, text) { function(node, text) {
return node.textContent.indexOf(text) >= 0; var idx = node.textContent.indexOf(text);
}); if (idx < 0) {
return null;
}
var diff = node.textContent.length - text.length;
var res = { stop: diff == 0,
node: { node: node,
diff: diff
}
};
return res;
});
} }
targetNode = result.node;
} }
if (!targetNode) { if (!targetNode) {
@ -1713,28 +1744,46 @@ var performSmartLivePreview = function(lang, text, hints, isRegex) {
markNode(nrect); markNode(nrect);
} }
// isMatched() should return a strut or null:
// - null to indicates a mismatch;
// - { stop: whether continue search,
// node: { node: the matched node,
// diff: a value indicates the match quality (the lower the better)
// }
// }
var findNodeWithText = function(node, text, isMatched) { var findNodeWithText = function(node, text, isMatched) {
var result = {
node: null,
diff: 999999
};
findNodeWithTextInternal(node, text, isMatched, result);
return result;
}
// Return true to stop search.
var findNodeWithTextInternal = function(node, text, isMatched, result) {
var children = node.children; var children = node.children;
if (children.length == 0) { if (children.length > 0) {
if (isMatched(node, text)) { for (var i = 0; i < children.length; ++i) {
return node; var ret = findNodeWithTextInternal(children[i], text, isMatched, result);
} else { if (ret) {
return null; return ret;
}
} }
} }
for (var i = 0; i < children.length; ++i) { var res = isMatched(node, text);
var ret = findNodeWithText(children[i], text, isMatched); if (res) {
if (ret) { if (res.node.diff < result.diff) {
return ret; result.node = res.node.node;
result.diff = res.node.diff;
} }
return res.stop;
} }
if (isMatched(node, text)) { return false;
return node;
}
return null;
} }
// Draw a rectangle to mark @rect. // Draw a rectangle to mark @rect.

View File

@ -189,7 +189,7 @@ QByteArray VPlantUMLHelper::process(const QString &p_format, const QString &p_te
return out; return out;
} }
static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRegex) static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRegex, bool &p_needCreole)
{ {
Q_UNUSED(p_isRegex); Q_UNUSED(p_isRegex);
@ -232,6 +232,7 @@ static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRege
p_keyword = class2; p_keyword = class2;
p_hints = "id"; p_hints = "id";
} else { } else {
p_needCreole = true;
p_keyword = relation.cap(5).trimmed(); p_keyword = relation.cap(5).trimmed();
} }
@ -265,6 +266,7 @@ static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRege
"[^:]*" "[^:]*"
"(?::(.*))?"); "(?::(.*))?");
if (note4.indexIn(p_keyword) >= 0) { if (note4.indexIn(p_keyword) >= 0) {
p_needCreole = true;
p_keyword = note4.cap(1).trimmed(); p_keyword = note4.cap(1).trimmed();
return true; return true;
} }
@ -284,6 +286,8 @@ static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRege
if (!p_keyword.isEmpty()) { if (!p_keyword.isEmpty()) {
p_hints = "id"; p_hints = "id";
} }
} else {
p_needCreole = true;
} }
return true; return true;
@ -307,19 +311,11 @@ static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRege
return false; return false;
} }
static bool tryCommonElements(QString &p_keyword, QString &p_hints, bool &p_isRegex) static bool tryCommonElements(QString &p_keyword, QString &p_hints, bool &p_isRegex, bool &p_needCreole)
{ {
Q_UNUSED(p_isRegex); Q_UNUSED(p_isRegex);
Q_UNUSED(p_hints); Q_UNUSED(p_hints);
Q_UNUSED(p_needCreole);
// 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. // Words in quotes.
// cmf("abc") // cmf("abc")
@ -332,7 +328,7 @@ static bool tryCommonElements(QString &p_keyword, QString &p_hints, bool &p_isRe
return false; return false;
} }
static bool tryActivityDiagram(QString &p_keyword, QString &p_hints, bool &p_isRegex) static bool tryActivityDiagram(QString &p_keyword, QString &p_hints, bool &p_isRegex, bool &p_needCreole)
{ {
Q_UNUSED(p_isRegex); Q_UNUSED(p_isRegex);
Q_UNUSED(p_hints); Q_UNUSED(p_hints);
@ -351,6 +347,7 @@ static bool tryActivityDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
} }
} }
p_needCreole = true;
return true; return true;
} }
@ -367,6 +364,8 @@ static bool tryActivityDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
} }
} }
// It may conflict with note.
p_needCreole = true;
p_keyword = word.trimmed(); p_keyword = word.trimmed();
return true; return true;
} }
@ -436,7 +435,7 @@ 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) static bool trySequenceDiagram(QString &p_keyword, QString &p_hints, bool &p_isRegex, bool &p_needCreole)
{ {
Q_UNUSED(p_isRegex); Q_UNUSED(p_isRegex);
Q_UNUSED(p_hints); Q_UNUSED(p_hints);
@ -460,6 +459,7 @@ static bool trySequenceDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
"(?:\\w+|\"[^\"]+\")\\s*" "(?:\\w+|\"[^\"]+\")\\s*"
":\\s*(.+)"); ":\\s*(.+)");
if (message.indexIn(p_keyword) >= 0) { if (message.indexIn(p_keyword) >= 0) {
p_needCreole = true;
p_keyword = message.cap(1).trimmed(); p_keyword = message.cap(1).trimmed();
return true; return true;
} }
@ -494,6 +494,8 @@ static bool trySequenceDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
p_keyword = noteon.cap(2).trimmed(); p_keyword = noteon.cap(2).trimmed();
if (p_keyword.isEmpty()) { if (p_keyword.isEmpty()) {
p_keyword = noteon.cap(1); p_keyword = noteon.cap(1);
} else {
p_needCreole = true;
} }
return true; return true;
@ -544,6 +546,7 @@ static bool trySequenceDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
"(?:\\w+|\"[^\"]+\")\\s*" "(?:\\w+|\"[^\"]+\")\\s*"
":\\s*(.+)"); ":\\s*(.+)");
if (incoming.indexIn(p_keyword) >= 0) { if (incoming.indexIn(p_keyword) >= 0) {
p_needCreole = true;
p_keyword = incoming.cap(1).trimmed(); p_keyword = incoming.cap(1).trimmed();
return true; return true;
} }
@ -552,6 +555,7 @@ static bool trySequenceDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
"[-<>ox]+\\]\\s*" "[-<>ox]+\\]\\s*"
":\\s*(.+)"); ":\\s*(.+)");
if (outgoing.indexIn(p_keyword) >= 0) { if (outgoing.indexIn(p_keyword) >= 0) {
p_needCreole = true;
p_keyword = outgoing.cap(1).trimmed(); p_keyword = outgoing.cap(1).trimmed();
return true; return true;
} }
@ -573,6 +577,24 @@ static bool trySequenceDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
return false; return false;
} }
static bool tryCreole(QString &p_keyword)
{
if (p_keyword.isEmpty()) {
return false;
}
// List.
// ** list
// # list
static QRegExp listMark("^\\s*(?:\\*+|#+)\\s+(.+)$");
if (listMark.indexIn(p_keyword) >= 0) {
p_keyword = listMark.cap(1).trimmed();
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)
@ -583,30 +605,41 @@ QString VPlantUMLHelper::keywordForSmartLivePreview(const QString &p_text,
} }
p_isRegex = false; p_isRegex = false;
bool needCreole = false;
qDebug() << "tryClassDiagram" << kw; if (tryClassDiagram(kw, p_hints, p_isRegex, needCreole)) {
if (needCreole) {
goto creole;
}
if (tryClassDiagram(kw, p_hints, p_isRegex)) {
return kw; return kw;
} }
qDebug() << "tryActivityDiagram" << kw; if (tryActivityDiagram(kw, p_hints, p_isRegex, needCreole)) {
if (needCreole) {
goto creole;
}
if (tryActivityDiagram(kw, p_hints, p_isRegex)) {
return kw; return kw;
} }
qDebug() << "trySequenceDiagram" << kw; if (trySequenceDiagram(kw, p_hints, p_isRegex, needCreole)) {
if (needCreole) {
goto creole;
}
if (trySequenceDiagram(kw, p_hints, p_isRegex)) {
return kw; return kw;
} }
qDebug() << "tryCommonElements" << kw; if (tryCommonElements(kw, p_hints, p_isRegex, needCreole)) {
if (needCreole) {
goto creole;
}
if (tryCommonElements(kw, p_hints, p_isRegex)) {
return kw; return kw;
} }
creole:
tryCreole(kw);
return kw; return kw;
} }