Remember Column during navigation

This commit is contained in:
Fabian Jakobs 2010-05-17 17:58:26 +02:00
commit 1d7ed0d3dd
6 changed files with 174 additions and 126 deletions

View file

@ -562,4 +562,51 @@ ace.Document = function(text, mode) {
return Math.max(0, Math.min(row, this.lines.length-1));
};
this.documentToScreenColumn = function(row, docColumn) {
var tabSize = this.getTabSize();
var screenColumn = 0;
var remaining = docColumn;
var line = this.getLine(row).split("\t");
for (var i=0; i<line.length; i++) {
var len = line[i].length;
if (remaining > len) {
remaining -= (len + 1);
screenColumn += len + tabSize;
}
else {
screenColumn += remaining;
break;
}
}
return screenColumn;
};
this.screenToDocumentColumn = function(row, screenColumn) {
var tabSize = this.getTabSize();
var docColumn = 0;
var remaining = screenColumn;
var line = this.getLine(row).split("\t");
for (var i=0; i<line.length; i++) {
var len = line[i].length;
if (remaining >= len + tabSize) {
remaining -= (len + tabSize);
docColumn += (len + 1);
}
else if (remaining > len){
docColumn += len;
break;
}
else {
docColumn += remaining;
break;
}
}
return docColumn;
};
}).call(ace.Document.prototype);

View file

