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