some improvements in the scripting part

This commit is contained in:
Michael Zanetti 2019-11-28 20:51:49 +01:00
parent 59047704ae
commit e160ad9665
6 changed files with 75 additions and 26 deletions

View File

@ -15,6 +15,11 @@ CodeCompletion::CodeCompletion(QObject *parent):
m_classes.insert("DeviceState", ClassInfo("DeviceState", {"id", "deviceId", "stateTypeId", "stateName", "value"}, {}, {"onValueChanged"}));
m_classes.insert("DeviceEvent", ClassInfo("DeviceEvent", {"id", "deviceId", "eventTypeId", "eventName"}, {}, {"onTriggered"}));
m_classes.insert("Timer", ClassInfo("Timer", {"id", "interval", "running", "repeat"}, {"start", "stop"}, {"onTriggered"}));
m_classes.insert("PropertyAnimation", ClassInfo("PropertyAnimation", {"id", "target", "targets", "property", "properties", "value", "from", "to", "easing", "exclude", "duration", "alwaysRunToEnd", "loops", "paused", "running"}, {"start", "stop", "pause", "resume", "complete"}, {"onStarted", "onStopped", "onFinished", "onRunningChanged"}));
m_classes.insert("ColorAnimation", ClassInfo("ColorAnimation", {"id", "target", "targets", "property", "properties", "value", "from", "to", "easing", "exclude", "duration", "alwaysRunToEnd", "loops", "paused", "running"}, {"start", "stop", "pause", "resume", "complete"}, {"onStarted", "onStopped", "onFinished", "onRunningChanged"}));
m_classes.insert("SequentialAnimation", ClassInfo("SequentialAnimation", {"id", "alwaysRunToEnd", "loops", "paused", "running"}, {"start", "stop", "pause", "resume", "complete"}, {"onStarted", "onStopped", "onFinished", "onRunningChanged"}));
m_classes.insert("ParallelAnimation", ClassInfo("ParallelAnimation", {"id", "alwaysRunToEnd", "loops", "paused", "running"}, {"start", "stop", "pause", "resume", "complete"}, {"onStarted", "onStopped", "onFinished", "onRunningChanged"}));
m_classes.insert("PauseAnimation", ClassInfo("PauseAnimation", {"id", "duration", "alwaysRunToEnd", "loops", "paused", "running"}, {"start", "stop", "pause", "resume", "complete"}, {"onStarted", "onStopped", "onFinished", "onRunningChanged"}));
m_attachedClasses.insert("Component", ClassInfo("Component", {}, {}, {"onCompleted", "onDestruction", "onDestroyed"}));
@ -27,6 +32,7 @@ CodeCompletion::CodeCompletion(QObject *parent):
m_genericJsSyntax.insert("do", "do ");
m_genericJsSyntax.insert("if", "if ");
m_genericJsSyntax.insert("else", "else ");
m_genericJsSyntax.insert("print", "print");
m_jsClasses.insert("console", ClassInfo("console", {}, {"log", "warn"}));
m_jsClasses.insert("JSON", ClassInfo("JSON", {}, {"stringify", "parse", "hasOwnProperty", "isPrototypeOf", "toString", "valueOf", "toLocaleString", "propertyIsEnumerable"}));
@ -157,8 +163,10 @@ void CodeCompletion::update()
}
QRegExp stateNameExp(".*stateName: \"[a-zA-Z0-9-]*");
qDebug() << "block text" << blockText << stateNameExp.exactMatch(blockText);
if (stateNameExp.exactMatch(blockText)) {
BlockInfo info = getBlockInfo(m_cursor.position());
qDebug() << "stateName block info" << info.name << info.properties;
if (!info.properties.contains("deviceId")) {
return;
}
@ -456,7 +464,6 @@ CodeCompletion::BlockInfo CodeCompletion::getBlockInfo(int position) const
info.end = m_document->textDocument()->find("}", position).position();
info.valid = true;
qDebug() << "Block strats at" << blockStart.position();
info.name = blockStart.block().text();
info.name.remove(QRegExp(" *\\{"));
@ -464,25 +471,27 @@ CodeCompletion::BlockInfo CodeCompletion::getBlockInfo(int position) const
info.name.remove(QRegExp(".* "));
}
qDebug() << "Block starts at" << blockStart.position() << "contents:" << blockStart.block().text();
int childBlocks = 0;
while (!blockStart.isNull() && blockStart.position() < position) {
QTextCursor tmp = m_document->textDocument()->find(QRegExp("[{}\n]"), blockStart);
if (tmp.selectedText() == "{") {
blockStart = tmp;
QString line = blockStart.block().text();
if (line.endsWith("{")) {
blockStart.movePosition(QTextCursor::NextBlock);
childBlocks++;
continue;
}
if (tmp.selectedText() == "}") {
blockStart = tmp;
if (line.trimmed().startsWith("}")) {
blockStart.movePosition(QTextCursor::NextBlock);
childBlocks--;
continue;
}
// \n
if (childBlocks > 0) { // Skip all stuff in child blocks
blockStart = tmp;
if (childBlocks > 1) { // Skip all stuff in child blocks
blockStart.movePosition(QTextCursor::NextBlock);
continue;
}
foreach (const QString &statement, blockStart.block().text().split(";")) {
qDebug() << "Have statement" << statement;
QStringList parts = statement.split(":");
if (parts.length() != 2) {
continue;
@ -492,7 +501,7 @@ CodeCompletion::BlockInfo CodeCompletion::getBlockInfo(int position) const
qDebug() << "inserting:" << propName << "->" << propValue;
info.properties.insert(propName, propValue);
}
blockStart = tmp;
blockStart.movePosition(QTextCursor::NextBlock);
}
return info;

View File

@ -124,11 +124,16 @@ void ScriptManager::onNotificationReceived(const QVariantMap &params)
Script *script = new Script(scriptMap.value("id").toUuid());
script->setName(scriptMap.value("name").toString());
m_scripts->addScript(script);
emit addScriptReply(params.value("id").toInt(),
params.value("params").toMap().value("scriptError").toString(),
params.value("params").toMap().value("scriptId").toUuid(),
params.value("params").toMap().value("errors").toStringList());
}
else if (params.value("notification").toString() == "Scripts.ScriptRemoved") {
QUuid id = params.value("params").toMap().value("scriptId").toUuid();
QUuid id = params.value("params").toMap().value("id").toUuid();
m_scripts->removeScript(id);
emit removeScriptReply(params.value("id").toInt(), params.value("params").toMap().value("scriptError").toString());
}
else if (params.value("notification").toString() == "Scripts.ScriptChanged") {

View File

@ -28,7 +28,7 @@ Page {
RuleTemplatesFilterModel {
id: ruleTemplatesModel
ruleTemplates: RuleTemplates {}
readonly property var deviceClass: device ? engine.deviceManager.deviceClasses.getDeviceClass(root.device.deviceClassId) : null
readonly property var deviceClass: root.device ? engine.deviceManager.deviceClasses.getDeviceClass(root.device.deviceClassId) : null
filterByDevices: DevicesProxy { engine: _engine }
filterInterfaceNames: deviceClass ? deviceClass.interfaces : []
}

View File

@ -47,7 +47,7 @@ Page {
HeaderButton {
imageSource: "../images/save.svg"
enabled: d.script.name !== nameTextField.text || d.oldContent !== scriptEdit.text
enabled: d.script && d.script.name !== nameTextField.text || d.oldContent !== scriptEdit.text
color: enabled ? app.accentColor : keyColor
hoverEnabled: true
ToolTip.text: qsTr("Deploy script")
@ -90,6 +90,7 @@ Page {
d.callId = -1;
if (scriptError == "ScriptErrorNoError") {
d.scriptId = scriptId;
d.oldContent = scriptEdit.text;
}
errorModel.update(errors);
}
@ -97,8 +98,10 @@ Page {
onEditScriptReply: {
print("edit reply", id, d.callId)
if (id == d.callId) {
d.oldContent = scriptEdit.text;
d.callId = -1;
if (scriptError == "ScriptErrorNoError") {
d.oldContent = scriptEdit.text;
}
errorModel.update(errors)
}
}
@ -141,6 +144,7 @@ Page {
LineNumbers {
id: lineNumbers
textArea: scriptEdit
}
TextArea.flickable: TextArea {
@ -217,6 +221,20 @@ Page {
completionBox.show();
event.accepted = true;
return;
case Qt.Key_Plus:
if (event.modifiers & Qt.ControlModifier) {
scriptEdit.font.pixelSize++;
event.accepted = true;
return;
}
break;
case Qt.Key_Minus:
if (event.modifiers & Qt.ControlModifier) {
scriptEdit.font.pixelSize--;
event.accepted = true;
return;
}
}
// Things to do only when we're autocompleting
@ -289,8 +307,7 @@ Page {
delegate: Label {
width: parent.width
text: model.line + ":" + model.column + ": " + model.message
font.pixelSize: app.extraSmallFont
font.family: "Monospace"
font: scriptEdit.font
}
}
}
@ -324,8 +341,7 @@ Page {
delegate: Label {
width: parent.width
text: model.message
font.pixelSize: app.extraSmallFont
font.family: "Monospace"
font: scriptEdit.font
color: model.type === "ScriptMessageTypeWarning" ? "red" : app.foregroundColor
}
}

View File

@ -24,7 +24,7 @@ Page {
Connections {
target: engine.scriptManager
onRemovScriptReply: {
onRemoveScriptReply: {
if (id == d.pendingAction) {
d.pendingAction = -1;
}
@ -48,6 +48,17 @@ Page {
d.pendingAction = engine.scriptManager.removeScript(model.id);
}
}
EmptyViewPlaceholder {
anchors.centerIn: parent
title: qsTr("No scripts are installed yet.")
text: qsTr("Press \"Add script\" to get started.")
imageSource: "../images/script.svg"
buttonText: qsTr("Add script")
onButtonClicked: {
pageStack.push("ScriptEditor.qml");
}
}
}
BusyOverlay {

View File

@ -1,13 +1,21 @@
import QtQuick 2.2
import QtQuick 2.4
import QtQuick.Controls 2.2
Rectangle {
id: lineNumbers
id: root
property TextArea textArea: null
FontMetrics {
id: fontMetrics
font: textArea.font
}
width: {
var ret = 10;
var ret = fontMetrics.maximumCharacterWidth * 2;
var tmp = scriptEdit.lineCount
while (tmp >= 10) {
ret += 10;
ret += fontMetrics.maximumCharacterWidth;
tmp /= 10;
}
return ret;
@ -25,11 +33,11 @@ Rectangle {
anchors.fill: parent
anchors.topMargin: 8
Repeater {
model: scriptEdit.lineCount
model: root.textArea.lineCount
delegate: Rectangle {
id: lineNumberDelegate
width: parent.width
height: scriptEdit.contentHeight / scriptEdit.lineCount
height: root.textArea.contentHeight / root.textArea.lineCount
color: hasError ? "#FF0000" : "transparent"
readonly property bool hasError: errorModel.errorLines.indexOf(index + 1) >= 0
Label {
@ -38,8 +46,8 @@ Rectangle {
anchors.right: parent.right
anchors.rightMargin: 3
text: index + 1
font.pixelSize: scriptEdit.font.pixelSize
font.family: scriptEdit.font.family
font.pixelSize: root.textArea.font.pixelSize
font.family: root.textArea.font.family
font.weight: Font.Light
color: lineNumberDelegate.hasError ? "#FFFFFF" : "#808080"
}