@ -93,6 +93,7 @@ ace.Editor = function(renderer, doc) {
this.doc.addEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
this.selection = doc.getSelection();
this.$desiredColumn = 0;
this.$onCursorChange = ace.bind(this.onCursorChange, this);
this.selection.addEventListener("changeCursor", this.$onCursorChange);
@ -279,10 +280,12 @@ ace.Editor = function(renderer, doc) {
this.onMouseDoubleClick = function(e) {
this.selection.selectWord();
this.$updateDesiredColumn();
};
this.onMouseTripleClick = function(e) {
this.selection.selectLine();
this.$updateDesiredColumn();
};
this.onMouseWheel = function(e) {
@ -467,6 +470,7 @@ ace.Editor = function(renderer, doc) {
var addedColumns = this.doc.indentRows(this.getSelectionRange(), indentString);
this.selection.shiftSelection(addedColumns);
this.$updateDesiredColumn();
};
this.blockOutdent = function(indentString) {
@ -477,6 +481,7 @@ ace.Editor = function(renderer, doc) {
var addedColumns = this.doc.outdentRows(this.getSelectionRange(), indentString);
this.selection.shiftSelection(addedColumns);
this.$updateDesiredColumn();
};
this.toggleCommentLines = function() {
@ -656,14 +661,17 @@ ace.Editor = function(renderer, doc) {
this.clearSelection = function() {
this.selection.clearSelection();
this.$updateDesiredColumn();
};
this.moveCursorTo = function(row, column) {
this.selection.moveCursorTo(row, column);
this.$updateDesiredColumn();
};
this.moveCursorToPosition = function(pos) {
this.selection.moveCursorToPosition(pos);
this.$updateDesiredColumn();
};
@ -680,16 +688,34 @@ ace.Editor = function(renderer, doc) {
this.navigateTo = function(row, column) {
this.clearSelection();
this.moveCursorTo(row, column);
this.$updateDesiredColumn(column);
};
this.navigateUp = function() {
this.clearSelection();
this.selection.moveCursorUp();
this.selection.clearSelection();
this.selection.moveCursorBy(-1, 0);
if (this.$desiredColumn) {
var cursor = this.getCursorPosition();
var column = this.doc.screenToDocumentColumn(cursor.row, this.$desiredColumn);
this.selection.moveCursorTo(cursor.row, column);
}
};
this.navigateDown = function() {
this.clearSelection();
this.selection.moveCursorDown();
this.selection.clearSelection();
this.selection.moveCursorBy(1, 0);
if (this.$desiredColumn) {
var cursor = this.getCursorPosition();
var column = this.doc.screenToDocumentColumn(cursor.row, this.$desiredColumn);
this.selection.moveCursorTo(cursor.row, column);
}
};
this.$updateDesiredColumn = function() {
var cursor = this.getCursorPosition();
this.$desiredColumn = this.doc.documentToScreenColumn(cursor.row, cursor.column);
};
this.navigateLeft = function() {
@ -715,39 +741,40 @@ ace.Editor = function(renderer, doc) {
};
this.navigateLineStart = function() {
this.clearSelection();
this.selection.moveCursorLineStart();
this.clearSelection();
};
this.navigateLineEnd = function() {
this.clearSelection();
this.selection.moveCursorLineEnd();
this.clearSelection();
};
this.navigateFileEnd = function() {
this.clearSelection();
this.selection.moveCursorFileEnd();
this.clearSelection();
};
this.navigateFileStart = function() {
this.clearSelection();
this.selection.moveCursorFileStart();
this.clearSelection();
};
this.navigateWordRight = function() {
this.clearSelection();
this.selection.moveCursorWordRight();
this.clearSelection();
};
this.navigateWordLeft = function() {
this.clearSelection();
this.selection.moveCursorWordLeft();
this.clearSelection();
};
this.replace = function(replacement) {
var range = this.$tryReplace(this.getSelectionRange(), replacement);
if (range !== null)
this.selection.setSelectionRange(range);
this.$updateDesiredColumn();
},
this.replaceAll = function(replacement) {
@ -763,6 +790,7 @@ ace.Editor = function(renderer, doc) {
this.$tryReplace(range, replacement);
}
this.selection.setSelectionRange(range);
this.$updateDesiredColumn();
},
this.$tryReplace = function(range, replacement) {
@ -800,8 +828,10 @@ ace.Editor = function(renderer, doc) {
});
var range = this.$search.find(this.doc);
if (range)
if (range) {
this.selection.setSelectionRange(range);
this.$updateDesiredColumn();
}
};
this.undo = function() {

View file

@ -250,57 +250,10 @@ ace.VirtualRenderer = function(container) {
this.$documentToScreenPosition = function(pos) {
return {
row: pos.row,
column: this.$documentToScreenColumn(pos.row, pos.column)
column: this.doc.documentToScreenColumn(pos.row, pos.column)
};
};
this.$documentToScreenColumn = function(row, docColumn) {
var tabSize = this.doc.getTabSize();
var screenColumn = 0;
var remaining = docColumn;
var line = this.doc.getLine(row).split("\t");
for (var i=0; i<line.length; i++) {
var len = line[i].length;
if (remaining > len) {
remaining -= (len + 1);
screenColumn += len + tabSize;
}
else {
screenColumn += remaining;
break;
}
}
return screenColumn;
};
this.$screenToDocumentColumn = function(row, screenColumn) {
var tabSize = this.doc.getTabSize();
var docColumn = 0;
var remaining = screenColumn;
var line = this.doc.getLine(row).split("\t");
for (var i=0; i<line.length; i++) {
var len = line[i].length;
if (remaining >= len + tabSize) {
remaining -= (len + tabSize);
docColumn += (len + 1);
}
else if (remaining > len){
docColumn += len;
break;
}
else {
docColumn += remaining;
break;
}
}
return docColumn;
};
this.hideCursor = function() {
this.$cursorLayer.hideCursor();
};
@ -369,7 +322,7 @@ ace.VirtualRenderer = function(container) {
return {
row : row,
column : this.$screenToDocumentColumn(Math.max(0, Math.min(row, this.doc.getLength()-1)), col)
column : this.doc.screenToDocumentColumn(Math.max(0, Math.min(row, this.doc.getLength()-1)), col)
};
};

View file

@ -162,5 +162,51 @@ var TextDocumentTest = new TestCase("TextDocumentTest", {
undoManager.undo();
doc.$informUndoManager.call();
assertEquals(initialText, doc.toString());
},
"test: convert document to screen coordinates" : function() {
var doc = new ace.Document("01234\t567890\t1234");
doc.setTabSize(4);
assertEquals(0, doc.documentToScreenColumn(0, 0));
assertEquals(4, doc.documentToScreenColumn(0, 4));
assertEquals(5, doc.documentToScreenColumn(0, 5));
assertEquals(9, doc.documentToScreenColumn(0, 6));
assertEquals(15, doc.documentToScreenColumn(0, 12));
assertEquals(19, doc.documentToScreenColumn(0, 13));
doc.setTabSize(2);
assertEquals(0, doc.documentToScreenColumn(0, 0));
assertEquals(4, doc.documentToScreenColumn(0, 4));
assertEquals(5, doc.documentToScreenColumn(0, 5));
assertEquals(7, doc.documentToScreenColumn(0, 6));
assertEquals(13, doc.documentToScreenColumn(0, 12));
assertEquals(15, doc.documentToScreenColumn(0, 13));
},
"test: convert document to scrren coordinates with leading tabs": function() {
var doc = new ace.Document("\t\t123");
doc.setTabSize(4);
assertEquals(0, doc.documentToScreenColumn(0, 0));
assertEquals(4, doc.documentToScreenColumn(0, 1));
assertEquals(8, doc.documentToScreenColumn(0, 2));
assertEquals(9, doc.documentToScreenColumn(0, 3));
},
"test: convert screen to document coordinates" : function() {
var doc = new ace.Document("01234\t567890\t1234");
doc.setTabSize(4);
assertEquals(0, doc.screenToDocumentColumn(0, 0));
assertEquals(4, doc.screenToDocumentColumn(0, 4));
assertEquals(5, doc.screenToDocumentColumn(0, 5));
assertEquals(5, doc.screenToDocumentColumn(0, 6));
assertEquals(5, doc.screenToDocumentColumn(0, 7));
assertEquals(5, doc.screenToDocumentColumn(0, 8));
assertEquals(6, doc.screenToDocumentColumn(0, 9));
assertEquals(12, doc.screenToDocumentColumn(0, 15));
assertEquals(13, doc.screenToDocumentColumn(0, 19));
}
});

View file

@ -11,7 +11,7 @@ var NavigationTest = TestCase("NavigationTest",
var editor = new ace.Editor(new MockRenderer(), doc);
editor.navigateFileEnd();
var cursor = editor.getSelection().getCursor();
var cursor = editor.getCursorPosition();
assertTrue(editor.getFirstVisibleRow() <= cursor.row);
assertTrue(editor.getLastVisibleRow() >= cursor.row);
@ -32,32 +32,32 @@ var NavigationTest = TestCase("NavigationTest",
editor.navigateTo(0, 0);
editor.gotoLine(101);
assertPosition(100, 0, editor.getSelection().getCursor());
assertPosition(100, 0, editor.getCursorPosition());
assertEquals(90, editor.getFirstVisibleRow());
editor.navigateTo(100, 0);
editor.gotoLine(11);
assertPosition(10, 0, editor.getSelection().getCursor());
assertPosition(10, 0, editor.getCursorPosition());
assertEquals(0, editor.getFirstVisibleRow());
editor.navigateTo(100, 0);
editor.gotoLine(6);
assertPosition(5, 0, editor.getSelection().getCursor());
assertPosition(5, 0, editor.getCursorPosition());
assertEquals(0, editor.getFirstVisibleRow());
editor.navigateTo(100, 0);
editor.gotoLine(1);
assertPosition(0, 0, editor.getSelection().getCursor());
assertPosition(0, 0, editor.getCursorPosition());
assertEquals(0, editor.getFirstVisibleRow());
editor.navigateTo(0, 0);
editor.gotoLine(191);
assertPosition(190, 0, editor.getSelection().getCursor());
assertPosition(190, 0, editor.getCursorPosition());
assertEquals(180, editor.getFirstVisibleRow());
editor.navigateTo(0, 0);
editor.gotoLine(196);
assertPosition(195, 0, editor.getSelection().getCursor());
assertPosition(195, 0, editor.getCursorPosition());
assertEquals(180, editor.getFirstVisibleRow());
},
@ -66,12 +66,41 @@ var NavigationTest = TestCase("NavigationTest",
editor.navigateTo(0, 0);
editor.gotoLine(12);
assertPosition(11, 0, editor.getSelection().getCursor());
assertPosition(11, 0, editor.getCursorPosition());
assertEquals(0, editor.getFirstVisibleRow());
editor.navigateTo(30, 0);
editor.gotoLine(33);
assertPosition(32, 0, editor.getSelection().getCursor());
assertPosition(32, 0, editor.getCursorPosition());
assertEquals(30, editor.getFirstVisibleRow());
},
"test: navigate from the end of a long line down to a short line and back should maintain the curser column": function() {
var editor = new ace.Editor(new MockRenderer(), new ace.Document(["123456", "1"]));
editor.navigateTo(0, 6);
assertPosition(0, 6, editor.getCursorPosition());
editor.navigateDown();
assertPosition(1, 1, editor.getCursorPosition());
editor.navigateUp();
assertPosition(0, 6, editor.getCursorPosition());
},
"test: reset desired column on navigate left or right": function() {
var editor = new ace.Editor(new MockRenderer(), new ace.Document(["123456", "12"]));
editor.navigateTo(0, 6);
assertPosition(0, 6, editor.getCursorPosition());
editor.navigateDown();
assertPosition(1, 2, editor.getCursorPosition());
editor.navigateLeft();
assertPosition(1, 1, editor.getCursorPosition());
editor.navigateUp();
assertPosition(0, 1, editor.getCursorPosition());
}
});

View file

@ -1,62 +1,5 @@
var VirtualRendererTest = new TestCase("VirtualRendererTest", {
"test: convert document to screen coordinates" : function() {
var el = document.createElement("div");
var renderer = new ace.VirtualRenderer(el);
var doc = new ace.Document("01234\t567890\t1234");
doc.setTabSize(4);
renderer.setDocument(doc);
assertEquals(0, renderer.$documentToScreenColumn(0, 0));
assertEquals(4, renderer.$documentToScreenColumn(0, 4));
assertEquals(5, renderer.$documentToScreenColumn(0, 5));
assertEquals(9, renderer.$documentToScreenColumn(0, 6));
assertEquals(15, renderer.$documentToScreenColumn(0, 12));
assertEquals(19, renderer.$documentToScreenColumn(0, 13));
doc.setTabSize(2);
assertEquals(0, renderer.$documentToScreenColumn(0, 0));
assertEquals(4, renderer.$documentToScreenColumn(0, 4));
assertEquals(5, renderer.$documentToScreenColumn(0, 5));
assertEquals(7, renderer.$documentToScreenColumn(0, 6));
assertEquals(13, renderer.$documentToScreenColumn(0, 12));
assertEquals(15, renderer.$documentToScreenColumn(0, 13));
},
"test: convert document to scrren coordinates with leading tabs": function() {
var el = document.createElement("div");
var renderer = new ace.VirtualRenderer(el);
var doc = new ace.Document("\t\t123");
doc.setTabSize(4);
renderer.setDocument(doc);
assertEquals(0, renderer.$documentToScreenColumn(0, 0));
assertEquals(4, renderer.$documentToScreenColumn(0, 1));
assertEquals(8, renderer.$documentToScreenColumn(0, 2));
assertEquals(9, renderer.$documentToScreenColumn(0, 3));
},
"test: convert screen to document coordinates" : function() {
var el = document.createElement("div");
var renderer = new ace.VirtualRenderer(el);
var doc = new ace.Document("01234\t567890\t1234");
doc.setTabSize(4);
renderer.setDocument(doc);
assertEquals(0, renderer.$screenToDocumentColumn(0, 0));
assertEquals(4, renderer.$screenToDocumentColumn(0, 4));
assertEquals(5, renderer.$screenToDocumentColumn(0, 5));
assertEquals(5, renderer.$screenToDocumentColumn(0, 6));
assertEquals(5, renderer.$screenToDocumentColumn(0, 7));
assertEquals(5, renderer.$screenToDocumentColumn(0, 8));
assertEquals(6, renderer.$screenToDocumentColumn(0, 9));
assertEquals(12, renderer.$screenToDocumentColumn(0, 15));
assertEquals(13, renderer.$screenToDocumentColumn(0, 19));
},
"test: screen2text the column should be rounded to the next character edge" : function() {
var el = document.createElement("div");
el.style.left = "0px";