diff --git a/lib/ace/document.js b/lib/ace/document.js index 99a76fc4..0e6258a4 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -38,7 +38,6 @@ define(function(require, exports, module) { var oop = require("pilot/oop"); -var lang = require("pilot/lang"); var EventEmitter = require("pilot/event_emitter").EventEmitter; var Range = require("ace/range").Range; @@ -143,10 +142,21 @@ var Document = function(text) { } }; + this.$clipPosition = function(position) { + var length = this.$lines.length; + if (position.row >= length) { + position.row = Math.max(0, length - 1); + position.column = this.getLine(length-1).length; + } + return position; + } + this.insert = function(position, text) { if (text.length == 0) return position; - + + position = this.$clipPosition(position); + if (this.$lines.length <= 1) { this.$detectNewLine(text); } @@ -160,7 +170,8 @@ var Document = function(text) { var end = this.insertInLine(position, text); } else { - this.insertInLine(position, newLines[0]); + var end = this.insertInLine(position, newLines[0]); + this.insertNewLine(end); if (newLines.length > 2) this.insertLines(position.row+1, newLines.slice(1, newLines.length-1)); @@ -173,24 +184,23 @@ var Document = function(text) { this.insertLines = function(row, lines) { if (lines.length == 0) return {row: row, column: 0}; - + var args = [row, 0]; args.push.apply(args, lines); this.$lines.splice.apply(this.$lines, args); - var range = new Range(row, 0, row + lines.length, 0); + var range = new Range(row, 0, row + lines.length - 1, 0); var delta = { action: "insertLines", - nl: this.getNewLineCharacter(), range: range, lines: lines }; - this._dispatchEvent("changeDelta", { data: delta }); + this._dispatchEvent("change", { data: delta }); return range.end; }, this.insertNewLine = function(position) { - console.log(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)); @@ -205,12 +215,15 @@ var Document = function(text) { range: Range.fromPoints(position, end), text: this.getNewLineCharacter() }; - this._dispatchEvent("changeDelta", { data: delta }); + this._dispatchEvent("change", { data: delta }); return end; }; 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); @@ -225,18 +238,23 @@ var Document = function(text) { range: Range.fromPoints(position, end), text: text }; - this._dispatchEvent("changeDelta", { data: delta }); + this._dispatchEvent("change", { data: delta }); return end; }; this.remove = function(range) { + // clip to document + range.start = this.$clipPosition(range.start); + range.end = this.$clipPosition(range.end); + if (range.isEmpty()) - return range.start; + return; + + var firstRow = range.start.row; + var lastRow = range.end.row; if (range.isMultiLine()) { - var firstRow = range.start.row; - var lastRow = range.end.row; // TODO removeInLine can be optimized away! this.removeInLine(lastRow, 0, range.end.column); @@ -246,13 +264,16 @@ var Document = function(text) { this.removeNewLine(range.start.row); } else { - this.removeInLine(range) + this.removeInLine(firstRow, range.start.column, range.end.column); } }; this.removeInLine = function(row, startColumn, endColumn) { + if (startColumn == endColumn) + return; + var range = new Range(row, startColumn, row, endColumn); - var line = this.$lines[row]; + 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); @@ -262,6 +283,7 @@ var Document = function(text) { range: range, text: removed }; + this._dispatchEvent("change", { data: delta }); return range.start; }; @@ -275,7 +297,7 @@ var Document = function(text) { nl: this.getNewLineCharacter(), lines: removed }; - this._dispatchEvent("changeDelta", { data: delta }); + this._dispatchEvent("change", { data: delta }); }; this.removeNewLine = function(row) { @@ -292,7 +314,7 @@ var Document = function(text) { range: range, text: this.getNewLineCharacter() }; - this._dispatchEvent("changeDelta", { data: delta }); + this._dispatchEvent("change", { data: delta }); }; this.replace = function(range, text) { @@ -316,6 +338,38 @@ var Document = function(text) { return end; }; + + this.applyDeltas = function(deltas) { + for (var i=0; i=0; i--) { + var delta = deltas[i]; + var range = delta.range; + + if (delta.action == "insertLines") + this.removeLines(range.start.row, range.end.row) + 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) + } + }; }).call(Document.prototype); diff --git a/lib/ace/test/document_test.js b/lib/ace/test/document_test.js index 9076a7fd..5fc27ec3 100644 --- a/lib/ace/test/document_test.js +++ b/lib/ace/test/document_test.js @@ -42,9 +42,198 @@ var Document = require("../document").Document, var Test = { + "test: insert text in line" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insert({row: 0, column: 1}, "juhu"); + assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n")); + }, + + "test: insert new line" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insertNewLine({row: 0, column: 1}); + assert.equal(doc.getValue(), ["1", "2", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["1", "2", "34"].join("\n")); + }, + + "test: insert lines at the beginning" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insertLines(0, ["aa", "bb"]); + assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n")); + }, + + "test: insert lines at the end" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insertLines(2, ["aa", "bb"]); + assert.equal(doc.getValue(), ["12", "34", "aa", "bb"].join("\n")); + }, + + "test: insert lines in the middle" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insertLines(1, ["aa", "bb"]); + assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n")); + }, + + "test: insert multi line string at the start" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insert({row: 0, column: 0}, "aa\nbb\ncc"); + assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n")); + }, + + "test: insert multi line string at the end" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insert({row: 2, column: 0}, "aa\nbb\ncc"); + assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n")); + }, + + "test: insert multi line string in the middle" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.insert({row: 0, column: 1}, "aa\nbb\ncc"); + assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n")); + }, + + "test: delete in line" : function() { + var doc = new Document(["1234", "5678"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.remove(new Range(0, 1, 0, 3)); + assert.equal(doc.getValue(), ["14", "5678"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["1234", "5678"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["14", "5678"].join("\n")); + }, + + "test: delete new line" : function() { + var doc = new Document(["1234", "5678"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.remove(new Range(0, 4, 1, 0)); + assert.equal(doc.getValue(), ["12345678"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["1234", "5678"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12345678"].join("\n")); + }, + + "test: delete multi line range line" : function() { + var doc = new Document(["1234", "5678", "abcd"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.remove(new Range(0, 2, 2, 2)); + assert.equal(doc.getValue(), ["12cd"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["1234", "5678", "abcd"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12cd"].join("\n")); + }, + + "test: delete full lines" : function() { + var doc = new Document(["1234", "5678", "abcd"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e.data); }); + + doc.remove(new Range(1, 0, 3, 0)); + assert.equal(doc.getValue(), ["1234", ""].join("\n")); + }, + "test: should handle unix style new lines" : function() { var doc = new Document(["1", "2", "3"]); - assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); },