mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
LivePreview: support component/state/object diagram
This commit is contained in:
parent
774eec32d7
commit
2338002b1f
@ -189,23 +189,55 @@ QByteArray VPlantUMLHelper::process(const QString &p_format, const QString &p_te
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool tryKeywords(QString &p_keyword)
|
||||
static bool tryKeywords(QString &p_keyword, bool &p_needCreole)
|
||||
{
|
||||
// start, stop, end, endif, repeat, fork, fork again, end fork, },
|
||||
// detach, end note, end box, endrnote, endhnote,
|
||||
// top to bottom direction, left to right direction,
|
||||
// @startuml, @enduml
|
||||
// ||, --, title, end title, end legend
|
||||
static QRegExp keywords("^\\s*(?:start|stop|end|endif|repeat|"
|
||||
"fork(?:\\s+again)?|end\\s+fork|\\}|detach|"
|
||||
"end ?(?:note|box)|endrnote|endhnote|"
|
||||
"top\\s+to\\s+bottom\\s+direction|"
|
||||
"left\\s+to\\s+right\\s+direction|"
|
||||
"@startuml|@enduml)\\s*$");
|
||||
"@startuml|@enduml|"
|
||||
"--|\\|\\||(?:end\\s+)?title|end\\s+legend)\\s*$");
|
||||
if (keywords.indexIn(p_keyword) >= 0) {
|
||||
p_keyword.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Comments.
|
||||
static QRegExp comment("^\\s*'");
|
||||
if (comment.indexIn(p_keyword) >= 0) {
|
||||
p_keyword.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
// scale 1.5
|
||||
static QRegExp scale("^\\s*scale\\s+\\w+");
|
||||
if (scale.indexIn(p_keyword) >= 0) {
|
||||
p_keyword.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
// title
|
||||
// caption
|
||||
static QRegExp title("^\\s*(?:title|caption)\\s+(.+)");
|
||||
if (title.indexIn(p_keyword) >= 0) {
|
||||
p_keyword = title.cap(1).trimmed();
|
||||
p_needCreole = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// legend right
|
||||
static QRegExp legend("^\\s*legend(?:\\s+(?:left|right|center))?");
|
||||
if (legend.indexIn(p_keyword) >= 0) {
|
||||
p_keyword.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -214,7 +246,8 @@ static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRege
|
||||
Q_UNUSED(p_isRegex);
|
||||
|
||||
// class ABC #Pink
|
||||
static QRegExp classDef1("^\\s*(?:class|(?:abstract(?:\\s+class)?)|interface|annotation|enum)\\s+"
|
||||
// interface conflicts with component diagram, so it is removed from here.
|
||||
static QRegExp classDef1("^\\s*(?:class|(?:abstract(?:\\s+class)?)|annotation|enum)\\s+"
|
||||
"(?!class)(\\w+)");
|
||||
if (classDef1.indexIn(p_keyword) >= 0) {
|
||||
p_keyword = classDef1.cap(1);
|
||||
@ -223,7 +256,7 @@ static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRege
|
||||
}
|
||||
|
||||
// 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)?)|annotation|enum)\\s+"
|
||||
"\"([^\"]+)\"\\s*(?:\\bas\\s+(\\w+))?");
|
||||
if (classDef2.indexIn(p_keyword) >= 0) {
|
||||
if (classDef2.cap(2).isEmpty()) {
|
||||
@ -296,19 +329,28 @@ static bool tryClassDiagram(QString &p_keyword, QString &p_hints, bool &p_isRege
|
||||
// note top: message
|
||||
// hnote and rnote for sequence diagram.
|
||||
// note right of (use case)
|
||||
// note right of [component]
|
||||
static QRegExp note("^\\s*[hr]?note\\s+(?:left|top|right|bottom)"
|
||||
"(?:\\s+of\\s+(?:(\\w+)|\\(([^\\)]+)\\)))?"
|
||||
"(?:\\s+of\\s+(?:(\\w+)|"
|
||||
"\\(([^\\)]+)\\)|"
|
||||
"\\[([^\\]]+)\\]))?"
|
||||
"[^:]*"
|
||||
"(?::(.*))?");
|
||||
if (note.indexIn(p_keyword) >= 0) {
|
||||
p_keyword = note.cap(3).trimmed();
|
||||
p_keyword = note.cap(4).trimmed();
|
||||
if (p_keyword.isEmpty()) {
|
||||
p_keyword = note.cap(2).trimmed();
|
||||
if (p_keyword.isEmpty()) {
|
||||
p_keyword = note.cap(1);
|
||||
p_hints = "id";
|
||||
} else {
|
||||
QString ent = note.cap(1);
|
||||
if (ent.isEmpty()) {
|
||||
ent = note.cap(2).trimmed();
|
||||
if (ent.isEmpty()) {
|
||||
ent = note.cap(3).trimmed();
|
||||
}
|
||||
|
||||
p_keyword = ent;
|
||||
p_needCreole = true;
|
||||
} else {
|
||||
p_keyword = ent;
|
||||
p_hints = "id";
|
||||
}
|
||||
} else {
|
||||
p_needCreole = true;
|
||||
@ -370,7 +412,7 @@ static bool tryActivityDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
|
||||
|
||||
// Activity.
|
||||
// multiple lines;
|
||||
static QRegExp activity2("^\\s*(.+)([;|<>/\\]}])\\s*$");
|
||||
static QRegExp activity2("^\\s*([^\\[]+)([;|<>/\\]}])\\s*$");
|
||||
if (activity2.indexIn(p_keyword) >= 0) {
|
||||
QString word = activity2.cap(1);
|
||||
QChar end = activity2.cap(2)[0];
|
||||
@ -463,7 +505,7 @@ static bool trySequenceDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
|
||||
|
||||
// "abc" ->> "def" : Authentication
|
||||
static QRegExp message("^\\s*(?:\\w+|\"[^\"]+\")\\s+"
|
||||
"[-<>x\\\\/o]{2,}\\s+"
|
||||
"[-<>x\\\\/o]+\\s+"
|
||||
"(?:\\w+|\"[^\"]+\")\\s*"
|
||||
":\\s*(.+)");
|
||||
if (message.indexIn(p_keyword) >= 0) {
|
||||
@ -513,6 +555,7 @@ static bool trySequenceDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
|
||||
// == Initialization ==
|
||||
static QRegExp divider("^\\s*==\\s*([^=]*)==\\s*$");
|
||||
if (divider.indexIn(p_keyword) >= 0) {
|
||||
p_needCreole = true;
|
||||
p_keyword = divider.cap(1).trimmed();
|
||||
return true;
|
||||
}
|
||||
@ -521,6 +564,7 @@ static bool trySequenceDiagram(QString &p_keyword, QString &p_hints, bool &p_isR
|
||||
// ... 5 minutes latter ...
|
||||
static QRegExp delay("^\\s*\\.\\.\\.(?:(.+)\\.\\.\\.)?\\s*$");
|
||||
if (delay.indexIn(p_keyword) >= 0) {
|
||||
p_needCreole = true;
|
||||
p_keyword = delay.cap(1).trimmed();
|
||||
return true;
|
||||
}
|
||||
@ -588,7 +632,7 @@ static bool tryUseCaseDiagram(QString &p_keyword, QString &p_hints, bool &p_isRe
|
||||
// :Main Admin: --> (Use the application) : This is another label
|
||||
// (chekckout) -- (payment) : include
|
||||
static QRegExp rel("^\\s*(?:(\\w+)|:([^:]+):|\\(([^\\)]+)\\))\\s*"
|
||||
"[-.<>]{2,}\\s*"
|
||||
"[-.<>]+\\s*"
|
||||
"(?:\\(([^\\)]+)\\)|(\\w+))\\s*"
|
||||
"(?::(.+))?");
|
||||
if (rel.indexIn(p_keyword) >= 0) {
|
||||
@ -624,7 +668,7 @@ static bool tryUseCaseDiagram(QString &p_keyword, QString &p_hints, bool &p_isRe
|
||||
// (First usecase) as (UC2)
|
||||
// usecase UC3
|
||||
// usecase (Last usecase) as UC4
|
||||
static QRegExp usecase1("^\\s*usecase\\s+(?:(\\w+)|\\(([^\\)]+)\\)\\s+as\\s+\\w+)");
|
||||
static QRegExp usecase1("^\\s*usecase\\s+""(?:(\\w+)|\\(([^\\)]+)\\)\\s+as\\s+\\w+)");
|
||||
if (usecase1.indexIn(p_keyword) >= 0) {
|
||||
if (usecase1.cap(1).isEmpty()) {
|
||||
p_keyword = usecase1.cap(2).trimmed();
|
||||
@ -674,25 +718,280 @@ static bool tryUseCaseDiagram(QString &p_keyword, QString &p_hints, bool &p_isRe
|
||||
return true;
|
||||
}
|
||||
|
||||
// Grouping.
|
||||
// package "ABC DEF" {
|
||||
static QRegExp group("^\\s*(?:package|node|folder|frame|cloud|database)\\s+"
|
||||
"(?:(\\w+)|\"([^\"]+)\")");
|
||||
if (group.indexIn(p_keyword) >= 0) {
|
||||
if (group.cap(1).isEmpty()) {
|
||||
p_keyword = group.cap(2).trimmed();
|
||||
p_needCreole = true;
|
||||
} else {
|
||||
p_keyword = group.cap(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool tryComponentDiagram(QString &p_keyword, QString &p_hints, bool &p_isRegex, bool &p_needCreole)
|
||||
{
|
||||
Q_UNUSED(p_isRegex);
|
||||
Q_UNUSED(p_hints);
|
||||
|
||||
// DataAccess - [First Component]
|
||||
// [First Component] ..> HTTP : use
|
||||
static QRegExp rel("^\\s*(?:(\\w+)|\\[([^\\]]+)\\])\\s*"
|
||||
"[-.<>]+\\s*"
|
||||
"(?:(\\w+)|\\[([^\\]]+)\\])\\s*"
|
||||
"(?::(.+))?");
|
||||
if (rel.indexIn(p_keyword) >= 0) {
|
||||
QString msg(rel.cap(5).trimmed());
|
||||
if (msg.isEmpty()) {
|
||||
QString ent1(rel.cap(3));
|
||||
if (ent1.isEmpty()) {
|
||||
ent1 = rel.cap(4).trimmed();
|
||||
if (ent1 == "*") {
|
||||
// State diagram.
|
||||
ent1 = rel.cap(1);
|
||||
if (ent1.isEmpty()) {
|
||||
ent1 = rel.cap(2).trimmed();
|
||||
p_needCreole = true;
|
||||
}
|
||||
} else {
|
||||
p_needCreole = true;
|
||||
}
|
||||
}
|
||||
|
||||
p_keyword = ent1;
|
||||
} else {
|
||||
p_needCreole = true;
|
||||
p_keyword = msg;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Components.
|
||||
// [First component]
|
||||
// [Another component] as Comp2
|
||||
// component comp3
|
||||
// component [last\ncomponent] as Comp4
|
||||
static QRegExp comp1("^\\s*component\\s+(?:(\\w+)|\\[([^\\]]+)\\]\\s+as\\s+\\w+)");
|
||||
if (comp1.indexIn(p_keyword) >= 0) {
|
||||
if (comp1.cap(1).isEmpty()) {
|
||||
p_keyword = comp1.cap(2).trimmed();
|
||||
p_needCreole = true;
|
||||
} else {
|
||||
p_keyword = comp1.cap(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This will eat almost anything starting with [].
|
||||
static QRegExp comp2("^\\s*\\[([^\\]]+)\\]");
|
||||
if (comp2.indexIn(p_keyword) >= 0) {
|
||||
p_keyword = comp2.cap(1).trimmed();
|
||||
p_needCreole = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Interface.
|
||||
// interface Int1
|
||||
// interface "last interface" as Int2
|
||||
static QRegExp int1("^\\s*interface\\s+(?:(\\w+)|\"([^\"]+)\"\\s+as\\s+\\w+)");
|
||||
if (int1.indexIn(p_keyword) >= 0) {
|
||||
if (int1.cap(1).isEmpty()) {
|
||||
p_keyword = int1.cap(2).trimmed();
|
||||
p_needCreole = true;
|
||||
} else {
|
||||
p_keyword = int1.cap(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// () "First Interface" as Inter2
|
||||
static QRegExp int2("^\\s*\\(\\)\\s+\"([^\"]+)\"");
|
||||
if (int2.indexIn(p_keyword) >= 0) {
|
||||
p_keyword = int2.cap(1).trimmed();
|
||||
p_needCreole = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool tryStateDiagram(QString &p_keyword, QString &p_hints, bool &p_isRegex, bool &p_needCreole)
|
||||
{
|
||||
Q_UNUSED(p_isRegex);
|
||||
Q_UNUSED(p_hints);
|
||||
|
||||
// state State3 {
|
||||
static QRegExp state("^\\s*state\\s+"
|
||||
"(?:(\\w+)|\"([^\"]+)\")");
|
||||
if (state.indexIn(p_keyword) >= 0) {
|
||||
p_keyword = state.cap(1);
|
||||
if (p_keyword.isEmpty()) {
|
||||
p_keyword = state.cap(2).trimmed();
|
||||
p_needCreole = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// state1 : this is a string
|
||||
static QRegExp state2("^\\s*\\w+\\s*:(.+)");
|
||||
if (state2.indexIn(p_keyword) >= 0) {
|
||||
p_keyword = state2.cap(1).trimmed();
|
||||
p_needCreole = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool tryObjectDiagram(QString &p_keyword, QString &p_hints, bool &p_isRegex, bool &p_needCreole)
|
||||
{
|
||||
Q_UNUSED(p_isRegex);
|
||||
Q_UNUSED(p_hints);
|
||||
|
||||
// object obj {
|
||||
static QRegExp object("^\\s*object\\s+"
|
||||
"(?:(\\w+)|\"([^\"]+)\")");
|
||||
if (object.indexIn(p_keyword) >= 0) {
|
||||
p_keyword = object.cap(1);
|
||||
if (p_keyword.isEmpty()) {
|
||||
p_keyword = object.cap(2).trimmed();
|
||||
p_needCreole = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool tryMultipleLineText(QString &p_keyword)
|
||||
{
|
||||
static QRegExp mulline("\\\\n");
|
||||
|
||||
QString maxPart;
|
||||
bool found = false;
|
||||
int pos = 0;
|
||||
while (pos < p_keyword.size()) {
|
||||
int idx = mulline.indexIn(p_keyword, pos);
|
||||
if (idx == -1) {
|
||||
if (found) {
|
||||
if (p_keyword.size() - pos > maxPart.size()) {
|
||||
maxPart = p_keyword.mid(pos);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
found = true;
|
||||
|
||||
// [pos, idx) is part of the plain text.
|
||||
if (idx - pos > maxPart.size()) {
|
||||
maxPart = p_keyword.mid(pos, idx - pos);
|
||||
}
|
||||
|
||||
pos = idx + mulline.matchedLength();
|
||||
}
|
||||
|
||||
if (found) {
|
||||
p_keyword = maxPart.trimmed();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool tryEmphasizedText(QString &p_keyword)
|
||||
{
|
||||
static QRegExp emph("(--|\\*\\*|//|\"\"|__|~~)"
|
||||
"([^-*/\"_~]+)"
|
||||
"\\1");
|
||||
QString maxPart;
|
||||
bool found = false;
|
||||
int pos = 0;
|
||||
while (pos < p_keyword.size()) {
|
||||
int idx = emph.indexIn(p_keyword, pos);
|
||||
if (idx == -1) {
|
||||
if (found) {
|
||||
if (p_keyword.size() - pos > maxPart.size()) {
|
||||
maxPart = p_keyword.mid(pos);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
found = true;
|
||||
|
||||
// [pos, idx) is part of the plain text.
|
||||
if (idx - pos > maxPart.size()) {
|
||||
maxPart = p_keyword.mid(pos, idx - pos);
|
||||
}
|
||||
|
||||
if (emph.cap(2).size() > maxPart.size()) {
|
||||
maxPart = emph.cap(2);
|
||||
}
|
||||
|
||||
pos = idx + emph.matchedLength();
|
||||
}
|
||||
|
||||
if (found) {
|
||||
p_keyword = maxPart.trimmed();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool tryCreole(QString &p_keyword)
|
||||
{
|
||||
if (p_keyword.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
|
||||
// List.
|
||||
// ** list
|
||||
// # list
|
||||
static QRegExp listMark("^\\s*(?:\\*+|#+)\\s+(.+)$");
|
||||
if (listMark.indexIn(p_keyword) >= 0) {
|
||||
p_keyword = listMark.cap(1).trimmed();
|
||||
return true;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
// Heading.
|
||||
// ### head
|
||||
static QRegExp headMark("^\\s*=+\\s+(.+)");
|
||||
if (headMark.indexIn(p_keyword) >= 0) {
|
||||
p_keyword = headMark.cap(1).trimmed();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
// \n
|
||||
if (tryMultipleLineText(p_keyword)) {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
// Emphasized text.
|
||||
if (tryEmphasizedText(p_keyword)) {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString VPlantUMLHelper::keywordForSmartLivePreview(const QString &p_text,
|
||||
@ -709,7 +1008,11 @@ QString VPlantUMLHelper::keywordForSmartLivePreview(const QString &p_text,
|
||||
|
||||
qDebug() << "tryKeywords" << kw;
|
||||
|
||||
if (tryKeywords(kw)) {
|
||||
if (tryKeywords(kw, needCreole)) {
|
||||
if (needCreole) {
|
||||
goto creole;
|
||||
}
|
||||
|
||||
return kw;
|
||||
}
|
||||
|
||||
@ -753,6 +1056,36 @@ QString VPlantUMLHelper::keywordForSmartLivePreview(const QString &p_text,
|
||||
return kw;
|
||||
}
|
||||
|
||||
qDebug() << "tryComponentDiagram" << kw;
|
||||
|
||||
if (tryComponentDiagram(kw, p_hints, p_isRegex, needCreole)) {
|
||||
if (needCreole) {
|
||||
goto creole;
|
||||
}
|
||||
|
||||
return kw;
|
||||
}
|
||||
|
||||
qDebug() << "tryStateDiagram" << kw;
|
||||
|
||||
if (tryStateDiagram(kw, p_hints, p_isRegex, needCreole)) {
|
||||
if (needCreole) {
|
||||
goto creole;
|
||||
}
|
||||
|
||||
return kw;
|
||||
}
|
||||
|
||||
qDebug() << "tryObjectDiagram" << kw;
|
||||
|
||||
if (tryObjectDiagram(kw, p_hints, p_isRegex, needCreole)) {
|
||||
if (needCreole) {
|
||||
goto creole;
|
||||
}
|
||||
|
||||
return kw;
|
||||
}
|
||||
|
||||
qDebug() << "tryCommonElements" << kw;
|
||||
|
||||
if (tryCommonElements(kw, p_hints, p_isRegex, needCreole)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user