refactor selection to use anchors

This commit is contained in:
Fabian Jakobs 2011-02-11 08:10:44 +01:00
commit b74a322c7d
2 changed files with 95 additions and 152 deletions

View file

@ -578,8 +578,7 @@ var Editor =function(renderer, session) {
if (range.start.row < range.end.row || range.start.column < range.end.column) { if (range.start.row < range.end.row || range.start.column < range.end.column) {
var rows = this.$getSelectedRows(); var rows = this.$getSelectedRows();
var count = session.indentRows(rows.first, rows.last, "\t"); var count = session.indentRows(rows.first, rows.last, "\t");
// TODO remove count from indent
this.selection.shiftSelection(count);
} else { } else {
var indentString; var indentString;
@ -602,8 +601,8 @@ var Editor =function(renderer, session) {
var selection = this.session.getSelection(); var selection = this.session.getSelection();
var range = this.session.outdentRows(selection.getRange()); var range = this.session.outdentRows(selection.getRange());
// TODO remove range from outdent
selection.setSelectionRange(range, selection.isBackwards()); //selection.setSelectionRange(range, selection.isBackwards());
}; };
this.toggleCommentLines = function() { this.toggleCommentLines = function() {
@ -613,7 +612,7 @@ var Editor =function(renderer, session) {
var state = this.bgTokenizer.getState(this.getCursorPosition().row); var state = this.bgTokenizer.getState(this.getCursorPosition().row);
var rows = this.$getSelectedRows() var rows = this.$getSelectedRows()
var addedColumns = this.mode.toggleCommentLines(state, this.session, rows.first, rows.last); var addedColumns = this.mode.toggleCommentLines(state, this.session, rows.first, rows.last);
this.selection.shiftSelection(addedColumns); // TODO remove addedColumns
}; };
this.removeLines = function() { this.removeLines = function() {
@ -689,7 +688,6 @@ var Editor =function(renderer, session) {
this.onCompositionStart = function(text) { this.onCompositionStart = function(text) {
this.renderer.showComposition(this.getCursorPosition()); this.renderer.showComposition(this.getCursorPosition());
//this.onTextInput(text);
}; };
this.onCompositionUpdate = function(text) { this.onCompositionUpdate = function(text) {
@ -698,7 +696,6 @@ var Editor =function(renderer, session) {
this.onCompositionEnd = function() { this.onCompositionEnd = function() {
this.renderer.hideComposition(); this.renderer.hideComposition();
//this.removeLeft();
}; };

View file

@ -42,15 +42,27 @@ var oop = require("pilot/oop");
var lang = require("pilot/lang"); var lang = require("pilot/lang");
var EventEmitter = require("pilot/event_emitter").EventEmitter; var EventEmitter = require("pilot/event_emitter").EventEmitter;
var Range = require("ace/range").Range; var Range = require("ace/range").Range;
var Anchor = require("ace/anchor").Anchor;
var Selection = function(doc) { var Selection = function(session) {
this.doc = doc; this.session = session;
this.doc = session.getDocument();
this.clearSelection(); this.clearSelection();
this.selectionLead = { this.selectionLead = new Anchor(this.doc, 0, 0);
row: 0, this.selectionAnchor = new Anchor(this.doc, 0, 0);
column: 0
}; var _self = this;
this.selectionLead.on("change", function() {
_self._dispatchEvent("changeCursor");
if (!_self.$isEmpty)
_self._dispatchEvent("changeSelection");
});
this.selectionAnchor.on("change", function() {
if (!_self.$isEmpty)
_self._dispatchEvent("changeSelection");
});
}; };
(function() { (function() {
@ -58,9 +70,10 @@ var Selection = function(doc) {
oop.implement(this, EventEmitter); oop.implement(this, EventEmitter);
this.isEmpty = function() { this.isEmpty = function() {
return (!this.selectionAnchor || return (this.$isEmpty || (
(this.selectionAnchor.row == this.selectionLead.row && this.selectionAnchor.row == this.selectionLead.row &&
this.selectionAnchor.column == this.selectionLead.column)); this.selectionAnchor.column == this.selectionLead.column
));
}; };
this.isMultiLine = function() { this.isMultiLine = function() {
@ -72,37 +85,31 @@ var Selection = function(doc) {
}; };
this.getCursor = function() { this.getCursor = function() {
return this.selectionLead; return this.selectionLead.getPosition();
}; };
this.setSelectionAnchor = function(row, column) { this.setSelectionAnchor = function(row, column) {
var anchor = this.$clipPositionToDocument(row, column); this.selectionAnchor.setPosition(row, column);
if (!this.selectionAnchor) { if (this.$isEmpty) {
this.selectionAnchor = anchor; this.$isEmpty = false;
this._dispatchEvent("changeSelection", {}); this._dispatchEvent("changeSelection");
} }
else if (this.selectionAnchor.row !== anchor.row || this.selectionAnchor.column !== anchor.column) {
this.selectionAnchor = anchor;
this._dispatchEvent("changeSelection", {});
}
}; };
this.getSelectionAnchor = function() { this.getSelectionAnchor = function() {
if (this.selectionAnchor) { if (this.$isEmpty)
return this.$clone(this.selectionAnchor); return this.getSelectionLead()
} else { else
return this.$clone(this.selectionLead); return this.selectionAnchor.getPosition();
}
}; };
this.getSelectionLead = function() { this.getSelectionLead = function() {
return this.$clone(this.selectionLead); return this.selectionLead.getPosition();
}; };
this.shiftSelection = function(columns) { this.shiftSelection = function(columns) {
if (this.isEmpty()) { if (this.$isEmpty) {
this.moveCursorTo(this.selectionLead.row, this.selectionLead.column + columns); this.moveCursorTo(this.selectionLead.row, this.selectionLead.column + columns);
return; return;
}; };
@ -123,15 +130,18 @@ var Selection = function(doc) {
}; };
this.isBackwards = function() { this.isBackwards = function() {
var anchor = this.selectionAnchor || this.selectionLead; var anchor = this.selectionAnchor;
var lead = this.selectionLead; var lead = this.selectionLead;
return (anchor.row > lead.row || (anchor.row == lead.row && anchor.column > lead.column)); return (anchor.row > lead.row || (anchor.row == lead.row && anchor.column > lead.column));
}; };
this.getRange = function() { this.getRange = function() {
var anchor = this.selectionAnchor || this.selectionLead; var anchor = this.selectionAnchor;
var lead = this.selectionLead; var lead = this.selectionLead;
if (this.isEmpty())
return Range.fromPoints(lead, lead);
if (this.isBackwards()) { if (this.isBackwards()) {
return Range.fromPoints(lead, anchor); return Range.fromPoints(lead, anchor);
} }
@ -141,26 +151,17 @@ var Selection = function(doc) {
}; };
this.clearSelection = function() { this.clearSelection = function() {
if (this.selectionAnchor) { if (!this.$isEmpty) {
this.selectionAnchor = null; this.$isEmpty = true;
this._dispatchEvent("changeSelection", {}); this._dispatchEvent("changeSelection");
} }
}; };
this.selectAll = function() { this.selectAll = function() {
var lastRow = this.doc.getLength() - 1; var lastRow = this.doc.getLength() - 1;
this.setSelectionAnchor(lastRow, this.doc.getLine(lastRow).length); this.setSelectionAnchor(lastRow, this.doc.getLine(lastRow).length);
this.setSelectionLead(0, 0);
if (!this.selectionAnchor) { // this._dispatchEvent("changeSelection", {blockScrolling: true});
this.selectionAnchor = this.$clone(this.selectionLead);
}
var cursor = {row:0, column:0};
// only dispatch change if the cursor actually changed
if (cursor.row !== this.selectionLead.row || cursor.column !== this.selectionLead.column) {
this.selectionLead = cursor;
this._dispatchEvent("changeSelection", {blockScrolling: true});
}
}; };
this.setSelectionRange = function(range, reverse) { this.setSelectionRange = function(range, reverse) {
@ -177,27 +178,16 @@ var Selection = function(doc) {
this.$updateDesiredColumn = function() { this.$updateDesiredColumn = function() {
var cursor = this.getCursor(); var cursor = this.getCursor();
if (cursor) { if (cursor) {
this.$desiredColumn = this.doc.documentToScreenColumn(cursor.row, cursor.column); this.$desiredColumn = this.session.documentToScreenColumn(cursor.row, cursor.column);
} }
}; };
this.$moveSelection = function(mover) { this.$moveSelection = function(mover) {
var changed = false; var lead = this.selectionLead;
if (this.$isEmpty)
this.setSelectionAnchor(lead.row, lead.column);
if (!this.selectionAnchor) {
changed = true;
this.selectionAnchor = this.$clone(this.selectionLead);
}
var cursor = this.$clone(this.selectionLead);
mover.call(this); mover.call(this);
if (cursor.row !== this.selectionLead.row || cursor.column !== this.selectionLead.column) {
changed = true;
}
if (changed)
this._dispatchEvent("changeSelection", {});
}; };
this.selectTo = function(row, column) { this.selectTo = function(row, column) {
@ -253,15 +243,9 @@ var Selection = function(doc) {
}; };
this.selectWord = function() { this.selectWord = function() {
var cursor = this.selectionLead; var cursor = this.getCursor();
var column = cursor.column; var range = this.session.getWordRange(cursor.row, cursor.column);
var range = this.doc.getWordRange(cursor.row, column);
this.setSelectionRange(range); this.setSelectionRange(range);
/*this.setSelectionAnchor(cursor.row, start);
this.$moveSelection(function() {
this.moveCursorTo(cursor.row, end);
});*/
}; };
this.selectLine = function() { this.selectLine = function() {
@ -280,18 +264,16 @@ var Selection = function(doc) {
}; };
this.moveCursorLeft = function() { this.moveCursorLeft = function() {
if (this.selectionLead.column == 0) { var cursor = this.selectionLead.getPosition();
if (cursor.column == 0) {
// cursor is a line (start // cursor is a line (start
if (this.selectionLead.row > 0) { if (cursor.row > 0) {
this.moveCursorTo(this.selectionLead.row - 1, this.doc this.moveCursorTo(cursor.row - 1, this.doc.getLine(cursor.row - 1).length);
.getLine(this.selectionLead.row - 1).length);
} }
} }
else { else {
var doc = this.doc; var tabSize = this.session.getTabSize();
var tabSize = doc.getTabSize(); if (this.session.isTabStop(cursor) && this.doc.getLine(cursor.row).slice(cursor.column-tabSize, cursor.column).split(" ").length-1 == tabSize)
var cursor = this.selectionLead;
if (doc.isTabStop(cursor) && doc.getLine(cursor.row).slice(cursor.column-tabSize, cursor.column).split(" ").length-1 == tabSize)
this.moveCursorBy(0, -tabSize); this.moveCursorBy(0, -tabSize);
else else
this.moveCursorBy(0, -1); this.moveCursorBy(0, -1);
@ -305,10 +287,9 @@ var Selection = function(doc) {
} }
} }
else { else {
var doc = this.doc; var tabSize = this.session.getTabSize();
var tabSize = doc.getTabSize();
var cursor = this.selectionLead; var cursor = this.selectionLead;
if (doc.isTabStop(cursor) && doc.getLine(cursor.row).slice(cursor.column, cursor.column+tabSize).split(" ").length-1 == tabSize) if (this.session.isTabStop(cursor) && this.doc.getLine(cursor.row).slice(cursor.column, cursor.column+tabSize).split(" ").length-1 == tabSize)
this.moveCursorBy(0, tabSize); this.moveCursorBy(0, tabSize);
else else
this.moveCursorBy(0, 1); this.moveCursorBy(0, 1);
@ -318,12 +299,12 @@ var Selection = function(doc) {
this.moveCursorLineStart = function() { this.moveCursorLineStart = function() {
var row = this.selectionLead.row; var row = this.selectionLead.row;
var column = this.selectionLead.column; var column = this.selectionLead.column;
var screenRow = this.doc.documentToScreenRow(row, column); var screenRow = this.session.documentToScreenRow(row, column);
var firstRowColumn = this.doc.getScreenFirstRowColumn(screenRow); var firstRowColumn = this.session.getScreenFirstRowColumn(screenRow);
var beforeCursor = this.doc.getLine(row).slice(firstRowColumn, column); var beforeCursor = this.doc.getLine(row).slice(firstRowColumn, column);
var leadingSpace = beforeCursor.match(/^\s*/); var leadingSpace = beforeCursor.match(/^\s*/);
if (leadingSpace[0].length == 0) { if (leadingSpace[0].length == 0) {
var lastRowColumn = this.doc.getDocumentLastRowColumn(row, column); var lastRowColumn = this.session.getDocumentLastRowColumn(row, column);
leadingSpace = this.doc.getLine(row). leadingSpace = this.doc.getLine(row).
substring(firstRowColumn, lastRowColumn). substring(firstRowColumn, lastRowColumn).
match(/^\s*/); match(/^\s*/);
@ -336,9 +317,8 @@ var Selection = function(doc) {
}; };
this.moveCursorLineEnd = function() { this.moveCursorLineEnd = function() {
var selLead = this.selectionLead; var lead = this.selectionLead;
this.moveCursorTo(selLead.row, this.moveCursorTo(lead.row, this.session.getDocumentLastRowColumn(lead.row, lead.column));
this.doc.getDocumentLastRowColumn(selLead.row, selLead.column));
}; };
this.moveCursorFileEnd = function() { this.moveCursorFileEnd = function() {
@ -358,20 +338,20 @@ var Selection = function(doc) {
var rightOfCursor = line.substring(column); var rightOfCursor = line.substring(column);
var match; var match;
this.doc.nonTokenRe.lastIndex = 0; this.session.nonTokenRe.lastIndex = 0;
this.doc.tokenRe.lastIndex = 0; this.session.tokenRe.lastIndex = 0;
if (column == line.length) { if (column == line.length) {
this.moveCursorRight(); this.moveCursorRight();
return; return;
} }
else if (match = this.doc.nonTokenRe.exec(rightOfCursor)) { else if (match = this.session.nonTokenRe.exec(rightOfCursor)) {
column += this.doc.nonTokenRe.lastIndex; column += this.session.nonTokenRe.lastIndex;
this.doc.nonTokenRe.lastIndex = 0; this.session.nonTokenRe.lastIndex = 0;
} }
else if (match = this.doc.tokenRe.exec(rightOfCursor)) { else if (match = this.session.tokenRe.exec(rightOfCursor)) {
column += this.doc.tokenRe.lastIndex; column += this.session.tokenRe.lastIndex;
this.doc.tokenRe.lastIndex = 0; this.session.tokenRe.lastIndex = 0;
} }
this.moveCursorTo(row, column); this.moveCursorTo(row, column);
@ -384,83 +364,49 @@ var Selection = function(doc) {
var leftOfCursor = lang.stringReverse(line.substring(0, column)); var leftOfCursor = lang.stringReverse(line.substring(0, column));
var match; var match;
this.doc.nonTokenRe.lastIndex = 0; this.session.nonTokenRe.lastIndex = 0;
this.doc.tokenRe.lastIndex = 0; this.session.tokenRe.lastIndex = 0;
if (column == 0) { if (column == 0) {
this.moveCursorLeft(); this.moveCursorLeft();
return; return;
} }
else if (match = this.doc.nonTokenRe.exec(leftOfCursor)) { else if (match = this.session.nonTokenRe.exec(leftOfCursor)) {
column -= this.doc.nonTokenRe.lastIndex; column -= this.session.nonTokenRe.lastIndex;
this.doc.nonTokenRe.lastIndex = 0; this.session.nonTokenRe.lastIndex = 0;
} }
else if (match = this.doc.tokenRe.exec(leftOfCursor)) { else if (match = this.session.tokenRe.exec(leftOfCursor)) {
column -= this.doc.tokenRe.lastIndex; column -= this.session.tokenRe.lastIndex;
this.doc.tokenRe.lastIndex = 0; this.session.tokenRe.lastIndex = 0;
} }
this.moveCursorTo(row, column); this.moveCursorTo(row, column);
}; };
this.moveCursorBy = function(rows, chars) { this.moveCursorBy = function(rows, chars) {
if (this.doc.getUseWrapMode()) { if (this.session.getUseWrapMode()) {
var screenPos = this.doc.documentToScreenPosition( var screenPos = this.session.documentToScreenPosition(
this.selectionLead.row, this.selectionLead.column); this.selectionLead.row,
var screenCol = this.selectionLead.column
(chars == 0 && this.$desiredColumn) || screenPos.column; );
var screenCol = (chars == 0 && this.$desiredColumn) || screenPos.column;
var docPos = this.session.screenToDocumentPosition(screenPos.row + rows, screenCol);
var docPos = this.doc.screenToDocumentPosition(
screenPos.row + rows, screenCol);
this.moveCursorTo(docPos.row, docPos.column + chars, chars == 0); this.moveCursorTo(docPos.row, docPos.column + chars, chars == 0);
} else { } else {
var docColumn = var docColumn = (chars == 0 && this.$desiredColumn) || this.selectionLead.column;
(chars == 0 && this.$desiredColumn) || this.selectionLead.column; this.moveCursorTo(this.selectionLead.row + rows, docColumn + chars, chars == 0);
this.moveCursorTo(
this.selectionLead.row + rows, docColumn + chars, chars == 0);
} }
}; };
this.moveCursorToPosition = function(position) { this.moveCursorToPosition = function(position) {
this.moveCursorTo(position.row, position.column); this.moveCursorTo(position.row, position.column);
}; };
this.moveCursorTo = function(row, column, preventUpdateDesiredColumn) { this.moveCursorTo = function(row, column, preventUpdateDesiredColumn) {
var cursor = this.$clipPositionToDocument(row, column); this.selectionLead.setPosition(row, column);
if (!preventUpdateDesiredColumn)
// only dispatch change if the cursor actually changed this.$updateDesiredColumn(column);
if (cursor.row !== this.selectionLead.row || cursor.column !== this.selectionLead.column) {
this.selectionLead = cursor;
!preventUpdateDesiredColumn && this.$updateDesiredColumn(column);
this._dispatchEvent("changeCursor", { data: this.getCursor() });
}
};
this.$clipPositionToDocument = function(row, column) {
var pos = {};
if (row >= this.doc.getLength()) {
pos.row = Math.max(0, this.doc.getLength() - 1);
pos.column = this.doc.getLine(pos.row).length;
}
else if (row < 0) {
pos.row = 0;
pos.column = 0;
}
else {
pos.row = row;
pos.column = Math.min(this.doc.getLine(pos.row).length,
Math.max(0, column));
}
return pos;
};
this.$clone = function(pos) {
return {
row: pos.row,
column: pos.column
};
}; };
}).call(Selection.prototype); }).call(Selection.prototype);