Some improvements in the Script autocompletion
parent
f865481b03
commit
828231c625
|
|
@ -427,28 +427,40 @@ void CodeCompletion::update()
|
||||||
QString id = blockText;
|
QString id = blockText;
|
||||||
id.remove(QRegExp(".* ")).remove(QRegExp("\\.[a-zA-Z0-9]*"));
|
id.remove(QRegExp(".* ")).remove(QRegExp("\\.[a-zA-Z0-9]*"));
|
||||||
QString type = getIdTypes().value(id);
|
QString type = getIdTypes().value(id);
|
||||||
|
int blockPosition = getBlockPosition(id);
|
||||||
|
BlockInfo blockInfo = getBlockInfo(blockPosition);
|
||||||
|
|
||||||
qDebug() << "dot expression:" << id << type;
|
qDebug() << "dot expression:" << id << type;
|
||||||
// Classes
|
qDebug() << "lvalue info:" << blockInfo.properties.keys() << blockInfo.properties.value("actionName") << blockInfo.properties.value("actionTypeId");
|
||||||
|
|
||||||
|
// Append properties of the type
|
||||||
foreach (const QString &property, m_classes.value(type).properties) {
|
foreach (const QString &property, m_classes.value(type).properties) {
|
||||||
entries.append(CompletionModel::Entry(property, property, "property"));
|
entries.append(CompletionModel::Entry(property, property, "property"));
|
||||||
}
|
}
|
||||||
|
// Append user-defined properties of the type
|
||||||
|
foreach (const QString &property, blockInfo.properties.keys()) {
|
||||||
|
CompletionModel::Entry entry(property, property, "property");
|
||||||
|
if (!entries.contains(entry)) {
|
||||||
|
entries.append(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append methods of the item
|
||||||
foreach (const QString &method, m_classes.value(type).methods) {
|
foreach (const QString &method, m_classes.value(type).methods) {
|
||||||
QString paramString;
|
QString paramString;
|
||||||
|
// If it's an execute() call, also autocomplete the params
|
||||||
if (method == "execute") {
|
if (method == "execute") {
|
||||||
int blockposition = getBlockPosition(id);
|
qDebug() << "Blockposition:" << blockPosition;
|
||||||
qDebug() << "Blockposition:" << blockposition;
|
if (blockPosition >= 0) {
|
||||||
if (blockposition >= 0) {
|
if (blockInfo.valid) {
|
||||||
BlockInfo info = getBlockInfo(blockposition);
|
QString thingId = blockInfo.properties.value("thingId");
|
||||||
qDebug() << "actionType" << info.properties.keys() << info.properties.value("actionName") << info.properties.value("actionTypeId");
|
|
||||||
if (info.valid) {
|
|
||||||
QString thingId = info.properties.value("thingId");
|
|
||||||
Device *d = m_engine->thingManager()->things()->getDevice(QUuid(thingId));
|
Device *d = m_engine->thingManager()->things()->getDevice(QUuid(thingId));
|
||||||
if (d) {
|
if (d) {
|
||||||
ActionType *at = nullptr;
|
ActionType *at = nullptr;
|
||||||
if (info.properties.contains("actionTypeId")) {
|
if (blockInfo.properties.contains("actionTypeId")) {
|
||||||
at = d->thingClass()->actionTypes()->getActionType(info.properties.value("actionTypeId"));
|
at = d->thingClass()->actionTypes()->getActionType(blockInfo.properties.value("actionTypeId"));
|
||||||
} else if (info.properties.contains("actionName")) {
|
} else if (blockInfo.properties.contains("actionName")) {
|
||||||
at = d->thingClass()->actionTypes()->findByName(info.properties.value("actionName"));
|
at = d->thingClass()->actionTypes()->findByName(blockInfo.properties.value("actionName"));
|
||||||
}
|
}
|
||||||
if (at) {
|
if (at) {
|
||||||
QStringList params;
|
QStringList params;
|
||||||
|
|
@ -466,6 +478,10 @@ void CodeCompletion::update()
|
||||||
}
|
}
|
||||||
entries.append(CompletionModel::Entry(method + "(", method, "method", "", paramString + ")"));
|
entries.append(CompletionModel::Entry(method + "(", method, "method", "", paramString + ")"));
|
||||||
}
|
}
|
||||||
|
// User-defined functions of the item
|
||||||
|
foreach (const QString &function, blockInfo.functions) {
|
||||||
|
entries.append(CompletionModel::Entry(function + "(", function, "method", "", ")"));
|
||||||
|
}
|
||||||
// Attached classes/properties
|
// Attached classes/properties
|
||||||
foreach (const QString &property, m_attachedClasses.value(id).properties) {
|
foreach (const QString &property, m_attachedClasses.value(id).properties) {
|
||||||
entries.append(CompletionModel::Entry(property, property, "property"));
|
entries.append(CompletionModel::Entry(property, property, "property"));
|
||||||
|
|
@ -595,8 +611,9 @@ CodeCompletion::BlockInfo CodeCompletion::getBlockInfo(int position) const
|
||||||
}
|
}
|
||||||
|
|
||||||
info.start = blockStart.position();
|
info.start = blockStart.position();
|
||||||
info.end = blockEnd.position(); //m_document->textDocument()->find("}", position).position();
|
info.end = blockEnd.position();
|
||||||
info.valid = true;
|
info.valid = true;
|
||||||
|
// qDebug() << "Block start:" << info.start << "end:" << info.end;
|
||||||
|
|
||||||
info.name = blockStart.block().text();
|
info.name = blockStart.block().text();
|
||||||
info.name.remove(QRegExp(" *\\{ *"));
|
info.name.remove(QRegExp(" *\\{ *"));
|
||||||
|
|
@ -607,14 +624,11 @@ CodeCompletion::BlockInfo CodeCompletion::getBlockInfo(int position) const
|
||||||
int childBlocks = 0;
|
int childBlocks = 0;
|
||||||
while (!blockStart.isNull() && blockStart.position() < info.end) {
|
while (!blockStart.isNull() && blockStart.position() < info.end) {
|
||||||
QString line = blockStart.block().text();
|
QString line = blockStart.block().text();
|
||||||
if (line.endsWith("{")) {
|
// qDebug() << "line:" << line;
|
||||||
|
if (line.contains("{") && !line.contains("}")) {
|
||||||
childBlocks++;
|
childBlocks++;
|
||||||
if (!blockStart.movePosition(QTextCursor::NextBlock)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (line.trimmed().startsWith("}")) {
|
if (line.contains("}") && !line.contains("{")) {
|
||||||
childBlocks--;
|
childBlocks--;
|
||||||
if (!blockStart.movePosition(QTextCursor::NextBlock)) {
|
if (!blockStart.movePosition(QTextCursor::NextBlock)) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -622,18 +636,30 @@ CodeCompletion::BlockInfo CodeCompletion::getBlockInfo(int position) const
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// \n
|
// \n
|
||||||
if (childBlocks > 1) { // Skip all stuff in child blocks
|
if (childBlocks > 1 && !(childBlocks == 2 && line.trimmed().startsWith("function"))) { // Skip all stuff in child blocks
|
||||||
|
// qDebug() << "skipping line in child block" << childBlocks;
|
||||||
blockStart.movePosition(QTextCursor::NextBlock);
|
blockStart.movePosition(QTextCursor::NextBlock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
foreach (const QString &statement, blockStart.block().text().split(";")) {
|
foreach (const QString &statement, blockStart.block().text().split(";")) {
|
||||||
|
// qDebug() << "analysing statement:" << statement;
|
||||||
QStringList parts = statement.split(":");
|
QStringList parts = statement.split(":");
|
||||||
if (parts.length() != 2) {
|
if (parts.length() == 2) { // Properties must be "foo: bar"
|
||||||
continue;
|
QString propName = parts.first().trimmed();
|
||||||
|
if (propName.split(" ").count() > 1) { // trim modifiers e.g. "property bool foo: bar"
|
||||||
|
propName = propName.split(" ").last();
|
||||||
|
}
|
||||||
|
if (propName.contains(".")) { // skip attached properties e.g. "Component.onCompleted: ..."
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
QString propValue = parts.last().split("//").first().trimmed().remove("\"");
|
||||||
|
info.properties.insert(propName, propValue);
|
||||||
|
}
|
||||||
|
parts = statement.trimmed().split(" ");
|
||||||
|
if (parts.count() >= 2 && parts.first().trimmed() == "function") {
|
||||||
|
QString functionHeader = parts.at(1).trimmed();
|
||||||
|
info.functions.append(functionHeader.split("(").first());
|
||||||
}
|
}
|
||||||
QString propName = parts.first().trimmed();
|
|
||||||
QString propValue = parts.last().split("//").first().trimmed().remove("\"");
|
|
||||||
info.properties.insert(propName, propValue);
|
|
||||||
}
|
}
|
||||||
if (!blockStart.movePosition(QTextCursor::NextBlock)) {
|
if (!blockStart.movePosition(QTextCursor::NextBlock)) {
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ private:
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
QString name;
|
QString name;
|
||||||
QHash<QString, QString> properties;
|
QHash<QString, QString> properties;
|
||||||
|
QStringList functions;
|
||||||
int start = -1;
|
int start = -1;
|
||||||
int end = -1;
|
int end = -1;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ CompletionModel::Entry CompletionModel::get(int index)
|
||||||
return m_list.at(index);
|
return m_list.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//************************************************
|
//************************************************
|
||||||
// CompletionProxyModel
|
// CompletionProxyModel
|
||||||
//************************************************
|
//************************************************
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,9 @@ public:
|
||||||
QString decoration;
|
QString decoration;
|
||||||
QString decorationProperty;
|
QString decorationProperty;
|
||||||
QString trailingText;
|
QString trailingText;
|
||||||
|
bool operator==(const Entry &other) const {
|
||||||
|
return text == other.text && displayText == other.displayText;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
CompletionModel(QObject *parent = nullptr);
|
CompletionModel(QObject *parent = nullptr);
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QTextDocumentFragment>
|
#include <QTextDocumentFragment>
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
class ScriptSyntaxHighlighterPrivate: public QSyntaxHighlighter
|
class ScriptSyntaxHighlighterPrivate: public QSyntaxHighlighter
|
||||||
{
|
{
|
||||||
|
|
@ -62,7 +63,7 @@ private:
|
||||||
};
|
};
|
||||||
struct HighlightingRule
|
struct HighlightingRule
|
||||||
{
|
{
|
||||||
QRegExp pattern;
|
QRegularExpression pattern;
|
||||||
QTextCharFormat format;
|
QTextCharFormat format;
|
||||||
};
|
};
|
||||||
QVector<HighlightingRule> highlightingRules;
|
QVector<HighlightingRule> highlightingRules;
|
||||||
|
|
@ -118,19 +119,19 @@ void ScriptSyntaxHighlighterPrivate::update(bool dark)
|
||||||
|
|
||||||
// ClassNames
|
// ClassNames
|
||||||
format.setForeground(dark ? QColor("#55fc49") : QColor("#800080"));
|
format.setForeground(dark ? QColor("#55fc49") : QColor("#800080"));
|
||||||
rule.pattern = QRegExp("\\b[A-Z][a-zA-Z0-9_]+\\b");
|
rule.pattern = QRegularExpression("\\b[A-Z][a-zA-Z0-9_]+\\b");
|
||||||
rule.format = format;
|
rule.format = format;
|
||||||
highlightingRules.append(rule);
|
highlightingRules.append(rule);
|
||||||
|
|
||||||
// Property bindings
|
// Property bindings
|
||||||
format.setForeground(dark ? QColor("#ff5555") : QColor("#800000"));
|
format.setForeground(dark ? QColor("#ff5555") : QColor("#800000"));
|
||||||
rule.pattern = QRegExp("[a-zA-Z][a-zA-Z0-9_.]+:");
|
rule.pattern = QRegularExpression("[a-zA-Z][a-zA-Z0-9_.]+:");
|
||||||
rule.format = format;
|
rule.format = format;
|
||||||
highlightingRules.append(rule);
|
highlightingRules.append(rule);
|
||||||
|
|
||||||
// imports
|
// imports
|
||||||
format.clearForeground();
|
format.clearForeground();
|
||||||
rule.pattern = QRegExp("import .*$");
|
rule.pattern = QRegularExpression("import .*$");
|
||||||
rule.format = format;
|
rule.format = format;
|
||||||
highlightingRules.append(rule);
|
highlightingRules.append(rule);
|
||||||
|
|
||||||
|
|
@ -158,13 +159,14 @@ void ScriptSyntaxHighlighterPrivate::update(bool dark)
|
||||||
"\\bbool\\b",
|
"\\bbool\\b",
|
||||||
"\\bint\\b",
|
"\\bint\\b",
|
||||||
"\\breal\\b",
|
"\\breal\\b",
|
||||||
|
"\\bdouble\\b",
|
||||||
"\\bdate\\b",
|
"\\bdate\\b",
|
||||||
"\\btrue\\b",
|
"\\btrue\\b",
|
||||||
"\\bfalse\\b",
|
"\\bfalse\\b",
|
||||||
};
|
};
|
||||||
format.setForeground(dark ? Qt::yellow : QColor("#80831a"));
|
format.setForeground(dark ? Qt::yellow : QColor("#80831a"));
|
||||||
foreach (const QString &pattern, keywordPatterns) {
|
foreach (const QString &pattern, keywordPatterns) {
|
||||||
rule.pattern = QRegExp(pattern);
|
rule.pattern = QRegularExpression(pattern);
|
||||||
rule.format = format;
|
rule.format = format;
|
||||||
highlightingRules.append(rule);
|
highlightingRules.append(rule);
|
||||||
}
|
}
|
||||||
|
|
@ -172,17 +174,15 @@ void ScriptSyntaxHighlighterPrivate::update(bool dark)
|
||||||
// String literals
|
// String literals
|
||||||
format.setForeground(dark ? QColor("#e64ad7") : Qt::darkGreen);
|
format.setForeground(dark ? QColor("#e64ad7") : Qt::darkGreen);
|
||||||
rule.format = format;
|
rule.format = format;
|
||||||
rule.pattern = QRegExp("\".[^\"]*\"");
|
rule.pattern = QRegularExpression(R"**((?<!\\)([\"'])(.*?)(?<!\\)\1)**", QRegularExpression::DotMatchesEverythingOption | QRegularExpression::MultilineOption);
|
||||||
highlightingRules.append(rule);
|
|
||||||
rule.pattern = QRegExp("'.[^']*'");
|
|
||||||
highlightingRules.append(rule);
|
highlightingRules.append(rule);
|
||||||
|
|
||||||
// comments
|
// comments
|
||||||
format.setForeground(dark ? Qt::cyan : Qt::darkGray);
|
format.setForeground(dark ? Qt::cyan : Qt::darkGray);
|
||||||
rule.format = format;
|
rule.format = format;
|
||||||
rule.pattern = QRegExp("//.*$");
|
rule.pattern = QRegularExpression("//.*$");
|
||||||
highlightingRules.append(rule);
|
highlightingRules.append(rule);
|
||||||
rule.pattern = QRegExp("/*.*\\*/");
|
rule.pattern = QRegularExpression("/*.*\\*/");
|
||||||
highlightingRules.append(rule);
|
highlightingRules.append(rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,15 +191,11 @@ void ScriptSyntaxHighlighterPrivate::highlightBlock(const QString &text)
|
||||||
// qDebug() << "hightlightBlock called for" << text << previousBlockState() << currentBlock().text();
|
// qDebug() << "hightlightBlock called for" << text << previousBlockState() << currentBlock().text();
|
||||||
|
|
||||||
foreach(const HighlightingRule &rule, highlightingRules){
|
foreach(const HighlightingRule &rule, highlightingRules){
|
||||||
QRegExp expression(rule.pattern);
|
QRegularExpression expression(rule.pattern);
|
||||||
int index = expression.indexIn(text);
|
QRegularExpressionMatchIterator matches = expression.globalMatch(text);
|
||||||
while (index >= 0) {
|
while (matches.hasNext()) {
|
||||||
int length = expression.matchedLength();
|
QRegularExpressionMatch match = matches.next();
|
||||||
if (text.mid(index, length).endsWith(':')) {
|
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
|
||||||
length--;
|
|
||||||
}
|
|
||||||
setFormat(index, length, rule.format);
|
|
||||||
index = expression.indexIn(text, index + length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (text.trimmed().startsWith("import")) {
|
if (text.trimmed().startsWith("import")) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue