diff --git a/plugins/node_modules/ace/lib/ace/ace.js b/plugins/node_modules/ace/lib/ace/ace.js index 93af50a1..6cc536c3 100644 --- a/plugins/node_modules/ace/lib/ace/ace.js +++ b/plugins/node_modules/ace/lib/ace/ace.js @@ -42,6 +42,7 @@ require("./lib/fixoldbrowsers"); var dom = require("./lib/dom"); var event = require("./lib/event"); +var Range = require("./range").Range; var Editor = require("./editor").Editor; var EditSession = require("./edit_session").EditSession; var UndoManager = require("./undomanager").UndoManager; @@ -92,7 +93,7 @@ exports.edit = function(el, options) { el = dom.createElement("pre"); oldNode.parentNode.replaceChild(el, oldNode); } else if (el) { - value = dom.getInnerText(el); + value = el.textContent; el.innerHTML = ""; } @@ -126,7 +127,9 @@ exports.createEditSession = function(text, mode) { doc.setUndoManager(new UndoManager()); return doc; }; +exports.Range = Range; exports.EditSession = EditSession; exports.UndoManager = UndoManager; -exports.version = "1.2.9"; +exports.VirtualRenderer = Renderer; +exports.version = "1.3.1"; }); diff --git a/plugins/node_modules/ace/lib/ace/autocomplete.js b/plugins/node_modules/ace/lib/ace/autocomplete.js index 8b362c23..3b99f03c 100644 --- a/plugins/node_modules/ace/lib/ace/autocomplete.js +++ b/plugins/node_modules/ace/lib/ace/autocomplete.js @@ -381,14 +381,28 @@ var Autocomplete = function() { tooltipNode.style.top = popup.container.style.top; tooltipNode.style.bottom = popup.container.style.bottom; + tooltipNode.style.display = "block"; if (window.innerWidth - rect.right < 320) { - tooltipNode.style.right = window.innerWidth - rect.left + "px"; - tooltipNode.style.left = ""; + if (rect.left < 320) { + if(popup.isTopdown) { + tooltipNode.style.top = rect.bottom + "px"; + tooltipNode.style.left = rect.left + "px"; + tooltipNode.style.right = ""; + tooltipNode.style.bottom = ""; + } else { + tooltipNode.style.top = popup.container.offsetTop - tooltipNode.offsetHeight + "px"; + tooltipNode.style.left = rect.left + "px"; + tooltipNode.style.right = ""; + tooltipNode.style.bottom = ""; + } + } else { + tooltipNode.style.right = window.innerWidth - rect.left + "px"; + tooltipNode.style.left = ""; + } } else { tooltipNode.style.left = (rect.right + 1) + "px"; tooltipNode.style.right = ""; } - tooltipNode.style.display = "block"; }; this.hideDocTooltip = function() { @@ -475,24 +489,35 @@ var FilteredList = function(array, filterText) { if (this.exactMatch) { if (needle !== caption.substr(0, needle.length)) continue loop; - }else{ - // caption char iteration is faster in Chrome but slower in Firefox, so lets use indexOf - for (var j = 0; j < needle.length; j++) { - // TODO add penalty on case mismatch - var i1 = caption.indexOf(lower[j], lastIndex + 1); - var i2 = caption.indexOf(upper[j], lastIndex + 1); - index = (i1 >= 0) ? ((i2 < 0 || i1 < i2) ? i1 : i2) : i2; - if (index < 0) - continue loop; - distance = index - lastIndex - 1; - if (distance > 0) { - // first char mismatch should be more sensitive - if (lastIndex === -1) - penalty += 10; - penalty += distance; + } else { + /** + * It is for situation then, for example, we find some like 'tab' in item.value="Check the table" + * and want to see "Check the TABle" but see "Check The tABle". + */ + var a; + if ((a = caption.toLowerCase().indexOf(lower)) > -1) { + for (var k = a; k < a + lower.length; k++) { + matchMask = matchMask | (1 << k); + } + } else { + // caption char iteration is faster in Chrome but slower in Firefox, so lets use indexOf + for (var j = 0; j < needle.length; j++) { + // TODO add penalty on case mismatch + var i1 = caption.indexOf(lower[j], lastIndex + 1); + var i2 = caption.indexOf(upper[j], lastIndex + 1); + index = (i1 >= 0) ? ((i2 < 0 || i1 < i2) ? i1 : i2) : i2; + if (index < 0) + continue loop; + distance = index - lastIndex - 1; + if (distance > 0) { + // first char mismatch should be more sensitive + if (lastIndex === -1) + penalty += 10; + penalty += distance; + } + matchMask = matchMask | (1 << index); + lastIndex = index; } - matchMask = matchMask | (1 << index); - lastIndex = index; } } item.matchMask = matchMask; diff --git a/plugins/node_modules/ace/lib/ace/commands/default_commands.js b/plugins/node_modules/ace/lib/ace/commands/default_commands.js index f7c6d5f5..527bebe8 100644 --- a/plugins/node_modules/ace/lib/ace/commands/default_commands.js +++ b/plugins/node_modules/ace/lib/ace/commands/default_commands.js @@ -57,7 +57,7 @@ exports.commands = [{ name: "goToNextError", bindKey: bindKey("Alt-E", "F4"), exec: function(editor) { - config.loadModule("ace/ext/error_marker", function(module) { + config.loadModule("./ext/error_marker", function(module) { module.showErrorMarker(editor, 1); }); }, @@ -67,7 +67,7 @@ exports.commands = [{ name: "goToPreviousError", bindKey: bindKey("Alt-Shift-E", "Shift-F4"), exec: function(editor) { - config.loadModule("ace/ext/error_marker", function(module) { + config.loadModule("./ext/error_marker", function(module) { module.showErrorMarker(editor, -1); }); }, diff --git a/plugins/node_modules/ace/lib/ace/document.js b/plugins/node_modules/ace/lib/ace/document.js index 245f66ba..17f94427 100644 --- a/plugins/node_modules/ace/lib/ace/document.js +++ b/plugins/node_modules/ace/lib/ace/document.js @@ -575,12 +575,13 @@ var Document = function(textOrLines) { return; } - if (isInsert && delta.lines.length > 20000) + if (isInsert && delta.lines.length > 20000) { this.$splitAndapplyLargeDelta(delta, 20000); - - // Apply. - applyDelta(this.$lines, delta, doNotValidate); - this._signal("change", delta); + } + else { + applyDelta(this.$lines, delta, doNotValidate); + this._signal("change", delta); + } }; this.$splitAndapplyLargeDelta = function(delta, MAX) { @@ -594,21 +595,12 @@ var Document = function(textOrLines) { // as shown in https://gist.github.com/aldendaniels/8367109#file-document-snippet-js // If we do this, update validateDelta() to limit the number of lines in a delete delta. var lines = delta.lines; - var l = lines.length; + var l = lines.length - MAX + 1; var row = delta.start.row; var column = delta.start.column; - var from = 0, to = 0; - do { - from = to; + for (var from = 0, to = 0; from < l; from = to) { to += MAX - 1; var chunk = lines.slice(from, to); - if (to > l) { - // Update remaining delta. - delta.lines = chunk; - delta.start.row = row + from; - delta.start.column = column; - break; - } chunk.push(""); this.applyDelta({ start: this.pos(row + from, column), @@ -616,7 +608,12 @@ var Document = function(textOrLines) { action: delta.action, lines: chunk }, true); - } while(true); + } + // Update remaining delta. + delta.lines = lines.slice(from); + delta.start.row = row + from; + delta.start.column = column; + this.applyDelta(delta, true); }; /** @@ -656,7 +653,7 @@ var Document = function(textOrLines) { if (index < 0) return {row: i, column: index + lines[i].length + newlineLength}; } - return {row: l-1, column: lines[l-1].length}; + return {row: l-1, column: index + lines[l-1].length + newlineLength}; }; /** diff --git a/plugins/node_modules/ace/lib/ace/document_test.js b/plugins/node_modules/ace/lib/ace/document_test.js index 30048470..bcb6e877 100644 --- a/plugins/node_modules/ace/lib/ace/document_test.js +++ b/plugins/node_modules/ace/lib/ace/document_test.js @@ -30,7 +30,6 @@ if (typeof process !== "undefined") { require("amd-loader"); - require("./test/mockdom"); } define(function(require, exports, module) { @@ -102,6 +101,31 @@ module.exports = { doc.insertFullLines(2, ["aa", "bb"]); assert.equal(doc.getValue(), ["12", "34", "aa", "bb"].join("\n")); }, + + "test: insertInLine" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.insertInLine({row: 0, column: 1}, "a"); + assert.equal(doc.getValue(), ["1a2", "34"].join("\n")); + doc.insertInLine({row: 10, column: Infinity}, "b"); + assert.equal(doc.getValue(), ["1a2", "34b"].join("\n")); + doc.insertInLine({row: undefined, column: Infinity}, "x"); + assert.equal(doc.getValue(), ["1a2", "34b", "x"].join("\n")); + doc.insertInLine({row: -1, column: Infinity}, "z"); + assert.equal(doc.getValue(), ["1a2z", "34b", "x"].join("\n")); + + doc.removeInLine(0, 1, 2); + assert.equal(doc.getValue(), ["12z", "34b", "x"].join("\n")); + doc.removeInLine(0, 2, 10); + assert.equal(doc.getValue(), ["12", "34b", "x"].join("\n")); + doc.removeNewLine(1); + assert.equal(doc.getValue(), ["12", "34bx"].join("\n")); + doc.removeNewLine(1); + assert.equal(doc.getValue(), ["12", "34bx"].join("\n")); + }, "test: insert lines in the middle" : function() { var doc = new Document(["12", "34"]); @@ -249,6 +273,11 @@ module.exports = { doc.setNewLineMode("unix"); assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + assert.equal(doc.getNewLineMode(), "unix"); + assert.ok(doc.isNewLine("\r")); + assert.ok(doc.isNewLine("\n")); + assert.ok(doc.isNewLine("\r\n")); + assert.notOk(doc.isNewLine("\n\r")); }, "test: set new line mode to 'windows' should use '\\r\\n' as new lines": function() { @@ -311,20 +340,48 @@ module.exports = { "test: inserting huge delta": function() { var doc = new Document(""); var val = ""; - var MAX = 0xF000; - for (var i = 0; i < 10 * MAX; i++) { + var MAX = 20000 - 1; + for (var i = 0; i < 4 * MAX; i++) { val += i + "\n"; } + var changeCount = 0; + function testDelta(delta) { + changeCount++; + assert.equal(delta.lines.length, MAX + 1); + } + doc.on("change", testDelta); doc.setValue(val); + doc.off("change", testDelta); + assert.equal(changeCount, 4); assert.equal(doc.getValue(), val); - for (var i = 3 * MAX + 2; i >= 3 * MAX - 2; i--) { + for (var i = 2 * MAX + 20; i >= 2 * MAX - 20; i--) { val = doc.getLines(0, i).join("\n"); doc.setValue("\nab"); assert.equal(doc.getValue(), "\nab"); doc.insert({row: 1, column: 1}, val); assert.equal(doc.getValue(), "\na" + val + "b"); } + }, + + "test: indexToPosition": function() { + function test(value) { + var doc = new Document(value); + var secondLine = value.indexOf("|"); + for (var i = -2; i < value.length + 4; i++) { + if (value[i - 1] == "\r") continue; + var pos = doc.indexToPosition(i); + var text = doc.getTextRange({start: {row: 0, column: 0}, end: pos}); + assert.equal(text, value.substring(0, i)); + assert.equal(doc.positionToIndex(pos), i); + if (i >= secondLine) { + assert.deepEqual(doc.indexToPosition(i - secondLine, 1), pos); + assert.equal(doc.positionToIndex(pos, 1), i - secondLine); + } + } + } + test("abc\n|defx\ngh"); + test("abc\r\n|defx\r\ngh"); } }; diff --git a/plugins/node_modules/ace/lib/ace/edit_session.js b/plugins/node_modules/ace/lib/ace/edit_session.js index fdd75858..e09b7e9c 100644 --- a/plugins/node_modules/ace/lib/ace/edit_session.js +++ b/plugins/node_modules/ace/lib/ace/edit_session.js @@ -2540,6 +2540,10 @@ config.defineOptions(EditSession.prototype, "session", { handlesSet: true }, navigateWithinSoftTabs: {initialValue: false}, + foldStyle: { + set: function(val) {this.setFoldStyle(val);}, + handlesSet: true + }, overwrite: { set: function(val) {this._signal("changeOverwrite");}, initialValue: false diff --git a/plugins/node_modules/ace/lib/ace/editor.js b/plugins/node_modules/ace/lib/ace/editor.js index 1ec567f0..9dfc7513 100644 --- a/plugins/node_modules/ace/lib/ace/editor.js +++ b/plugins/node_modules/ace/lib/ace/editor.js @@ -252,7 +252,7 @@ Editor.$uid = 0; * **/ this.setKeyboardHandler = function(keyboardHandler, cb) { - if (keyboardHandler && typeof keyboardHandler === "string") { + if (keyboardHandler && typeof keyboardHandler === "string" && keyboardHandler != "ace") { this.$keybindingId = keyboardHandler; var _self = this; config.loadModule(["keybinding", keyboardHandler], function(module) { @@ -504,7 +504,7 @@ Editor.$uid = 0; */ this.getFontSize = function () { return this.getOption("fontSize") || - dom.computedStyle(this.container, "fontSize"); + dom.computedStyle(this.container).fontSize; }; /** @@ -640,12 +640,13 @@ Editor.$uid = 0; * Brings the current `textInput` into focus. **/ this.focus = function() { - // Safari needs the timeout - // iOS and Firefox need it called immediately - // to be on the save side we do both + // focusing after timeout is not needed now, but some code using ace + // depends on being able to call focus when textarea is not visible, + // so to keep backwards compatibility we keep this until the next major release var _self = this; setTimeout(function() { - _self.textInput.focus(); + if (!_self.isFocused()) + _self.textInput.focus(); }); this.textInput.focus(); }; @@ -753,8 +754,10 @@ Editor.$uid = 0; var highlight; if (this.$highlightActiveLine) { - if ((this.$selectionStyle != "line" || !this.selection.isMultiLine())) + if (this.$selectionStyle != "line" || !this.selection.isMultiLine()) highlight = this.getCursorPosition(); + if (this.renderer.theme && this.renderer.theme.$selectionColorConflict && !this.selection.isEmpty()) + highlight = false; if (this.renderer.$maxLines && this.session.getLength() === 1 && !(this.renderer.$minLines > 1)) highlight = false; } @@ -2648,8 +2651,7 @@ config.defineOptions(Editor.prototype, "editor", { }, readOnly: { set: function(readOnly) { - // disabled to not break vim mode! - // this.textInput.setReadOnly(readOnly); + this.textInput.setReadOnly(readOnly); this.$resetCursorStyle(); }, initialValue: false @@ -2712,11 +2714,12 @@ config.defineOptions(Editor.prototype, "editor", { scrollPastEnd: "renderer", fixedWidthGutter: "renderer", theme: "renderer", + hasCssTransforms: "renderer", scrollSpeed: "$mouseHandler", dragDelay: "$mouseHandler", dragEnabled: "$mouseHandler", - focusTimout: "$mouseHandler", + focusTimeout: "$mouseHandler", tooltipFollowsMouse: "$mouseHandler", firstLineNumber: "session", @@ -2724,6 +2727,7 @@ config.defineOptions(Editor.prototype, "editor", { newLineMode: "session", useWorker: "session", useSoftTabs: "session", + navigateWithinSoftTabs: "session", tabSize: "session", wrap: "session", indentedSoftWrap: "session", diff --git a/plugins/node_modules/ace/lib/ace/editor_commands_test.js b/plugins/node_modules/ace/lib/ace/editor_commands_test.js new file mode 100644 index 00000000..7819d999 --- /dev/null +++ b/plugins/node_modules/ace/lib/ace/editor_commands_test.js @@ -0,0 +1,542 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, 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 ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var ace = require("./ace"); +var EditSession = require("./edit_session").EditSession; +var Editor = require("./editor").Editor; +var MockRenderer = require("./test/mockrenderer").MockRenderer; +var JavaScriptMode = require("./mode/javascript").Mode; +var HTMLMode = require("./mode/html").Mode; +var assert = require("./test/assertions"); +var editor; + +var exec = function(name, times, args) { + do { + editor.commands.exec(name, editor, args); + } while(times --> 1); +}; + + +module.exports = { + + "test modifyNumber": function() { + editor = new Editor(new MockRenderer()); + editor.setValue("999"); + editor.execCommand(editor.commands.byName.modifyNumberUp); + assert.equal(editor.getValue(), "1000"); + + editor.setValue("999f"); + editor.execCommand(editor.commands.byName.modifyNumberUp); + assert.equal(editor.getValue(), "999f"); + + editor.setValue("1000"); + editor.execCommand(editor.commands.byName.modifyNumberDown); + assert.equal(editor.getValue(), "999"); + + editor.setValue("1000.1"); + editor.execCommand(editor.commands.byName.modifyNumberDown); + assert.equal(editor.getValue(), "1000.0"); + + editor.setValue("123.3", 1); + exec("gotoleft", 2); + editor.execCommand(editor.commands.byName.modifyNumberDown); + assert.equal(editor.getValue(), "122.3"); + }, + "test duplicateSelection": function() { + editor = new Editor(new MockRenderer()); + + editor.setValue("123.3", 1); + exec("selectleft", 2); + editor.execCommand(editor.commands.byName.duplicateSelection); + assert.equal(editor.getValue(), "123.3.3"); + + editor.setValue("124.3", 1); + exec("gotoleft", 3); + exec("selectright", 2); + editor.execCommand(editor.commands.byName.duplicateSelection); + assert.equal(editor.getValue(), "124.4.3"); + editor.clearSelection(); + editor.execCommand(editor.commands.byName.duplicateSelection); + assert.equal(editor.getValue(), "124.4.3\n124.4.3"); + }, + "test editor find": function() { + editor = new Editor(new MockRenderer()); + + editor.setValue("for for foo", 1); + exec("gotoleft", 8); + exec("selectleft", 3); + editor.execCommand(editor.commands.byName.findnext); + assert.range(editor.selection.getRange(), 0, 4, 0, 7); + + editor.setValue("for for for foo", 1); + exec("gotoleft", 8); + exec("selectleft", 3); + editor.execCommand(editor.commands.byName.findprevious); + assert.range(editor.selection.getRange(), 0, 0, 0, 3); + + editor.setValue("foo for foo foo", 1); + exec("gotoleft", 8); + editor.execCommand(editor.commands.byName.selectOrFindNext); + assert.range(editor.selection.getRange(), 0, 4, 0, 7); + + editor.setValue("foo for foo foo", 1); + exec("gotoleft", 7); + exec("selectright", 3); + editor.execCommand(editor.commands.byName.selectOrFindNext); + assert.range(editor.selection.getRange(), 0, 12, 0, 15); + + editor.setValue("foo for foo foo", 1); + exec("gotoleft", 8); + editor.execCommand(editor.commands.byName.selectOrFindPrevious); + assert.range(editor.selection.getRange(), 0, 4, 0, 7); + + editor.setValue("foo for foo foo", 1); + exec("gotoleft", 7); + exec("selectright", 3); + editor.execCommand(editor.commands.byName.selectOrFindPrevious); + assert.range(editor.selection.getRange(), 0, 0, 0, 3); + }, + "test overwrite": function() { + editor = new Editor(new MockRenderer()); + + editor.setValue("foo for foo foo", 1); + exec("gotoleft", 7); + editor.execCommand(editor.commands.byName.overwrite); + exec("insertstring", 1, "b"); + assert.equal(editor.getValue(),"foo for boo foo"); + }, + "test selections": function() { + editor = new Editor(new MockRenderer(5)); + + editor.setValue("foo for foo foo\nfoo for foo foo", 1); + exec("gotoleft", 7); + editor.execCommand(editor.commands.byName.selecttostart); + assert.range(editor.selection.getRange(), 0, 0, 1, 8); + + editor.setValue("foo for foo foo\nfsdfsd232", 1); + exec("gotoleft", 3); + editor.execCommand(editor.commands.byName.selectup); + assert.range(editor.selection.getRange(), 0, 6, 1, 6); + + editor.setValue("foo for foo foo\nfsdfsd232", 1); + exec("gotoleft", 9); + editor.execCommand(editor.commands.byName.selecttoend); + assert.range(editor.selection.getRange(), 1, 0, 1, 9); + + editor.setValue("foo for foo foo\nfsdfsd232", 1); + exec("gotostart", 1); + exec("gotoright", 3); + editor.execCommand(editor.commands.byName.selectdown); + assert.range(editor.selection.getRange(), 0, 3, 1, 3); + + editor.setValue("foo for foo foo\nfsdfsd232", 1); + exec("gotoleft", 4); + editor.execCommand(editor.commands.byName.selecttolinestart); + assert.range(editor.selection.getRange(), 1, 0, 1, 5); + + editor.setValue("foo for foo foo", 1); + exec("gotoleft", 7); + editor.execCommand(editor.commands.byName.selectwordright); + assert.range(editor.selection.getRange(), 0, 8, 0, 11); + + editor.setValue("foo for foo foo", 1); + exec("gotostart", 1); + exec("gotoright", 2); + exec("selectright", 2); + editor.execCommand(editor.commands.byName.selecttolineend); + assert.range(editor.selection.getRange(), 0, 2, 0, 15); + + // dublicate command + editor.setValue("foo for foo foo", 1); + exec("gotostart", 1); + exec("gotoright", 2); + exec("selectright", 2); + editor.execCommand(editor.commands.byName.selectlineend); + assert.range(editor.selection.getRange(), 0, 2, 0, 15); + + editor.setValue("foo for foo foo", 1); + exec("gotoleft", 2); + editor.execCommand(editor.commands.byName.selectlinestart); + assert.range(editor.selection.getRange(), 0, 0, 0, 13); + + editor.setValue("foo for foo foo", 1); + exec("gotostart", 1); + exec("gotoright", 3); + exec("selectright", 3); + editor.execCommand(editor.commands.byName.invertSelection); + assert.range(editor.selection.getAllRanges()[0], 0, 0, 0, 3); + assert.range(editor.selection.getAllRanges()[1], 0, 6, 0, 15); + + editor.setValue("foo for foo foo", 1); + exec("gotostart", 1); + exec("selectright", 3); + editor.execCommand(editor.commands.byName.invertSelection); + assert.range(editor.selection.getRange(), 0, 3, 0, 15); + + editor.setValue("foo for foo foo", 1); + exec("gotostart", 1); + editor.execCommand(editor.commands.byName.invertSelection); + assert.range(editor.selection.getRange(), 0, 0, 0, 15); + + editor.setValue("foo for foo foo"); + editor.execCommand(editor.commands.byName.invertSelection); + assert.range(editor.selection.getRange(), 0, 15, 0, 15); + + // ToDO: plenty of matching tests + editor.session.setMode(new HTMLMode); + editor.setValue("
abcd", 1); + exec("gotostart", 1); + exec("gotoright", 3); + editor.execCommand(editor.commands.byName.selecttomatching); + assert.range(editor.selection.getRange(), 0, 3, 0, 24); + + editor.setValue("