add goToNextError command

This commit is contained in:
nightwing 2013-12-29 19:56:29 +04:00
commit 4c4ab09870
3 changed files with 278 additions and 23 deletions

View file

@ -52,6 +52,26 @@ exports.commands = [{
});
},
readOnly: true
}, {
name: "goToNextError",
bindKey: bindKey("Alt-E", "Ctrl-E"),
exec: function(editor) {
config.loadModule("ace/ext/error_marker", function(module) {
module.showErrorMarker(editor, 1);
});
},
scrollIntoView: "center",
readOnly: true
}, {
name: "goToPreviousError",
bindKey: bindKey("Alt-Shift-E", "Ctrl-Shift-E"),
exec: function(editor) {
config.loadModule("ace/ext/error_marker", function(module) {
module.showErrorMarker(editor, -1);
});
},
scrollIntoView: "center",
readOnly: true
}, {
name: "selectall",
bindKey: bindKey("Ctrl-A", "Command-A"),
@ -165,6 +185,7 @@ exports.commands = [{
exec: function(editor) { editor.getSelection().selectFileStart(); },
multiSelectAction: "forEach",
readOnly: true,
scrollIntoView: "animate",
aceCommandGroup: "fileJump"
}, {
name: "gotostart",
@ -172,6 +193,7 @@ exports.commands = [{
exec: function(editor) { editor.navigateFileStart(); },
multiSelectAction: "forEach",
readOnly: true,
scrollIntoView: "animate",
aceCommandGroup: "fileJump"
}, {
name: "selectup",
@ -191,6 +213,7 @@ exports.commands = [{
exec: function(editor) { editor.getSelection().selectFileEnd(); },
multiSelectAction: "forEach",
readOnly: true,
scrollIntoView: "animate",
aceCommandGroup: "fileJump"
}, {
name: "gotoend",
@ -198,90 +221,105 @@ exports.commands = [{
exec: function(editor) { editor.navigateFileEnd(); },
multiSelectAction: "forEach",
readOnly: true,
scrollIntoView: "animate",
aceCommandGroup: "fileJump"
}, {
name: "selectdown",
bindKey: bindKey("Shift-Down", "Shift-Down"),
exec: function(editor) { editor.getSelection().selectDown(); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "golinedown",
bindKey: bindKey("Down", "Down|Ctrl-N"),
exec: function(editor, args) { editor.navigateDown(args.times); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "selectwordleft",
bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"),
exec: function(editor) { editor.getSelection().selectWordLeft(); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "gotowordleft",
bindKey: bindKey("Ctrl-Left", "Option-Left"),
exec: function(editor) { editor.navigateWordLeft(); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "selecttolinestart",
bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left"),
exec: function(editor) { editor.getSelection().selectLineStart(); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "gotolinestart",
bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"),
exec: function(editor) { editor.navigateLineStart(); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "selectleft",
bindKey: bindKey("Shift-Left", "Shift-Left"),
exec: function(editor) { editor.getSelection().selectLeft(); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "gotoleft",
bindKey: bindKey("Left", "Left|Ctrl-B"),
exec: function(editor, args) { editor.navigateLeft(args.times); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "selectwordright",
bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"),
exec: function(editor) { editor.getSelection().selectWordRight(); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "gotowordright",
bindKey: bindKey("Ctrl-Right", "Option-Right"),
exec: function(editor) { editor.navigateWordRight(); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "selecttolineend",
bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right"),
exec: function(editor) { editor.getSelection().selectLineEnd(); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "gotolineend",
bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"),
exec: function(editor) { editor.navigateLineEnd(); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "selectright",
bindKey: bindKey("Shift-Right", "Shift-Right"),
exec: function(editor) { editor.getSelection().selectRight(); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "gotoright",
bindKey: bindKey("Right", "Right|Ctrl-F"),
exec: function(editor, args) { editor.navigateRight(args.times); },
multiSelectAction: "forEach",
scrollIntoView: "cursor",
readOnly: true
}, {
name: "selectpagedown",

212
lib/ace/ext/error_marker.js Normal file
View file

@ -0,0 +1,212 @@
/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2012, Ajax.org B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var LineWidgets = require("ace/line_widgets").LineWidgets;
var dom = require("ace/lib/dom");
var Range = require("ace/range").Range;
function binarySearch(array, needle, comparator) {
var first = 0;
var last = array.length - 1;
while (first <= last) {
var mid = (first + last) >> 1;
var c = comparator(needle, array[mid]);
if (c > 0)
first = mid + 1;
else if (c < 0)
last = mid - 1;
else
return mid;
}
// Return the nearest lesser index, "-1" means "0, "-2" means "1", etc.
return -(first + 1);
}
function findAnnotations(session, row, dir) {
var annotations = session.getAnnotations().sort(Range.comparePoints);
if (!annotations.length)
return;
var i = binarySearch(annotations, {row: row, column: -1}, Range.comparePoints);
if (i < 0)
i = -i - 1;
if (i >= annotations.length - 1)
i = dir > 0 ? 0 : annotations.length - 1;
else if (i === 0 && dir < 0)
i = annotations.length - 1;
var annotation = annotations[i];
if (!annotation || !dir)
return;
if (annotation.row === row) {
do {
annotation = annotations[i += dir];
} while (annotation && annotation.row === row);
if (!annotation)
return annotations.slice();
}
var matched = [];
row = annotation.row;
do {
matched[dir < 0 ? "unshift" : "push"](annotation);
annotation = annotations[i += dir];
} while (annotation && annotation.row == row);
return matched.length && matched;
}
exports.showErrorMarker = function(editor, dir) {
var session = editor.session;
if (!session.widgetManager) {
session.widgetManager = new LineWidgets(session);
session.widgetManager.attach(editor);
}
var pos = editor.getCursorPosition();
var row = pos.row;
var oldWidget = session.lineWidgets && session.lineWidgets[row];
if (oldWidget) {
oldWidget.destroy();
} else {
row -= dir;
}
var annotations = findAnnotations(session, row, dir);
var gutterAnno;
if (annotations) {
var annotation = annotations[0];
if (annotation.pos && annotation.column == null)
pos.column = annotation.pos.sc;
pos.row = annotation.row;
gutterAnno = editor.renderer.$gutterLayer.$annotations[pos.row];
} else if (oldWidget) {
return;
} else {
gutterAnno = {
text: ["Looks good!"],
className: "ace_ok"
};
}
editor.session.unfold(pos.row);
editor.selection.moveCursorToPosition(pos);
editor.selection.clearSelection();
var w = {
row: pos.row,
fixedWidth: true,
coverGutter: true,
el: dom.createElement("div")
};
var el = w.el.appendChild(dom.createElement("div"));
var arrow = w.el.appendChild(dom.createElement("div"));
arrow.className = "error_widget_arrow " + gutterAnno.className;
var left = editor.renderer.$cursorLayer
.getPixelPosition(pos).left;
arrow.style.left = left + editor.renderer.gutterWidth - 5 + "px";
w.el.className = "error_widget_wrapper";
el.className = "error_widget " + gutterAnno.className;
el.innerHTML = gutterAnno.text.join("<br>");
var kb = {
handleKeyboard:function(_,hashId, keyString) {
if (hashId === 0 && keyString === "esc") {
w.destroy();
return true;
}
}
};
w.destroy = function() {
if (editor.$mouseHandler.isMousePressed)
return;
editor.keyBinding.removeKeyboardHandler(kb);
session.widgetManager.removeLineWidget(w);
editor.off("changeSelection", w.destroy);
editor.off("changeSession", w.destroy);
editor.off("mouseup", w.destroy);
editor.off("change", w.destroy);
};
editor.keyBinding.addKeyboardHandler(kb);
editor.on("changeSelection", w.destroy);
editor.on("changeSession", w.destroy);
editor.on("mouseup", w.destroy);
editor.on("change", w.destroy);
editor.session.widgetManager.addLineWidget(w);
w.el.onmousedown = editor.focus.bind(editor);
};
dom.importCssString("\
.error_widget_wrapper {\
background: inherit;\
color: inherit;\
border:none\
}\
.error_widget {\
border-top: solid 2px;\
border-bottom: solid 2px;\
margin: 5px 0;\
padding: 10px 40px;\
white-space: pre-wrap;\
}\
.error_widget.ace_error, .error_widget_arrow.ace_error{\
border-color: #ff5a5a\
}\
.error_widget.ace_warning, .error_widget_arrow.ace_warning{\
border-color: #F1D817\
}\
.error_widget.ace_info, .error_widget_arrow.ace_info{\
border-color: #5a5a5a\
}\
.error_widget.ace_ok, .error_widget_arrow.ace_ok{\
border-color: #5aaa5a\
}\
.error_widget_arrow {\
position: absolute;\
border: solid 5px;\
border-top-color: transparent!important;\
border-right-color: transparent!important;\
border-left-color: transparent!important;\
top: -5px;\
}\
", "");
});

View file

@ -48,12 +48,13 @@ function LineWidgets(session) {
this.detach = this.detach.bind(this);
this.session.on("change", this.updateOnChange);
};
}
(function() {
this.getRowLength = function(row) {
var h;
if (this.lineWidgets)
var h = this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0;
h = this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0;
else
h = 0;
if (!this.$useWrapMode || !this.$wrapData[row]) {
@ -104,7 +105,8 @@ function LineWidgets(session) {
editor.renderer.off("beforeRender", this.measureWidgets);
editor.renderer.off("afterRender", this.renderWidgets);
this.session.lineWidgets.forEach(function(w) {
var lineWidgets = this.session.lineWidgets;
lineWidgets && lineWidgets.forEach(function(w) {
if (w && w.el && w.el.parentNode) {
w._inDocument = false;
w.el.parentNode.removeChild(w.el);
@ -113,8 +115,8 @@ function LineWidgets(session) {
};
this.updateOnChange = function(e) {
var cells = this.session.lineWidgets;
if (!cells) return;
var lineWidgets = this.session.lineWidgets;
if (!lineWidgets) return;
var delta = e.data;
var range = delta.range;
@ -124,24 +126,24 @@ function LineWidgets(session) {
if (len === 0) {
// return
} else if (delta.action == "removeText" || delta.action == "removeLines") {
var removed = cells.splice(startRow + 1, len);
var removed = lineWidgets.splice(startRow + 1, len);
removed.forEach(function(w) {
w && this.removeLineWidget(w);
}, this);
this.$updateRows();
} else {
var args = Array(len);
var args = new Array(len);
args.unshift(startRow, 0);
cells.splice.apply(cells, args);
lineWidgets.splice.apply(lineWidgets, args);
this.$updateRows();
}
};
this.$updateRows = function() {
var lw = this.session.lineWidgets;
if (!lw) return;
var lineWidgets = this.session.lineWidgets;
if (!lineWidgets) return;
var noWidgets = true;
lw.forEach(function(w, i) {
lineWidgets.forEach(function(w, i) {
if (w) {
noWidgets = false;
w.row = i;
@ -149,11 +151,11 @@ function LineWidgets(session) {
});
if (noWidgets)
this.session.lineWidgets = null;
}
};
this.addLineWidget = function(w) {
if (!this.session.lineWidgets)
this.session.lineWidgets = Array(this.session.getLength())
this.session.lineWidgets = new Array(this.session.getLength());
this.session.lineWidgets[w.row] = w;
@ -164,6 +166,8 @@ function LineWidgets(session) {
}
if (w.el) {
dom.addCssClass(w.el, "ace_lineWidgetContainer");
w.el.style.position = "absolute";
w.el.style.zIndex = 5;
renderer.container.appendChild(w.el);
w._inDocument = true;
}
@ -191,7 +195,8 @@ function LineWidgets(session) {
if (w.editor && w.editor.destroy) try {
w.editor.destroy();
} catch(e){}
this.session.lineWidgets[w.row] = undefined;
if (this.session.lineWidgets)
this.session.lineWidgets[w.row] = undefined;
this.session._emit("changeFold", {data:{start:{row: w.row}}});
this.$updateRows();
};
@ -202,13 +207,13 @@ function LineWidgets(session) {
};
this.measureWidgets = function(e, renderer) {
var ws = this.session._changedWidgets;
var changedWidgets = this.session._changedWidgets;
var config = renderer.layerConfig;
if (!ws || !ws.length) return;
if (!changedWidgets || !changedWidgets.length) return;
var min = Infinity;
for (var i = 0; i < ws.length; i++) {
var w = ws[i].lineWidget;
for (var i = 0; i < changedWidgets.length; i++) {
var w = changedWidgets[i];
if (!w._inDocument) {
w._inDocument = true;
renderer.container.appendChild(w.el);
@ -242,13 +247,13 @@ function LineWidgets(session) {
this.renderWidgets = function(e, renderer) {
var config = renderer.layerConfig;
var ws = this.session.lineWidgets;
if (!ws)
var lineWidgets = this.session.lineWidgets;
if (!lineWidgets)
return;
var first = Math.min(this.firstRow, config.firstRow);
var last = Math.max(this.lastRow, config.lastRow, ws.length);
var last = Math.max(this.lastRow, config.lastRow, lineWidgets.length);
while (first > 0 && !ws[first])
while (first > 0 && !lineWidgets[first])
first--;
this.firstRow = config.firstRow;
@ -256,7 +261,7 @@ function LineWidgets(session) {
renderer.$cursorLayer.config = config;
for (var i = first; i <= last; i++) {
var w = ws[i];
var w = lineWidgets[i];
if (!w || !w.el) continue;
if (!w._inDocument) {