From cc0c16ca6fb76582825bbc996bb7cd84855c2b0a Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Tue, 4 May 2010 11:34:38 +0200 Subject: [PATCH] Refactor: replace range map with a proper object --- demo/editor.html | 1 + src/ace/Document.js | 37 ++++----------- src/ace/Editor.js | 47 +++--------------- src/ace/Range.js | 65 +++++++++++++++++++++++++ src/ace/Search.js | 12 +---- src/ace/Selection.js | 13 ++--- src/ace/layer/Marker.js | 37 ++------------- src/ace/mode/MatchingBraceOutdent.js | 13 +---- src/test/DocumentTest.js | 30 ++++++++++-- src/test/RangeTest.js | 71 ++++++++++++++++++++++++++++ 10 files changed, 187 insertions(+), 139 deletions(-) create mode 100644 src/ace/Range.js create mode 100644 src/test/RangeTest.js diff --git a/demo/editor.html b/demo/editor.html index fd5b8c18..35dd4d1e 100644 --- a/demo/editor.html +++ b/demo/editor.html @@ -59,6 +59,7 @@ + diff --git a/src/ace/Document.js b/src/ace/Document.js index 6bc91f7c..2df8ae7b 100644 --- a/src/ace/Document.js +++ b/src/ace/Document.js @@ -312,16 +312,7 @@ ace.Document = function(text, mode) { var nl = this.$getNewLineCharacter(); this.$deltas.push({ type: "insert", - range: { - start: { - row: row, - column: 0 - }, - end: { - row: row + lines.length, - column: 0 - } - }, + range: new ace.Range(row, 0, row + lines.length, 0), text: lines.join(nl) + nl }); this.$informUndoManager.schedule(); @@ -378,10 +369,7 @@ ace.Document = function(text, mode) { var nl = this.$getNewLineCharacter(); this.$deltas.push({ type: "insert", - range: { - start: ace.copyObject(position), - end: ace.copyObject(end) - }, + range: ace.Range.fromPoints(position, end), text: text }); this.$informUndoManager.schedule(); @@ -398,7 +386,7 @@ ace.Document = function(text, mode) { this.$remove(range, fromUndo); this.fireChangeEvent(range.start.row, - range.end.row == range.start.row ? range.start.row + !range.isMultiLine() ? range.start.row : undefined); return range.start; @@ -409,10 +397,7 @@ ace.Document = function(text, mode) { var nl = this.$getNewLineCharacter(); this.$deltas.push({ type: "remove", - range: { - start: ace.copyObject(range.start), - end: ace.copyObject(range.end) - }, + range: range.clone(), text: this.getTextRange(range) }); this.$informUndoManager.schedule(); @@ -423,8 +408,8 @@ ace.Document = function(text, mode) { var firstRow = range.start.row; var lastRow = range.end.row; - var row = this.lines[firstRow].substring(0, range.start.column) - + this.lines[lastRow].substring(range.end.column); + var row = this.getLine(firstRow).substring(0, range.start.column) + + this.getLine(lastRow).substring(range.end.column); this.lines.splice(firstRow, lastRow - firstRow + 1, row); @@ -438,6 +423,7 @@ ace.Document = function(text, mode) { var delta = deltas[i]; if (delta.type == "insert") { this.remove(delta.range, true); + this.selection.clearSelection(); this.selection.moveCursorToPosition(delta.range.start); } else { this.insert(delta.range.start, delta.text, true); @@ -494,14 +480,7 @@ ace.Document = function(text, mode) { } } - var deleteRange = { - start: { - column: 0 - }, - end: { - column: outdentLength - } - }; + var deleteRange = new ace.Range(0, 0, 0, outdentLength); for (var i=range.start.row; i<= range.end.row; i++) { diff --git a/src/ace/Editor.js b/src/ace/Editor.js index 9fabcf60..49362563 100644 --- a/src/ace/Editor.js +++ b/src/ace/Editor.js @@ -107,13 +107,7 @@ ace.Editor = function(renderer, doc) { var pos = self.doc.findMatchingBracket(self.getCursorPosition()); if (pos) { - range = { - start: pos, - end: { - row: pos.row, - column: pos.column+1 - } - }; + range = new ace.Range(pos.row, pos.column, pos.row, pos.column=1); self.$bracketHighlight = self.renderer.addMarker(range, "bracket"); } }, 10); @@ -166,16 +160,7 @@ ace.Editor = function(renderer, doc) { if (this.getHighlightActiveLine() && !this.selection.isMultiLine()) { var cursor = this.getCursorPosition(); - var range = { - start: { - row: cursor.row, - column: 0 - }, - end: { - row: cursor.row+1, - column: 0 - } - }; + var range = new ace.Range(cursor.row, 0, cursor.row+1, 0); this.$highlightLineMarker = this.renderer.addMarker(range, "active_line", "line"); } }; @@ -296,13 +281,8 @@ ace.Editor = function(renderer, doc) { var cursor = this.doc.remove(this.getSelectionRange()); this.clearSelection(); } else if (this.$overwrite){ - var range = { - start: cursor, - end: { - row: cursor.row, - column: cursor.column + text.length - } - }; + var range = new ace.Range.fromPoints(cursor, cursor); + range.end.column += text.length; this.doc.remove(range); } @@ -321,13 +301,7 @@ ace.Editor = function(renderer, doc) { if (row !== end.row) { var indent = this.mode.getNextLineIndent(lineState, line, this.doc.getTabString()); if (indent) { - var indentRange = { - start: { - row: row+1, - column: 0 - }, - end : end - }; + var indentRange = new ace.Range(row+1, 0, end.row, end.column); end.column += this.doc.indentRows(indentRange, indent); } } else { @@ -454,16 +428,7 @@ ace.Editor = function(renderer, doc) { var rows = this.$getSelectedRows(); - var range = { - start: { - row: rows.first, - column: 0 - }, - end: { - row: rows.last, - column: 0 - } - }; + var range = new ace.Range(rows.first, 0, rows.last, 0); var state = this.bgTokenizer.getState(this.getCursorPosition().row); var addedColumns = this.mode.toggleCommentLines(state, this.doc, range); diff --git a/src/ace/Range.js b/src/ace/Range.js new file mode 100644 index 00000000..43418cc9 --- /dev/null +++ b/src/ace/Range.js @@ -0,0 +1,65 @@ +ace.provide("ace.Range"); + +ace.Range = function(startRow, startColumn, endRow, endColumn) { + this.start = { + row: startRow, + column: startColumn + }; + + this.end = { + row: endRow, + column: endColumn + }; +}; + +(function() { + + this.clipRows = function(firstRow, lastRow) { + if (this.end.row > lastRow) { + this.end = { + row: lastRow+1, + column: 0 + }; + } + + if (this.start.row > lastRow) { + this.start = { + row: lastRow+1, + column: 0 + }; + } + + if (this.start.row < firstRow) { + this.start = { + row: firstRow, + column: 0 + }; + } + + if (this.end.row < firstRow) { + this.end = { + row: firstRow, + column: 0 + }; + } + return this; + }; + + this.isEmpty = function() { + return (this.start.row == this.end.row && this.start.column == this.end.column); + }; + + this.isMultiLine = function() { + return (this.start.row !== this.end.row); + }; + + this.clone = function() { + return ace.Range.fromPoints(this.start, this.end); + }; + +}).call(ace.Range.prototype); + + +ace.Range.fromPoints = function(start, end) { + return new ace.Range(start.row, start.column, end.row, end.column); +}; \ No newline at end of file diff --git a/src/ace/Search.js b/src/ace/Search.js index 5c4c97dc..d14dd3f8 100644 --- a/src/ace/Search.js +++ b/src/ace/Search.js @@ -142,17 +142,7 @@ ace.Search.SELECTION = 2; this.$rangeFromMatch = function(row, column, length) { - var range = { - start: { - row: row, - column: column - }, - end: { - row: row, - column: column + length - } - }; - return range; + return new ace.Range(row, column, row, column+length); }; this.$assembleRegExp = function() { diff --git a/src/ace/Selection.js b/src/ace/Selection.js index a3cd5be8..6d68825b 100644 --- a/src/ace/Selection.js +++ b/src/ace/Selection.js @@ -27,8 +27,7 @@ ace.Selection = function(doc) { return false; } - var range = this.getRange(); - return (range.start.row !== range.end.row); + return this.getRange().isMultiLine(); }; this.getCursor = function() { @@ -73,16 +72,10 @@ ace.Selection = function(doc) { if (anchor.row > lead.row || (anchor.row == lead.row && anchor.column > lead.column)) { - return { - start : lead, - end : anchor - }; + return ace.Range.fromPoints(lead, anchor); } else { - return { - start : anchor, - end : lead - }; + return ace.Range.fromPoints(anchor, lead); } }; diff --git a/src/ace/layer/Marker.js b/src/ace/layer/Marker.js index 6c129b1a..51b9c9d9 100644 --- a/src/ace/layer/Marker.js +++ b/src/ace/layer/Marker.js @@ -45,30 +45,11 @@ ace.layer.Marker = function(parentEl) { var html = []; for ( var key in this.markers) { var marker = this.markers[key]; - var range = { - start: marker.range.start, - end: marker.range.end - }; - // clip - if (range.start.row > config.lastRow) continue; - if (range.end.row < config.firstRow) continue; + var range = marker.range.clone().clipRows(config.firstRow, config.lastRow); + if (range.isEmpty()) continue; - if (range.end.row > config.lastRow) { - range.end = { - row: config.lastRow+1, - column: 0 - }; - } - - if (range.start.row < config.firstRow) { - range.start = { - row: config.firstRow, - column: 0 - }; - } - - if (range.start.row !== range.end.row) { + if (range.isMultiLine()) { if (marker.type == "text") { this.drawTextMarker(html, range, marker.clazz, config); } else { @@ -86,20 +67,12 @@ ace.layer.Marker = function(parentEl) { // selection start var row = range.start.row; - var lineRange = { start: {}, end: {}}; - - lineRange.start.row = row; - lineRange.start.column = range.start.column; - lineRange.end.row = row; - lineRange.end.column = this.doc.getLine(row).length; + var lineRange = new ace.Range(row, range.start.column, row, this.doc.getLine(row).length); this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig); // selection end var row = range.end.row; - lineRange.start.row = row; - lineRange.start.column = 0; - lineRange.end.row = row; - lineRange.end.column = range.end.column; + var lineRange = new ace.Range(row, 0, row, range.end.column); this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig); for (var row = range.start.row + 1; row < range.end.row; row++) { diff --git a/src/ace/mode/MatchingBraceOutdent.js b/src/ace/mode/MatchingBraceOutdent.js index 5c6e5d0b..62cf8954 100644 --- a/src/ace/mode/MatchingBraceOutdent.js +++ b/src/ace/mode/MatchingBraceOutdent.js @@ -23,18 +23,7 @@ ace.mode.MatchingBraceOutdent = function() {}; if (!openBracePos || openBracePos.row == row) return 0; var indent = this.$getIndent(doc.getLine(openBracePos.row)); - - var range = { - start: { - row: row, - column: 0 - }, - end: { - row: row, - column: column-1 - } - }; - doc.replace(range, indent); + doc.replace(new ace.Range(row, 0, row, column-1), indent); return indent.length - (column-1); }; diff --git a/src/test/DocumentTest.js b/src/test/DocumentTest.js index 08067696..9d788384 100644 --- a/src/test/DocumentTest.js +++ b/src/test/DocumentTest.js @@ -135,15 +135,37 @@ var TextDocumentTest = new TestCase("TextDocumentTest", { var editor = new ace.Editor(new MockRenderer(), doc); editor.removeLines(); - var removedText = doc.toString(); - + var step1 = doc.toString(); + assertEquals("222\n333", step1); // call normally async code now doc.$informUndoManager.call(); + editor.removeLines(); + var step2 = doc.toString(); + assertEquals("333", step2); + // call normally async code now + doc.$informUndoManager.call(); + + editor.removeLines(); + var step3 = doc.toString(); + assertEquals("", step3); + // call normally async code now + doc.$informUndoManager.call(); + + + undoManager.undo(); + assertEquals(step2, doc.toString()); + + undoManager.undo(); + assertEquals(step1, doc.toString()); + undoManager.undo(); assertEquals(initialText, doc.toString()); - undoManager.redo(); - assertEquals(removedText, doc.toString()); + undoManager.undo(); + assertEquals(initialText, doc.toString()); + +// undoManager.redo(); +// assertEquals(removedText, doc.toString()); } }); \ No newline at end of file diff --git a/src/test/RangeTest.js b/src/test/RangeTest.js new file mode 100644 index 00000000..39eb41fd --- /dev/null +++ b/src/test/RangeTest.js @@ -0,0 +1,71 @@ +RangeTest = new TestCase("RangeTest", { + + "test: create range": function() { + var range = new ace.Range(1,2,3,4); + + assertEquals(1, range.start.row); + assertEquals(2, range.start.column); + assertEquals(3, range.end.row); + assertEquals(4, range.end.column); + }, + + "test: create from points": function() { + var range = ace.Range.fromPoints({row: 1, column: 2}, {row:3, column:4}); + + assertEquals(1, range.start.row); + assertEquals(2, range.start.column); + assertEquals(3, range.end.row); + assertEquals(4, range.end.column); + }, + + "test: clip to rows": function() { + var range = new ace.Range(0, 20, 100, 30); + range.clipRows(10, 30); + + assertPosition(10, 0, range.start); + assertPosition(31, 0, range.end); + + var range = new ace.Range(0, 20, 30, 10); + range.clipRows(10, 30); + + assertPosition(10, 0, range.start); + assertPosition(30, 10, range.end); + + var range = new ace.Range(0, 20, 3, 10); + range.clipRows(10, 30); + + assertTrue(range.isEmpty()); + assertPosition(10, 0, range.start); + assertPosition(10, 0, range.end); + }, + + "test: isEmpty": function() { + var range = new ace.Range(1, 2, 1, 2); + assertTrue(range.isEmpty()); + + var range = new ace.Range(1, 2, 1, 6); + assertFalse(range.isEmpty()); + }, + + "test: is multi line": function() { + var range = new ace.Range(1, 2, 1, 6); + assertFalse(range.isMultiLine()); + + var range = new ace.Range(1, 2, 2, 6); + assertTrue(range.isMultiLine()); + }, + + "test: clone": function() { + var range = new ace.Range(1, 2, 3, 4); + var clone = range.clone(); + + assertPosition(1, 2, clone.start); + assertPosition(3, 4, clone.end); + + clone.start.column = 20; + assertPosition(1, 2, range.start); + + clone.end.column = 20; + assertPosition(3, 4, range.end); + } +}); \ No newline at end of file