diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml
index 516b7f7a3..358750b24 100644
--- a/mix/qml/Debugger.qml
+++ b/mix/qml/Debugger.qml
@@ -40,7 +40,7 @@ Rectangle {
var errorInfo = ErrorLocationFormater.extractErrorInfo(compilationErrorMessage, false);
errorLocation.text = errorInfo.errorLocation;
errorDetail.text = errorInfo.errorDetail;
- errorLine.text = errorInfo.errorLine;
+ errorLine.text = errorInfo.line;
}
function update(data, giveFocus)
@@ -242,7 +242,6 @@ Rectangle {
height: 30
buttonShortcut: "Ctrl+Shift+F11"
buttonTooltip: qsTr("Step Out Back")
- visible: false
}
StepActionImage
@@ -315,9 +314,8 @@ Rectangle {
height: 30
buttonShortcut: "Ctrl+F5"
buttonTooltip: qsTr("Run Forward")
+ visible: false
}
-
-
}
}
diff --git a/mix/qml/WebCodeEditor.qml b/mix/qml/WebCodeEditor.qml
index 5cf786d5f..7e5945fc7 100644
--- a/mix/qml/WebCodeEditor.qml
+++ b/mix/qml/WebCodeEditor.qml
@@ -4,6 +4,7 @@ import QtQuick.Layouts 1.0
import QtQuick.Controls.Styles 1.1
import QtWebEngine 1.0
import QtWebEngine.experimental 1.0
+import "js/ErrorLocationFormater.js" as ErrorLocationFormater
Item {
signal editorTextChanged
@@ -83,7 +84,22 @@ Item {
runJavaScript("getTextChanged()", function(result) { });
pollTimer.running = true;
syncClipboard();
+ if (currentMode === "solidity")
+ {
+ codeModel.onCompilationComplete.connect(function(){
+ runJavaScript("compilationComplete()", function(result) { });
+ });
+
+ codeModel.onCompilationError.connect(function(error){
+ var errorInfo = ErrorLocationFormater.extractErrorInfo(error, false);
+ if (errorInfo.line && errorInfo.column)
+ runJavaScript("compilationError('" + errorInfo.line + "', '" + errorInfo.column + "', '" + errorInfo.errorDetail + "')", function(result) { });
+ else
+ runJavaScript("compilationComplete()", function(result) { });
+ });
+ }
parent.changeGeneration();
+
}
}
diff --git a/mix/qml/html/cm/errorannotation.js b/mix/qml/html/cm/errorannotation.js
new file mode 100644
index 000000000..03e36c927
--- /dev/null
+++ b/mix/qml/html/cm/errorannotation.js
@@ -0,0 +1,46 @@
+function ErrorAnnotation(editor, line, column, content)
+{
+ this.opened = false;
+ this.line = line;
+ this.column = column;
+ this.content = content.replace("Contract Error:", "");
+ this.editor = editor;
+ this.errorMark = null;
+ this.lineWidget = null;
+ this.init();
+ this.open();
+}
+
+ErrorAnnotation.prototype.init = function()
+{
+ var separators = [';', ',', '\\\(', '\\\{', '\\\}', '\\\)', ':'];
+ var errorPart = editor.getLine(this.line).substring(this.column);
+ var incrMark = this.column + errorPart.split(new RegExp(separators.join('|'), 'g'))[0].length;
+ if (incrMark === this.column)
+ incrMark = this.column + 1;
+ this.errorMark = editor.markText({ line: this.line, ch: this.column }, { line: this.line, ch: incrMark }, { className: "CodeMirror-errorannotation", inclusiveRight: true });
+}
+
+ErrorAnnotation.prototype.open = function()
+{
+ var node = document.createElement("div");
+ node.id = "annotation"
+ node.innerHTML = this.content;
+ node.className = "CodeMirror-errorannotation-context";
+ this.lineWidget = this.editor.addLineWidget(this.errorMark.find().from.line, node, { coverGutter: false });
+ this.opened = true;
+}
+
+ErrorAnnotation.prototype.close = function()
+{
+ this.lineWidget.clear();
+ this.opened = false;
+}
+
+ErrorAnnotation.prototype.destroy = function()
+{
+ if (this.opened)
+ this.close();
+ if (this.errorMark)
+ this.errorMark.clear();
+}
diff --git a/mix/qml/html/cm/solarized.css b/mix/qml/html/cm/solarized.css
index f07b8b43b..ece98a95c 100644
--- a/mix/qml/html/cm/solarized.css
+++ b/mix/qml/html/cm/solarized.css
@@ -169,3 +169,16 @@ view-port
background: rgba(255, 255, 255, 0.10);
}
+/* Error annotation */
+.CodeMirror-errorannotation {
+ border-bottom: 1px solid #b58900;
+}
+
+.CodeMirror-errorannotation-context {
+ font-family: monospace;
+ font-size: small;
+ color: #586e75;
+ background: #b58900;
+ padding: 2px;
+}
+
diff --git a/mix/qml/html/codeeditor.html b/mix/qml/html/codeeditor.html
index 28a01c9a5..eec13f109 100644
--- a/mix/qml/html/codeeditor.html
+++ b/mix/qml/html/codeeditor.html
@@ -22,6 +22,7 @@
+
diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js
index b739e2ed5..daf1286d8 100644
--- a/mix/qml/html/codeeditor.js
+++ b/mix/qml/html/codeeditor.js
@@ -22,23 +22,23 @@ editor.on("change", function(eMirror, object) {
var mac = /Mac/.test(navigator.platform);
if (mac === true) {
-editor.setOption("extraKeys", {
- "Cmd-V": function(cm) {
- cm.replaceSelection(clipboard);
- },
- "Cmd-X": function(cm) {
- window.document.execCommand("cut");
- },
- "Cmd-C": function(cm) {
- window.document.execCommand("copy");
- }});
+ editor.setOption("extraKeys", {
+ "Cmd-V": function(cm) {
+ cm.replaceSelection(clipboard);
+ },
+ "Cmd-X": function(cm) {
+ window.document.execCommand("cut");
+ },
+ "Cmd-C": function(cm) {
+ window.document.execCommand("copy");
+ }});
}
makeMarker = function() {
- var marker = document.createElement("div");
- marker.style.color = "#822";
- marker.innerHTML = "●";
- return marker;
+ var marker = document.createElement("div");
+ marker.style.color = "#822";
+ marker.innerHTML = "●";
+ return marker;
};
toggleBreakpointLine = function(n) {
@@ -77,9 +77,9 @@ getBreakpoints = function() {
if (line.gutterMarkers && line.gutterMarkers["breakpoints"]) {
var l = doc.getLineNumber(line);
locations.push({
- start: editor.indexFromPos({ line: l, ch: 0}),
- end: editor.indexFromPos({ line: l + 1, ch: 0})
- });;
+ start: editor.indexFromPos({ line: l, ch: 0}),
+ end: editor.indexFromPos({ line: l + 1, ch: 0})
+ });;
}
});
return locations;
@@ -116,7 +116,7 @@ setMode = function(mode) {
else if (mode === "solidity")
{
CodeMirror.commands.autocomplete = function(cm) {
- CodeMirror.showHint(cm, CodeMirror.hint.anyword);
+ CodeMirror.showHint(cm, CodeMirror.hint.anyword);
}
editor.setOption("extraKeys", {
"Ctrl-Space": "autocomplete"
@@ -132,6 +132,8 @@ var executionMark;
highlightExecution = function(start, end) {
if (executionMark)
executionMark.clear();
+ if (start === 0 && end + 1 === editor.getValue().length)
+ return; // Do not hightlight the whole document.
executionMark = editor.markText(editor.posFromIndex(start), editor.posFromIndex(end), { className: "CodeMirror-exechighlight" });
}
@@ -145,3 +147,38 @@ isClean = function()
{
return editor.isClean(changeId);
}
+
+var annotation = null;
+var compilationCompleteBool = true;
+compilationError = function(line, column, content)
+{
+ compilationCompleteBool = false;
+ window.setTimeout(function(){
+ if (compilationCompleteBool)
+ return;
+ line = parseInt(line);
+ column = parseInt(column);
+ if (line > 0)
+ line = line - 1;
+ if (column > 0)
+ column = column - 1;
+
+ if (annotation == null)
+ annotation = new ErrorAnnotation(editor, line, column, content);
+ else if (annotation.line !== line || annotation.column !== column || annotation.content !== content)
+ {
+ annotation.destroy();
+ annotation = new ErrorAnnotation(editor, line, column, content);
+ }
+ }, 500)
+}
+
+compilationComplete = function()
+{
+ if (annotation !== null)
+ {
+ annotation.destroy();
+ annotation = null;
+ }
+ compilationCompleteBool = true;
+}
diff --git a/mix/qml/js/ErrorLocationFormater.js b/mix/qml/js/ErrorLocationFormater.js
index 8c83e6b15..cb92f298b 100644
--- a/mix/qml/js/ErrorLocationFormater.js
+++ b/mix/qml/js/ErrorLocationFormater.js
@@ -16,12 +16,15 @@ function extractErrorInfo(raw, shortMessage)
{
_return.errorLocation = ErrorLocationFormater.formatLocation(reg[0], shortMessage);
_return.errorDetail = detail.replace(reg[0], "");
+ _return.line = reg[0].split(':')[1];
+ _return.column = reg[0].split(':')[2];
}
else
{
_return.errorLocation = "";
_return.errorDetail = detail;
+ _return.line = "";
+ _return.column = "";
}
- _return.errorLine = raw.split('\n')[1];
return _return;
}
diff --git a/mix/web.qrc b/mix/web.qrc
index 499ad5746..aa5b38a67 100644
--- a/mix/web.qrc
+++ b/mix/web.qrc
@@ -27,6 +27,7 @@
qml/html/cm/closebrackets.js
qml/html/cm/solidityToken.js
qml/html/cm/javascript-hint.js
+ qml/html/cm/errorannotation.js
qml/html/cm/tern.js
qml/html/cm/ecma5spec.js
qml/html/cm/comment.js