From 2e6f12725bc01011c545c99c1f1c1da6065063d9 Mon Sep 17 00:00:00 2001 From: aldendaniels Date: Wed, 1 Jan 2014 00:41:45 -0600 Subject: [PATCH] #1744: Refactor document delta handling Refactor delta handling code to: - Combine the "insertText" and "insertLines" delta types into a single "insert" delta type - Combine the "removeText" and "removeLines" delta types into a single "remove" delta type - Make all document mutations in a single applyDelta function. - Add basic delta validation (more needed . . . see TODOs) - Rework anchor logic to handle new delta types (also simplified) - Rename "insert()" to "insertText()" and "remove()" to "removeText()" - Rename "insertLines()" to "insertFullLines()" and "removeLines()" to "removeFullLines()" See related issue for more information. All tests are passing and the changes appear functional under preliminary testing, but careful review and testing will be necessary. --- lib/ace/anchor.js | 108 +++--- lib/ace/anchor_test.js | 16 +- lib/ace/autocomplete.js | 2 +- lib/ace/background_tokenizer.js | 2 +- lib/ace/background_tokenizer_test.js | 2 +- lib/ace/commands/default_commands.js | 4 +- lib/ace/document.js | 516 +++++++++++++------------ lib/ace/document_test.js | 18 +- lib/ace/edit_session.js | 58 ++- lib/ace/edit_session/folding.js | 2 +- lib/ace/edit_session_test.js | 18 +- lib/ace/editor.js | 39 +- lib/ace/editor_change_document_test.js | 2 +- lib/ace/editor_navigation_test.js | 2 +- lib/ace/ext/chromevox.js | 4 +- lib/ace/ext/elastic_tabstops_lite.js | 2 +- lib/ace/ext/whitespace.js | 2 +- lib/ace/keyboard/vim/commands.js | 10 +- lib/ace/keyboard/vim/maps/motions.js | 6 +- lib/ace/layer/gutter.js | 4 +- lib/ace/line_widgets.js | 2 +- lib/ace/mode/javascript_test.js | 2 +- lib/ace/mode/text.js | 12 +- lib/ace/mouse/dragdrop_handler.js | 2 +- lib/ace/multi_select.js | 10 +- lib/ace/occur_test.js | 12 +- lib/ace/placeholder.js | 12 +- lib/ace/placeholder_test.js | 18 +- 28 files changed, 437 insertions(+), 450 deletions(-) diff --git a/lib/ace/anchor.js b/lib/ace/anchor.js index 3a62e632..91a62eb0 100644 --- a/lib/ace/anchor.js +++ b/lib/ace/anchor.js @@ -100,67 +100,55 @@ var Anchor = exports.Anchor = function(doc, row, column) { * **/ this.onChange = function(e) { - var delta = e.data; - var range = delta.range; - - if (range.start.row == range.end.row && range.start.row != this.row) - return; - - if (range.start.row > this.row) - return; - - if (range.start.row == this.row && range.start.column > this.column) - return; - - var row = this.row; - var column = this.column; - var start = range.start; - var end = range.end; - - if (delta.action === "insertText") { - if (start.row === row && start.column <= column) { - if (start.column === column && this.$insertRight) { - // do nothing - } else if (start.row === end.row) { - column += end.column - start.column; - } else { - column -= start.column; - row += end.row - start.row; - } - } else if (start.row !== end.row && start.row < row) { - row += end.row - start.row; - } - } else if (delta.action === "insertLines") { - if (start.row <= row) { - row += end.row - start.row; - } - } else if (delta.action === "removeText") { - if (start.row === row && start.column < column) { - if (end.column >= column) - column = start.column; - else - column = Math.max(0, column - (end.column - start.column)); - - } else if (start.row !== end.row && start.row < row) { - if (end.row === row) - column = Math.max(0, column - end.column) + start.column; - row -= (end.row - start.row); - } else if (end.row === row) { - row -= end.row - start.row; - column = Math.max(0, column - end.column) + start.column; - } - } else if (delta.action == "removeLines") { - if (start.row <= row) { - if (end.row <= row) - row -= end.row - start.row; - else { - row = start.row; - column = 0; - } - } + + function _pointsInOrder(point1, point2, equalPointsInOrder) + { + var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column; + return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter); } - - this.setPosition(row, column, true); + + function getTransformedPoint(delta, point, moveIfEqual) + { + // Get delta info. + var deltaIsInsert = (delta.action == 'insert') + var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.range.end.row - delta.range.start.row); + var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.range.end.column - delta.range.start.column); + var deltaStart = delta.range.start; + var deltaEnd = (deltaIsInsert ? deltaStart : delta.range.end); // Collapse insert range. + + // DELTA AFTER POINT: No change needed. + if (_pointsInOrder(point, deltaStart, moveIfEqual)) + { + return ( + { + row: point.row, + column: point.column + }); + } + + // DELTA BEFORE POINT: Move point by delta shift. + if (_pointsInOrder(deltaEnd, point, !moveIfEqual)) + { + return ( + { + row: point.row + deltaRowShift, + column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0) + }); + } + + // DELTA ENVELOPS POINT (delete only): Move point to delta start. + if (delta.action != 'delete') + throw 'Delete action expected.'; + return ( + { + row: deltaStart.row, + column: deltaStart.column + }); + } + + var delta = e.data; + var point = getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight); + this.setPosition(point.row, point.column, true); }; /** diff --git a/lib/ace/anchor_test.js b/lib/ace/anchor_test.js index 2d7fcb63..0588c9b6 100644 --- a/lib/ace/anchor_test.js +++ b/lib/ace/anchor_test.js @@ -54,7 +54,7 @@ module.exports = { var doc = new Document("juhu\nkinners"); var anchor = new Anchor(doc, 1, 4); - doc.insert({row: 1, column: 1}, "123"); + doc.insertText({row: 1, column: 1}, "123"); assert.position(anchor.getPosition(), 1, 7); }, @@ -62,7 +62,7 @@ module.exports = { var doc = new Document("juhu\nkinners"); var anchor = new Anchor(doc, 1, 4); - doc.insertLines(1, ["123", "456"]); + doc.insertFullLines(1, ["123", "456"]); assert.position(anchor.getPosition(), 3, 4); }, @@ -70,7 +70,7 @@ module.exports = { var doc = new Document("juhu\nkinners"); var anchor = new Anchor(doc, 1, 4); - doc.insertNewLine({row: 0, column: 0}); + doc.insertLines({row: 0, column: 0}, ['', '']); assert.position(anchor.getPosition(), 2, 4); }, @@ -78,7 +78,7 @@ module.exports = { var doc = new Document("juhu\nkinners"); var anchor = new Anchor(doc, 1, 4); - doc.insertNewLine({row: 1, column: 2}); + doc.insertLines({row: 1, column: 2}, ['', '']); assert.position(anchor.getPosition(), 2, 2); }, @@ -110,7 +110,7 @@ module.exports = { var doc = new Document("juhu\n1\n2\nkinners"); var anchor = new Anchor(doc, 3, 4); - doc.removeLines(1, 2); + doc.removeFullLines(1, 2); assert.position(anchor.getPosition(), 1, 4); }, @@ -134,7 +134,7 @@ module.exports = { var doc = new Document("juhu\nkinners\n123"); var anchor = new Anchor(doc, 1, 5); - doc.removeLines(1, 1); + doc.removeFullLines(1, 1); assert.position(anchor.getPosition(), 1, 0); }, @@ -173,9 +173,9 @@ module.exports = { var doc = new Document("juhu\nkinners\n123"); var anchor = new Anchor(doc, 2, 4); - doc.removeLines(0, 3); + doc.removeFullLines(0, 3); assert.position(anchor.getPosition(), 0, 0); - doc.insertLines(0, ["a", "b", "c"]); + doc.insertFullLines(0, ["a", "b", "c"]); assert.position(anchor.getPosition(), 3, 0); assert.equal(doc.getValue(), "a\nb\nc\n"); } diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index 50154c01..2344aede 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -170,7 +170,7 @@ var Autocomplete = function() { "Ctrl-Down|Ctrl-End": function(editor) { editor.completer.goTo("end"); }, "Esc": function(editor) { editor.completer.detach(); }, - "Space": function(editor) { editor.completer.detach(); editor.insert(" ");}, + "Space": function(editor) { editor.completer.detach(); editor.insertText(" ");}, "Return": function(editor) { editor.completer.insertMatch(); }, "Shift-Return": function(editor) { editor.completer.insertMatch(true); }, "Tab": function(editor) { editor.completer.insertMatch(); }, diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index 217be1b3..cb3ffe23 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -183,7 +183,7 @@ var BackgroundTokenizer = function(tokenizer, editor) { if (len === 0) { this.lines[startRow] = null; - } else if (delta.action == "removeText" || delta.action == "removeLines") { + } else if (delta.action == "delete") { this.lines.splice(startRow, len + 1, null); this.states.splice(startRow, len + 1, null); } else { diff --git a/lib/ace/background_tokenizer_test.js b/lib/ace/background_tokenizer_test.js index 7a4cc78c..16c63132 100644 --- a/lib/ace/background_tokenizer_test.js +++ b/lib/ace/background_tokenizer_test.js @@ -70,7 +70,7 @@ module.exports = { forceTokenize(doc) testStates(doc, ["comment_regex_allowed", "comment_regex_allowed"]) - doc.insert({row:0, column:2}, "\n*/") + doc.insertText({row:0, column:2}, "\n*/") testStates(doc, [undefined, undefined, "comment_regex_allowed"]) forceTokenize(doc) diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index e4a8212e..0fd9686c 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -508,13 +508,13 @@ exports.commands = [{ scrollIntoView: "selectionPart" }, { name: "insertstring", - exec: function(editor, str) { editor.insert(str); }, + exec: function(editor, str) { editor.insertText(str); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "inserttext", exec: function(editor, args) { - editor.insert(lang.stringRepeat(args.text || "", args.times || 1)); + editor.insertText(lang.stringRepeat(args.text || "", args.times || 1)); }, multiSelectAction: "forEach" }, { diff --git a/lib/ace/document.js b/lib/ace/document.js index 75a7920d..ace69e32 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -51,17 +51,17 @@ var Anchor = require("./anchor").Anchor; * @constructor **/ -var Document = function(text) { - this.$lines = []; +var Document = function(textOrLines) { + this.$lines = ['']; // There has to be one line at least in the document. If you pass an empty // string to the insert function, nothing will happen. Workaround. - if (text.length == 0) { + if (textOrLines.length == 0) { this.$lines = [""]; - } else if (Array.isArray(text)) { - this._insertLines(0, text); + } else if (Array.isArray(textOrLines)) { + this.insertLines({row: 0, column: 0}, textOrLines); } else { - this.insert({row: 0, column:0}, text); + this.insertText({row: 0, column:0}, textOrLines); } }; @@ -77,7 +77,7 @@ var Document = function(text) { this.setValue = function(text) { var len = this.getLength(); this.remove(new Range(0, 0, len, this.getLine(len-1).length)); - this.insert({row: 0, column:0}, text); + this.insertText({row: 0, column:0}, text); }; /** @@ -211,27 +211,85 @@ var Document = function(text) { * @returns {String} **/ this.getTextRange = function(range) { + return this._getLinesForRange(range).join(this.getNewLineCharacter()); + }; + + this._getLinesForRange = function(range) { if (range.start.row == range.end.row) { - return this.getLine(range.start.row) - .substring(range.start.column, range.end.column); + return [this.getLine(range.start.row) + .substring(range.start.column, range.end.column)]; } var lines = this.getLines(range.start.row, range.end.row); lines[0] = (lines[0] || "").substring(range.start.column); var l = lines.length - 1; if (range.end.row - range.start.row == l) lines[l] = lines[l].substring(0, range.end.column); - return lines.join(this.getNewLineCharacter()); + return lines; }; this.$clipPosition = function(position) { + var length = this.getLength(); - if (position.row >= length) { + if (position.row >= length) + { position.row = Math.max(0, length - 1); - position.column = this.getLine(length-1).length; - } else if (position.row < 0) - position.row = 0; + position.column = this.getLine(length - 1).length; + } + else + { + position.row = Math.max(0, position.row); + position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length); + } return position; }; + + this.$getClippedRange = function(range) + { + // Get Range object. + if (!range instanceof Range) + range = Range.fromPoints(range.start, range.end); + + // Return clipped range. + this.$clipPosition(range.start); + this.$clipPosition(range.end); + return range; + } + + this.$validateDelta = function(delta) + { + function fnThrow(errorText) + { + errorText = 'Invalid Delta: ' + errorText; + console.log(errorText, delta); + throw errorText; + } + + if (!delta.lines instanceof Array) + { + fnThrow('Delta object lines must be an array'); + } + + if (!delta.range instanceof Range) + { + fnThrow('Range object is not an instance of the Range class'); + } + + var start = delta.range.start; + if (Math.min(Math.max(start.row, 0), this.getLength() - 1 ) != start.row || + Math.min(Math.max(start.column, 0), this.$lines[start.row].length) != start.column) + { + fnThrow('Range start point not contained in document'); + } + + if (delta.lines.length - 1 != delta.range.end.row - delta.range.start.row) + { + fnThrow('Range row offsets does not match delta lines'); + } + + // TODO: Validate that the ending column offset matches the lines. + // TODO: Validate for deletions that the lines deleted match the lines + // in the document. + }, /** * Inserts a block of `text` at the indicated `position`. @@ -240,54 +298,34 @@ var Document = function(text) { * @returns {Object} The position ({row, column}) of the last line of `text`. If the length of `text` is 0, this function simply returns `position`. * **/ - this.insert = function(position, text) { - if (!text || text.length === 0) - return position; - - position = this.$clipPosition(position); - - // only detect new lines if the document has no line break yet + this.insertText = function(position, text) { + + // Only detect new lines if the document has no line break yet. if (this.getLength() <= 1) this.$detectNewLine(text); - - var lines = this.$split(text); - var firstLine = lines.splice(0, 1)[0]; - var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0]; - - position = this.insertInLine(position, firstLine); - if (lastLine !== null) { - position = this.insertNewLine(position); // terminate first line - position = this._insertLines(position.row, lines); - position = this.insertInLine(position, lastLine || ""); - } - return position; + + return this.insertLines(position, this.$split(text)); }; /** - * Fires whenever the document changes. - * - * Several methods trigger different `"change"` events. Below is a list of each action type, followed by each property that's also available: - * - * * `"insertLines"` (emitted by [[Document.insertLines]]) - * * `range`: the [[Range]] of the change within the document - * * `lines`: the lines in the document that are changing - * * `"insertText"` (emitted by [[Document.insertNewLine]]) - * * `range`: the [[Range]] of the change within the document - * * `text`: the text that's being added - * * `"removeLines"` (emitted by [[Document.insertLines]]) - * * `range`: the [[Range]] of the change within the document - * * `lines`: the lines in the document that were removed - * * `nl`: the new line character (as defined by [[Document.getNewLineCharacter]]) - * * `"removeText"` (emitted by [[Document.removeInLine]] and [[Document.removeNewLine]]) - * * `range`: the [[Range]] of the change within the document - * * `text`: the text that's being removed - * - * @event change - * @param {Object} e Contains at least one property called `"action"`. `"action"` indicates the action that triggered the change. Each action also has a set of additional properties. - * - **/ + * Fires whenever the document changes. + * + * Several methods trigger different `"change"` events. Below is a list of each action type, followed by each property that's also available: + * + * * `"insert"` + * * `range`: the [[Range]] of the change within the document + * * `lines`: the lines being added + * * `"delete"` + * * `range`: the [[Range]] of the change within the document + * * `lines`: the lines being removed + * + * @event change + * @param {Object} e Contains at least one property called `"action"`. `"action"` indicates the action that triggered the change. Each action also has a set of additional properties. + * + **/ + /** - * Inserts the elements in `lines` into the document, starting at the row index given by `row`. This method also triggers the `'change'` event. + * Inserts the elements in `lines` into the document as full lines (does not merge with existing line), starting at the row index given by `row`. This method also triggers the `'change'` event. * @param {Number} row The index of the row to insert at * @param {Array} lines An array of strings * @returns {Object} Contains the final row and column, like this: @@ -300,100 +338,62 @@ var Document = function(text) { * ``` * **/ - this.insertLines = function(row, lines) { - if (row >= this.getLength()) - return this.insert({row: row, column: 0}, "\n" + lines.join("\n")); - return this._insertLines(Math.max(row, 0), lines); - }; - this._insertLines = function(row, lines) { - if (lines.length == 0) - return {row: row, column: 0}; - - // apply doesn't work for big arrays (smallest threshold is on safari 0xFFFF) - // to circumvent that we have to break huge inserts into smaller chunks here - if (lines.length > 0xFFFF) { - var end = this._insertLines(row, lines.slice(0xFFFF)); - lines = lines.slice(0, 0xFFFF); + this.insertFullLines = function(row, lines) + { + // Clip to document. + // Allow one past the document end. + row = Math.min(Math.max(row, 0), this.getLength()); + + // Calculate insertion point. + var column = 0; + if (row < this.getLength()) // Insert before the specified row. + { + lines = lines.concat(['']); + column = 0; } + else // Insert after the last row in the document. + { + lines = [''].concat(lines); + row--; + var column = this.$lines[row].length; + } + + // Insert. + this.insertLines({row: row, column: column}, lines); + }, - var args = [row, 0]; - args.push.apply(args, lines); - this.$lines.splice.apply(this.$lines, args); + /** + * Inserts the elements in `lines` into the document, starting at the position index given by `row`. This method also triggers the `'change'` event. + * @param {Number} row The index of the row to insert at + * @param {Array} lines An array of strings + * @returns {Object} Contains the final row and column, like this: + * ``` + * {row: endRow, column: 0} + * ``` + * If `lines` is empty, this function returns an object containing the current row, and column, like this: + * ``` + * {row: row, column: 0} + * ``` + * + **/ + this.insertLines = function(position, lines){ - var range = new Range(row, 0, row + lines.length, 0); - var delta = { - action: "insertLines", - range: range, + // Calculate insertion range end point. + this.$clipPosition(position); + var endPoint = { + row : position.row + lines.length - 1, + column : (lines.length == 1 ? position.column : 0) + lines[lines.length - 1].length + }; + + // Apply delta (emits change). + this.applyDelta({ + action: "insert", + range: Range.fromPoints(position, endPoint), lines: lines - }; - this._emit("change", { data: delta }); - return end || range.end; - }; - - /** - * Inserts a new line into the document at the current row's `position`. This method also triggers the `'change'` event. - * @param {Object} position The position to insert at - * @returns {Object} Returns an object containing the final row and column, like this:
- * ``` - * {row: endRow, column: 0} - * ``` - * - **/ - this.insertNewLine = function(position) { - position = this.$clipPosition(position); - var line = this.$lines[position.row] || ""; - - this.$lines[position.row] = line.substring(0, position.column); - this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length)); - - var end = { - row : position.row + 1, - column : 0 - }; - - var delta = { - action: "insertText", - range: Range.fromPoints(position, end), - text: this.getNewLineCharacter() - }; - this._emit("change", { data: delta }); - - return end; - }; - - /** - * Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event. - * @param {Object} position The position to insert at; it's an object that looks like `{ row: row, column: column}` - * @param {String} text A chunk of text - * @returns {Object} Returns an object containing the final row and column, like this: - * ``` - * {row: endRow, column: 0} - * ``` - * - **/ - this.insertInLine = function(position, text) { - if (text.length == 0) - return position; - - var line = this.$lines[position.row] || ""; - - this.$lines[position.row] = line.substring(0, position.column) + text - + line.substring(position.column); - - var end = { - row : position.row, - column : position.column + text.length - }; - - var delta = { - action: "insertText", - range: Range.fromPoints(position, end), - text: text - }; - this._emit("change", { data: delta }); - - return end; - }; + }); + + return endPoint; + } /** * Removes the `range` from the document. @@ -402,37 +402,16 @@ var Document = function(text) { * **/ this.remove = function(range) { - if (!range instanceof Range) - range = Range.fromPoints(range.start, range.end); - // clip to document - range.start = this.$clipPosition(range.start); - range.end = this.$clipPosition(range.end); - - if (range.isEmpty()) - return range.start; - - var firstRow = range.start.row; - var lastRow = range.end.row; - - if (range.isMultiLine()) { - var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1; - var lastFullRow = lastRow - 1; - - if (range.end.column > 0) - this.removeInLine(lastRow, 0, range.end.column); - - if (lastFullRow >= firstFullRow) - this._removeLines(firstFullRow, lastFullRow); - - if (firstFullRow != firstRow) { - this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length); - this.removeNewLine(range.start.row); - } - } - else { - this.removeInLine(firstRow, range.start.column, range.end.column); - } - return range.start; + + // Apply delta (emits change). + range = this.$getClippedRange(range); + this.applyDelta( + { + action: 'delete', + range: range, + lines: this._getLinesForRange(range), + }); + return range.start; }; /** @@ -444,21 +423,18 @@ var Document = function(text) { * **/ this.removeInLine = function(row, startColumn, endColumn) { - if (startColumn == endColumn) - return; - + + // Calculate deleteion range. var range = new Range(row, startColumn, row, endColumn); - var line = this.getLine(row); - var removed = line.substring(startColumn, endColumn); - var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length); - this.$lines.splice(row, 1, newLine); - - var delta = { - action: "removeText", + range = this.$getClippedRange(range); + + // Apply delta (emits change). + this.applyDelta({ + action: "delete", range: range, - text: removed - }; - this._emit("change", { data: delta }); + lines: this._getLinesForRange(range) + }); + return range.start; }; @@ -469,24 +445,35 @@ var Document = function(text) { * @returns {[String]} Returns all the removed lines. * **/ - this.removeLines = function(firstRow, lastRow) { - if (firstRow < 0 || lastRow >= this.getLength()) - return this.remove(new Range(firstRow, 0, lastRow + 1, 0)); - return this._removeLines(firstRow, lastRow); - }; - - this._removeLines = function(firstRow, lastRow) { - var range = new Range(firstRow, 0, lastRow + 1, 0); - var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1); - - var delta = { - action: "removeLines", + this.removeFullLines = function(firstRow, lastRow) { + + // Clip to document. + firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1); + lastRow = Math.min(Math.max(0, lastRow ), this.getLength() - 1); + + // Calculate deletion range. + // Delete the ending new line unless we're at the end of the document. + // If we're at the end of the document, delete the starting new line. + var deleteFirstNewLine = lastRow == this.getLength() - 1 && firstRow > 0; + var deleteLastNewLine = lastRow < this.getLength() - 1; + var startRow = ( deleteFirstNewLine ? firstRow - 1 : firstRow ); + var startCol = ( deleteFirstNewLine ? this.getLine(startRow).length : 0 ); + var endRow = ( deleteLastNewLine ? lastRow + 1 : lastRow ); + var endCol = ( deleteLastNewLine ? 0 : this.getLine(endRow).length ); + var range = new Range(startRow, startCol, endRow, endCol); + + // Store delelted lines with bounding newlines ommitted (maintains previous behavior). + var deletedLines = this.$lines.slice(firstRow, lastRow + 1); + + // Apply delta (emits change). + this.applyDelta({ + action: "delete", range: range, - nl: this.getNewLineCharacter(), - lines: removed - }; - this._emit("change", { data: delta }); - return removed; + lines: this._getLinesForRange(range) + }); + + // Return the deleted lines. + return deletedLines; }; /** @@ -495,20 +482,16 @@ var Document = function(text) { * **/ this.removeNewLine = function(row) { - var firstLine = this.getLine(row); - var secondLine = this.getLine(row+1); - - var range = new Range(row, firstLine.length, row+1, 0); - var line = firstLine + secondLine; - - this.$lines.splice(row, 2, line); - - var delta = { - action: "removeText", - range: range, - text: this.getNewLineCharacter() - }; - this._emit("change", { data: delta }); + + if (row < this.getLength() - 1 && row >= 0) + { + // Apply delta (emits change). + this.applyDelta({ + action: "delete", + range: new Range(row, this.getLine(row).length, row + 1, 0), + lines: ['', ''] + }); + } }; /** @@ -534,53 +517,90 @@ var Document = function(text) { this.remove(range); if (text) { - var end = this.insert(range.start, text); + var end = this.insertText(range.start, text); } else { end = range.start; } - + return end; }; /** - * Applies all the changes previously accumulated. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`. + * Applies all the changes previously accumulated. These can be either `'insert'` or `'delete'`. **/ this.applyDeltas = function(deltas) { for (var i=0; i=0; i--) { - var delta = deltas[i]; - - var range = Range.fromPoints(delta.range.start, delta.range.end); - - if (delta.action == "insertLines") - this._removeLines(range.start.row, range.end.row - 1); - else if (delta.action == "insertText") - this.remove(range); - else if (delta.action == "removeLines") - this._insertLines(range.start.row, delta.lines); - else if (delta.action == "removeText") - this.insert(range.start, delta.text); + this.revertDelta(deltas[i]); } }; + + this.revertDelta = function(delta) + { + this.applyDelta({ + action: (delta.action == 'insert' ? 'delete' : 'insert'), + range: delta.range.clone(), + lines: delta.lines.slice() + }); + }, /** * Converts an index position in a document to a `{row, column}` object. diff --git a/lib/ace/document_test.js b/lib/ace/document_test.js index 5c324db0..50bd8b49 100644 --- a/lib/ace/document_test.js +++ b/lib/ace/document_test.js @@ -48,7 +48,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insert({row: 0, column: 1}, "juhu"); + doc.insertText({row: 0, column: 1}, "juhu"); assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n")); var d = deltas.concat(); @@ -65,7 +65,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertNewLine({row: 0, column: 1}); + doc.insertLines({row: 0, column: 1}, ['', '']); assert.equal(doc.getValue(), ["1", "2", "34"].join("\n")); var d = deltas.concat(); @@ -82,7 +82,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertLines(0, ["aa", "bb"]); + doc.insertFullLines(0, ["aa", "bb"]); assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n")); var d = deltas.concat(); @@ -99,7 +99,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertLines(2, ["aa", "bb"]); + doc.insertFullLines(2, ["aa", "bb"]); assert.equal(doc.getValue(), ["12", "34", "aa", "bb"].join("\n")); }, @@ -109,7 +109,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insertLines(1, ["aa", "bb"]); + doc.insertFullLines(1, ["aa", "bb"]); assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n")); var d = deltas.concat(); @@ -126,7 +126,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insert({row: 0, column: 0}, "aa\nbb\ncc"); + doc.insertText({row: 0, column: 0}, "aa\nbb\ncc"); assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n")); var d = deltas.concat(); @@ -143,7 +143,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insert({row: 2, column: 0}, "aa\nbb\ncc"); + doc.insertText({row: 1, column: 2}, "aa\nbb\ncc"); assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n")); var d = deltas.concat(); @@ -160,7 +160,7 @@ module.exports = { var deltas = []; doc.on("change", function(e) { deltas.push(e.data); }); - doc.insert({row: 0, column: 1}, "aa\nbb\ncc"); + doc.insertText({row: 0, column: 1}, "aa\nbb\ncc"); assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n")); var d = deltas.concat(); @@ -235,7 +235,7 @@ module.exports = { "test: remove lines should return the removed lines" : function() { var doc = new Document(["1234", "5678", "abcd"]); - var removed = doc.removeLines(1, 2); + var removed = doc.removeFullLines(1, 2); assert.equal(removed.join("\n"), ["5678", "abcd"].join("\n")); }, diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index a63ceeef..98c255a4 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -1136,8 +1136,8 @@ var EditSession = function(text, mode) { * * **/ - this.insert = function(position, text) { - return this.doc.insert(position, text); + this.insertText = function(position, text) { + return this.doc.insertText(position, text); }; /** @@ -1151,6 +1151,19 @@ var EditSession = function(text, mode) { this.remove = function(range) { return this.doc.remove(range); }; + + /** + * Removes a range of full lines. This method also triggers the `'change'` event. + * @param {Number} firstRow The first row to be removed + * @param {Number} lastRow The last row to be removed + * @returns {[String]} Returns all the removed lines. + * + * @related Document.removeFullLines + * + **/ + this.removeFullLines = function(firstRow, lastRow){ + return this.doc.removeFullLines(firstRow, lastRow) + } /** * Reverts previous changes to your document. @@ -1227,9 +1240,7 @@ var EditSession = function(text, mode) { this.$getUndoSelection = function(deltas, isUndo, lastUndoRange) { function isInsert(delta) { - var insert = - delta.action === "insertText" || delta.action === "insertLines"; - return isUndo ? !insert : insert; + return isUndo ? delta.action !== "insert" : delta.action === "insert"; } var delta = deltas[0]; @@ -1339,7 +1350,7 @@ var EditSession = function(text, mode) { } } - toRange.end = this.insert(toRange.start, text); + toRange.end = this.insertText(toRange.start, text); if (folds.length) { var oldStart = fromRange.start; var newStart = toRange.start; @@ -1373,7 +1384,7 @@ var EditSession = function(text, mode) { this.indentRows = function(startRow, endRow, indentString) { indentString = indentString.replace(/\t/g, this.getTabString()); for (var row=startRow; row<=endRow; row++) - this.insert({row: row, column:0}, indentString); + this.insertText({row: row, column:0}, indentString); }; /** @@ -1430,11 +1441,11 @@ var EditSession = function(text, mode) { x.end.row += diff; return x; }); - + var lines = dir == 0 ? this.doc.getLines(firstRow, lastRow) - : this.doc.removeLines(firstRow, lastRow); - this.doc.insertLines(firstRow+diff, lines); + : this.doc.removeFullLines(firstRow, lastRow); + this.doc.insertFullLines(firstRow+diff, lines); folds.length && this.addFolds(folds); return diff; }; @@ -1444,8 +1455,6 @@ var EditSession = function(text, mode) { * @param {Number} lastRow The final row to move up * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1. * - * @related Document.insertLines - * **/ this.moveLinesUp = function(firstRow, lastRow) { return this.$moveLines(firstRow, lastRow, -1); @@ -1456,8 +1465,6 @@ var EditSession = function(text, mode) { * @param {Number} firstRow The starting row to move down * @param {Number} lastRow The final row to move down * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1. - * - * @related Document.insertLines **/ this.moveLinesDown = function(firstRow, lastRow) { return this.$moveLines(firstRow, lastRow, 1); @@ -1668,28 +1675,17 @@ var EditSession = function(text, mode) { this.$updateInternalDataOnChange = function(e) { var useWrapMode = this.$useWrapMode; - var len; var action = e.data.action; - var firstRow = e.data.range.start.row; - var lastRow = e.data.range.end.row; var start = e.data.range.start; var end = e.data.range.end; + var firstRow = start.row; + var lastRow = end.row; + var len = lastRow - firstRow; var removedFolds = null; - - if (action.indexOf("Lines") != -1) { - if (action == "insertLines") { - lastRow = firstRow + (e.data.lines.length); - } else { - lastRow = firstRow; - } - len = e.data.lines ? e.data.lines.length : lastRow - firstRow; - } else { - len = lastRow - firstRow; - } - + this.$updating = true; if (len != 0) { - if (action.indexOf("remove") != -1) { + if (action == "delete") { this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len); var foldLines = this.$foldData; @@ -1764,7 +1760,7 @@ var EditSession = function(text, mode) { // Realign folds. E.g. if you add some new chars before a fold, the // fold should "move" to the right. len = Math.abs(e.data.range.start.column - e.data.range.end.column); - if (action.indexOf("remove") != -1) { + if (action == "delete") { // Get all the folds in the change range and remove them. removedFolds = this.getFoldsInRange(e.data.range); this.removeFolds(removedFolds); diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index 474818b2..9df35593 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -833,7 +833,7 @@ function Folding() { if (len === 0) { this.foldWidgets[firstRow] = null; - } else if (delta.action == "removeText" || delta.action == "removeLines") { + } else if (delta.action == "delete") { this.foldWidgets.splice(firstRow, len + 1, null); } else { var args = Array(len + 1); diff --git a/lib/ace/edit_session_test.js b/lib/ace/edit_session_test.js index 87cc9567..855da4d1 100644 --- a/lib/ace/edit_session_test.js +++ b/lib/ace/edit_session_test.js @@ -430,12 +430,12 @@ module.exports = { session.setTabSize(4); assert.equal(session.getScreenWidth(), 2); - session.doc.insertNewLine({row: 0, column: Infinity}); - session.doc.insertLines(1, ["123"]); + session.doc.insertLines({row: 0, column: Infinity}, ['', '']); + session.doc.insertFullLines(1, ["123"]); assert.equal(session.getScreenWidth(), 3); - session.doc.insertNewLine({row: 0, column: Infinity}); - session.doc.insertLines(1, ["\t\t"]); + session.doc.insertLines({row: 0, column: Infinity}, ['', '']); + session.doc.insertFullLines(1, ["\t\t"]); assert.equal(session.getScreenWidth(), 8); @@ -459,9 +459,9 @@ module.exports = { session.setUseWrapMode(true); - document.insertLines(0, ["a", "b"]); - document.insertLines(2, ["c", "d"]); - document.removeLines(1, 2); + document.insertFullLines(0, ["a", "b"]); + document.insertFullLines(2, ["c", "d"]); + document.removeFullLines(1, 2); }, "test wrapMode init has to create wrapData array": function() { @@ -649,7 +649,7 @@ module.exports = { var foldLines = session.$foldData; function insert(row, column, text) { - session.insert({row: row, column: column}, text); + session.insertText({row: row, column: column}, text); // Force the session to store all changes made to the document NOW // on the undoManager's queue. Otherwise we can't undo in separate @@ -748,7 +748,7 @@ module.exports = { undoManager = session.getUndoManager(), foldLines = session.$foldData; function insert(row, column, text) { - session.insert({row: row, column: column}, text); + session.insertText({row: row, column: column}, text); // Force the session to store all changes made to the document NOW // on the undoManager's queue. Otherwise we can't undo in separate // steps later. diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 6486a881..3926fc81 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -601,19 +601,10 @@ var Editor = function(renderer, session) { * **/ this.onDocumentChange = function(e) { - var delta = e.data; - var range = delta.range; - var lastRow; - - if (range.start.row == range.end.row && delta.action != "insertLines" && delta.action != "removeLines") - lastRow = range.end.row; - else - lastRow = Infinity; - this.renderer.updateLines(range.start.row, lastRow); - + this.renderer.updateLines(e.data.range.start.row, e.data.range.end.row); this._emit("change", e); - - // update cursor because tab characters can influence the cursor position + + // update cursor because tab characters can influence the cursor position. this.$cursorChange(); }; @@ -827,7 +818,7 @@ var Editor = function(renderer, session) { if (this.$readOnly) return; this._emit("paste", text); - this.insert(text); + this.insertText(text); }; @@ -841,7 +832,7 @@ var Editor = function(renderer, session) { * * **/ - this.insert = function(text) { + this.insertText = function(text) { var session = this.session; var mode = session.getMode(); var cursor = this.getCursorPosition(); @@ -887,7 +878,7 @@ var Editor = function(renderer, session) { var lineState = session.getState(cursor.row); var line = session.getLine(cursor.row); var shouldOutdent = mode.checkOutdent(lineState, line, text); - var end = session.insert(cursor, text); + var end = session.insertText(cursor, text); if (transform && transform.selection) { if (transform.selection.length == 2) { // Transform relative to the current column @@ -906,7 +897,7 @@ var Editor = function(renderer, session) { if (session.getDocument().isNewLine(text)) { var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString()); - session.insert({row: cursor.row+1, column: 0}, lineIndent); + session.insertText({row: cursor.row+1, column: 0}, lineIndent); } if (shouldOutdent) mode.autoOutdent(lineState, session, cursor.row); @@ -1279,7 +1270,7 @@ var Editor = function(renderer, session) { } var cursor = this.getCursorPosition(); - this.insert("\n"); + this.insertText("\n"); this.moveCursorToPosition(cursor); }; @@ -1378,7 +1369,7 @@ var Editor = function(renderer, session) { this.selection.setSelectionRange(range); indentString = "\t"; } - return this.insert(indentString); + return this.insertText(indentString); }; /** @@ -1516,15 +1507,7 @@ var Editor = function(renderer, session) { **/ this.removeLines = function() { var rows = this.$getSelectedRows(); - var range; - if (rows.first === 0 || rows.last+1 < this.session.getLength()) - range = new Range(rows.first, 0, rows.last+1, 0); - else - range = new Range( - rows.first-1, this.session.getLine(rows.first-1).length, - rows.last, this.session.getLine(rows.last).length - ); - this.session.remove(range); + this.session.removeFullLines(rows.first, rows.last); this.clearSelection(); }; @@ -1538,7 +1521,7 @@ var Editor = function(renderer, session) { doc.duplicateLines(row, row); } else { var point = reverse ? range.start : range.end; - var endPoint = doc.insert(point, doc.getTextRange(range), false); + var endPoint = doc.insertText(point, doc.getTextRange(range), false); range.start = point; range.end = endPoint; diff --git a/lib/ace/editor_change_document_test.js b/lib/ace/editor_change_document_test.js index a1fdaad9..83fffeb3 100644 --- a/lib/ace/editor_change_document_test.js +++ b/lib/ace/editor_change_document_test.js @@ -172,7 +172,7 @@ module.exports = { self.session1.setMode(new HtmlMode()); // 5. Try to type valid HTML - self.session1.insert({row: 0, column: 0}, ""); + self.session1.insertText({row: 0, column: 0}, ""); setTimeout(function() { assert.equal(Object.keys(self.session1.getAnnotations()).length, 0); diff --git a/lib/ace/editor_navigation_test.js b/lib/ace/editor_navigation_test.js index ab348241..b60d391d 100644 --- a/lib/ace/editor_navigation_test.js +++ b/lib/ace/editor_navigation_test.js @@ -150,7 +150,7 @@ module.exports = { var editor = new Editor(new MockRenderer(), new EditSession(["1234", "1234567890"])); editor.navigateTo(0, 3); - editor.insert("juhu"); + editor.insertText("juhu"); editor.navigateDown(); assert.position(editor.getCursorPosition(), 1, 7); diff --git a/lib/ace/ext/chromevox.js b/lib/ace/ext/chromevox.js index 9f7a7996..20bbb6c7 100644 --- a/lib/ace/ext/chromevox.js +++ b/lib/ace/ext/chromevox.js @@ -581,12 +581,12 @@ var onSelectionChange = function(evt) { var onChange = function(evt) { var data = evt.data; switch (data.action) { - case 'removeText': + case 'delete': cvox.Api.speak(data.text, 0, DELETED_PROP); /* Let the future cursor change event know it's from text change. */ changed = true; break; - case 'insertText': + case 'insert': cvox.Api.speak(data.text, 0); /* Let the future cursor change event know it's from text change. */ changed = true; diff --git a/lib/ace/ext/elastic_tabstops_lite.js b/lib/ace/ext/elastic_tabstops_lite.js index 9901c5df..4d3a40d4 100644 --- a/lib/ace/ext/elastic_tabstops_lite.js +++ b/lib/ace/ext/elastic_tabstops_lite.js @@ -236,7 +236,7 @@ var ElasticTabstopsLite = function(editor) { if (difference > 0) { // put the spaces after the tab and then delete the tab, so any insertion // points behave as expected - this.$editor.session.getDocument().insertInLine({row: row, column: it + 1}, Array(difference + 1).join(" ") + "\t"); + this.$editor.session.getDocument().insertText({row: row, column: it + 1}, Array(difference + 1).join(" ") + "\t"); this.$editor.session.getDocument().removeInLine(row, it, it + 1); bias += difference; diff --git a/lib/ace/ext/whitespace.js b/lib/ace/ext/whitespace.js index 83486fb0..736e991d 100644 --- a/lib/ace/ext/whitespace.js +++ b/lib/ace/ext/whitespace.js @@ -153,7 +153,7 @@ exports.convertIndentation = function(session, ch, len) { if (toInsert != match) { doc.removeInLine(i, 0, match.length); - doc.insertInLine({row: i, column: 0}, toInsert); + doc.insertText({row: i, column: 0}, toInsert); } } } diff --git a/lib/ace/keyboard/vim/commands.js b/lib/ace/keyboard/vim/commands.js index dd3357d6..defca037 100644 --- a/lib/ace/keyboard/vim/commands.js +++ b/lib/ace/keyboard/vim/commands.js @@ -104,7 +104,7 @@ var actions = exports.actions = { if (param && param.length) { if (param.length > 1) param = param == "return" ? "\n" : param == "tab" ? "\t" : param; - repeat(function() { editor.insert(param); }, count || 1); + repeat(function() { editor.insertText(param); }, count || 1); editor.navigateLeft(); } } @@ -224,12 +224,12 @@ var actions = exports.actions = { var pos = editor.getCursorPosition(); pos.column = editor.session.getLine(pos.row).length; var text = lang.stringRepeat("\n" + defaultReg.text, count || 1); - editor.session.insert(pos, text); + editor.session.insertText(pos, text); editor.moveCursorTo(pos.row + 1, 0); } else { editor.navigateRight(); - editor.insert(lang.stringRepeat(defaultReg.text, count || 1)); + editor.insertText(lang.stringRepeat(defaultReg.text, count || 1)); editor.navigateLeft(); } editor.setOverwrite(true); @@ -245,11 +245,11 @@ var actions = exports.actions = { var pos = editor.getCursorPosition(); pos.column = 0; var text = lang.stringRepeat(defaultReg.text + "\n", count || 1); - editor.session.insert(pos, text); + editor.session.insertText(pos, text); editor.moveCursorToPosition(pos); } else { - editor.insert(lang.stringRepeat(defaultReg.text, count || 1)); + editor.insertText(lang.stringRepeat(defaultReg.text, count || 1)); } editor.setOverwrite(true); editor.selection.clearSelection(); diff --git a/lib/ace/keyboard/vim/maps/motions.js b/lib/ace/keyboard/vim/maps/motions.js index 91c8b8af..2bf580b0 100644 --- a/lib/ace/keyboard/vim/maps/motions.js +++ b/lib/ace/keyboard/vim/maps/motions.js @@ -545,7 +545,7 @@ module.exports = { if (content.length) { editor.navigateLineEnd() - editor.insert(content); + editor.insertText(content); util.insertMode(editor); } } @@ -562,9 +562,9 @@ module.exports = { if(row > 0) { editor.navigateUp(); editor.navigateLineEnd() - editor.insert(content); + editor.insertText(content); } else { - editor.session.insert({row: 0, column: 0}, content); + editor.session.insertText({row: 0, column: 0}, content); editor.navigateUp(); } util.insertMode(editor); diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js index 5a535094..9d813d2a 100644 --- a/lib/ace/layer/gutter.js +++ b/lib/ace/layer/gutter.js @@ -108,8 +108,8 @@ var Gutter = function(parentEl) { var len = range.end.row - firstRow; if (len === 0) { // do nothing - } else if (delta.action == "removeText" || delta.action == "removeLines") { - this.$annotations.splice(firstRow, len + 1, null); + } else if (delta.action == "delete") { + this.$annotations.splice(firstRow, len, null); } else { var args = new Array(len + 1); args.unshift(firstRow, 1); diff --git a/lib/ace/line_widgets.js b/lib/ace/line_widgets.js index 597b3ca2..4023bd55 100644 --- a/lib/ace/line_widgets.js +++ b/lib/ace/line_widgets.js @@ -123,7 +123,7 @@ function LineWidgets(session) { if (len === 0) { // return - } else if (delta.action == "removeText" || delta.action == "removeLines") { + } else if (delta.action == "delete") { var removed = cells.splice(startRow + 1, len); removed.forEach(function(w) { w && this.removeLineWidget(w); diff --git a/lib/ace/mode/javascript_test.js b/lib/ace/mode/javascript_test.js index b413765a..cc2b22d7 100644 --- a/lib/ace/mode/javascript_test.js +++ b/lib/ace/mode/javascript_test.js @@ -131,7 +131,7 @@ module.exports = { this.mode.toggleCommentLines("start", session, 0, 2); assert.equal([" abc", " cde", " fg"].join("\n"), session.toString()); - session.insert({row: 0, column: 0}, " "); + session.insertText({row: 0, column: 0}, " "); this.mode.toggleCommentLines("start", session, 0, 2); assert.equal(["// abc", "// cde", "// fg"].join("\n"), session.toString()); }, diff --git a/lib/ace/mode/text.js b/lib/ace/mode/text.js index d04fed78..534ac03c 100644 --- a/lib/ace/mode/text.js +++ b/lib/ace/mode/text.js @@ -92,8 +92,8 @@ var Mode = function() { if (testRemove(line, i)) return; if (!ignoreBlankLines || /\S/.test(line)) { - doc.insertInLine({row: i, column: line.length}, lineCommentEnd); - doc.insertInLine({row: i, column: minIndent}, lineCommentStart); + doc.insertText({row: i, column: line.length}, lineCommentEnd); + doc.insertText({row: i, column: minIndent}, lineCommentStart); } }; @@ -138,9 +138,9 @@ var Mode = function() { var comment = function(line, i) { if (!ignoreBlankLines || /\S/.test(line)) { if (shouldInsertSpace(line, minIndent, minIndent)) - doc.insertInLine({row: i, column: minIndent}, commentWithSpace); + doc.insertText({row: i, column: minIndent}, commentWithSpace); else - doc.insertInLine({row: i, column: minIndent}, lineCommentStart); + doc.insertText({row: i, column: minIndent}, lineCommentStart); } }; var testRemove = function(line, i) { @@ -244,8 +244,8 @@ var Mode = function() { } else { colDiff = comment.start.length startRow = range.start.row; - session.insert(range.end, comment.end); - session.insert(range.start, comment.start); + session.insertText(range.end, comment.end); + session.insertText(range.start, comment.start); } // todo: selection should have ended up in the right place automatically! if (initialRange.start.row == startRow) diff --git a/lib/ace/mouse/dragdrop_handler.js b/lib/ace/mouse/dragdrop_handler.js index 3a4bc188..3ad54bb8 100644 --- a/lib/ace/mouse/dragdrop_handler.js +++ b/lib/ace/mouse/dragdrop_handler.js @@ -176,7 +176,7 @@ function DragdropHandler(mouseHandler) { var dropData = dataTransfer.getData('Text'); range = { start: dragCursor, - end: editor.session.insert(dragCursor, dropData) + end: editor.session.insertText(dragCursor, dropData) }; editor.focus(); dragOperation = null; diff --git a/lib/ace/multi_select.js b/lib/ace/multi_select.js index 7f4c5355..883d9a7c 100644 --- a/lib/ace/multi_select.js +++ b/lib/ace/multi_select.js @@ -544,7 +544,7 @@ var Editor = require("./editor").Editor; this._signal("paste", text); if (!this.inMultiSelectMode || this.inVirtualSelectionMode) - return this.insert(text); + return this.insertText(text); var lines = text.split(/\r\n|\r|\n/); var ranges = this.selection.rangeList.ranges; @@ -557,7 +557,7 @@ var Editor = require("./editor").Editor; if (!range.isEmpty()) this.session.remove(range); - this.session.insert(range.start, lines[i]); + this.session.insertText(range.start, lines[i]); } }; @@ -740,9 +740,9 @@ var Editor = require("./editor").Editor; if (fr < 0) fr = 0; if (lr >= max) lr = max - 1; } - var lines = this.session.doc.removeLines(fr, lr); + var lines = this.session.removeFullLines(fr, lr); lines = this.$reAlignText(lines, guessRange); - this.session.doc.insert({row: fr, column: 0}, lines.join("\n") + "\n"); + this.session.insertText({row: fr, column: 0}, lines.join("\n") + "\n"); if (!guessRange) { range.start.column = 0; range.end.column = lines[lines.length - 1].length; @@ -778,7 +778,7 @@ var Editor = require("./editor").Editor; var l = maxCol - p.column; var d = spaceOffsets[i] - minSpace; if (l > d) - session.insert(p, lang.stringRepeat(" ", l - d)); + session.insertText(p, lang.stringRepeat(" ", l - d)); else session.remove(new Range(p.row, p.column, p.row, p.column - l + d)); diff --git a/lib/ace/occur_test.js b/lib/ace/occur_test.js index 59fb8548..a9b2c894 100644 --- a/lib/ace/occur_test.js +++ b/lib/ace/occur_test.js @@ -55,7 +55,7 @@ module.exports = { }, "test: find lines matching" : function() { - editor.session.insert({row: 0, column: 0}, 'abc\ndef\nxyz\nbcxbc'); + editor.session.insertText({row: 0, column: 0}, 'abc\ndef\nxyz\nbcxbc'); var result = occur.matchingLines(editor.session, {needle: 'bc'}), expected = [{row: 0, content: 'abc'}, {row: 3, content: 'bcxbc'}]; assert.deepEqual(result, expected); @@ -63,7 +63,7 @@ module.exports = { "test: display occurrences" : function() { var text = 'abc\ndef\nxyz\nbcx\n'; - editor.session.insert({row: 0, column: 0}, text); + editor.session.insertText({row: 0, column: 0}, text); occur.displayOccurContent(editor, {needle: 'bc'}); assert.equal(editor.getValue(), 'abc\nbcx'); occur.displayOriginalContent(editor); @@ -72,7 +72,7 @@ module.exports = { "test: original position from occur doc" : function() { var text = 'abc\ndef\nxyz\nbcx\n'; - editor.session.insert({row: 0, column: 0}, text); + editor.session.insertText({row: 0, column: 0}, text); occur.displayOccurContent(editor, {needle: 'bc'}); assert.equal(editor.getValue(), 'abc\nbcx'); var pos = occur.occurToOriginalPosition(editor.session, {row: 1, column: 2}); @@ -82,7 +82,7 @@ module.exports = { "test: occur command" : function() { // setup var text = 'hel\nlo\n\nwo\nrld\n'; - editor.session.insert({row: 0, column: 0}, text); + editor.session.insertText({row: 0, column: 0}, text); editor.commands.addCommand(occurStartCommand); // run occur for lines including 'o' @@ -106,7 +106,7 @@ module.exports = { "test: occur navigation" : function() { // setup var text = 'hel\nlo\n\nwo\nrld\n'; - editor.session.insert({row: 0, column: 0}, text); + editor.session.insertText({row: 0, column: 0}, text); editor.commands.addCommand(occurStartCommand); editor.moveCursorToPosition({row: 1, column: 1}); @@ -125,7 +125,7 @@ module.exports = { "test: recursive occur" : function() { // setup var text = 'x\nabc1\nx\nabc2\n'; - editor.session.insert({row: 0, column: 0}, text); + editor.session.insertText({row: 0, column: 0}, text); editor.commands.addCommand(occurStartCommand); // orig -> occur1 diff --git a/lib/ace/placeholder.js b/lib/ace/placeholder.js index bcb44ce2..9d0a3c3c 100644 --- a/lib/ace/placeholder.js +++ b/lib/ace/placeholder.js @@ -155,21 +155,21 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) if(range.start.row !== this.pos.row) return; if (this.$updating) return; this.$updating = true; - var lengthDiff = delta.action === "insertText" ? range.end.column - range.start.column : range.start.column - range.end.column; + var lengthDiff = delta.action === "insert" ? range.end.column - range.start.column : range.start.column - range.end.column; if(range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1) { var distanceFromStart = range.start.column - this.pos.column; this.length += lengthDiff; if(!this.session.$fromUndo) { - if(delta.action === "insertText") { + if(delta.action === "insert") { for (var i = this.others.length - 1; i >= 0; i--) { var otherPos = this.others[i]; var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; if(otherPos.row === range.start.row && range.start.column < otherPos.column) newPos.column += lengthDiff; - this.doc.insert(newPos, delta.text); + this.doc.insertLines(newPos, delta.lines); } - } else if(delta.action === "removeText") { + } else if(delta.action === "delete") { for (var i = this.others.length - 1; i >= 0; i--) { var otherPos = this.others[i]; var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; @@ -179,7 +179,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) } } // Special case: insert in beginning - if(range.start.column === this.pos.column && delta.action === "insertText") { + if(range.start.column === this.pos.column && delta.action === "insert") { setTimeout(function() { this.pos.setPosition(this.pos.row, this.pos.column - lengthDiff); for (var i = 0; i < this.others.length; i++) { @@ -191,7 +191,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) } }.bind(this), 0); } - else if(range.start.column === this.pos.column && delta.action === "removeText") { + else if(range.start.column === this.pos.column && delta.action === "delete") { setTimeout(function() { for (var i = 0; i < this.others.length; i++) { var other = this.others[i]; diff --git a/lib/ace/placeholder_test.js b/lib/ace/placeholder_test.js index 97e561fd..dc7e4b23 100644 --- a/lib/ace/placeholder_test.js +++ b/lib/ace/placeholder_test.js @@ -53,9 +53,9 @@ module.exports = { new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(0, 5); - editor.insert('b'); + editor.insertText('b'); assert.equal(session.doc.getValue(), "var ab = 10;\nconsole.log(ab, ab);"); - editor.insert('cd'); + editor.insertText('cd'); assert.equal(session.doc.getValue(), "var abcd = 10;\nconsole.log(abcd, abcd);"); editor.remove('left'); editor.remove('left'); @@ -70,7 +70,7 @@ module.exports = { new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(2, 0); - editor.insert('b'); + editor.insertText('b'); assert.equal(session.doc.getValue(), "var a = 10;\nconsole.log(a, a);\nb"); }, @@ -81,12 +81,12 @@ module.exports = { var p = new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(0, 4); - editor.insert('$'); + editor.insertText('$'); assert.equal(session.doc.getValue(), "var $a = 10;\nconsole.log($a, $a);"); editor.moveCursorTo(0, 4); // Have to put this in a setTimeout because the anchor is only fixed later. setTimeout(function() { - editor.insert('v'); + editor.insertText('v'); assert.equal(session.doc.getValue(), "var v$a = 10;\nconsole.log(v$a, v$a);"); next(); }, 10); @@ -99,10 +99,10 @@ module.exports = { var p = new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(0, 5); - editor.insert('b'); + editor.insertText('b'); assert.equal(session.doc.getValue(), "var ab = 10;\nconsole.log(ab, ab);"); p.detach(); - editor.insert('cd'); + editor.insertText('cd'); assert.equal(session.doc.getValue(), "var abcd = 10;\nconsole.log(ab, ab);"); }, @@ -136,8 +136,8 @@ module.exports = { var p = new PlaceHolder(session, 1, {row: 0, column: 4}, [{row: 1, column: 12}, {row: 1, column: 15}]); editor.moveCursorTo(0, 5); - editor.insert('b'); - editor.insert('cd'); + editor.insertText('b'); + editor.insertText('cd'); editor.remove('left'); assert.equal(session.doc.getValue(), "var abc = 10;\nconsole.log(abc, abc);"); // Wait a little for the changes to enter the undo stack