ace/Editor.js
2010-04-08 18:46:43 +02:00

577 lines
No EOL
13 KiB
JavaScript

var keys = {
UP: 38,
RIGHT: 39,
DOWN: 40,
LEFT: 37,
POS1: 36,
END: 35,
DELETE: 46,
BACKSPACE: 8,
TAB: 9,
A: 65
}
function KeyBinding(element, host)
{
lib.addListener(element, "keydown", function(e)
{
var key = e.keyCode;
switch (key)
{
case keys.A:
if (e.metaKey)
{
host.selectAll();
return lib.stopEvent(e);
}
break;
case keys.UP:
if (e.shiftKey) {
host.selectUp();
} else {
host.navigateUp();
}
return lib.stopEvent(e);
case keys.DOWN:
if (e.shiftKey) {
host.selectDown();
} else {
host.navigateDown();
}
return lib.stopEvent(e);
case keys.LEFT:
if (e.metaKey && e.shiftKey) {
host.selectLineStart();
} else if (e.metaKey) {
host.navigateLineStart();
} else if (e.shiftKey) {
host.selectLeft();
} else {
host.navigateLeft();
}
return lib.stopEvent(e);
case keys.RIGHT:
if (e.metaKey && e.shiftKey) {
host.selectLineEnd();
} else if (e.metaKey) {
host.navigateLineEnd();
} else if (e.shiftKey) {
host.selectRight();
} else {
host.navigateRight();
}
return lib.stopEvent(e);
case keys.POS1:
if (e.shiftKey) {
host.selectLineStart();
} else {
host.navigateLineStart();
}
return lib.stopEvent(e);
case keys.END:
if (e.shiftKey) {
host.selectLineEnd();
} else {
host.navigateLineEnd();
}
return lib.stopEvent(e);
case keys.DELETE:
host.removeRight();
return lib.stopEvent(e);
case keys.BACKSPACE:
host.removeLeft();
return lib.stopEvent(e);
case keys.TAB:
host.onTextInput(" ");
return lib.stopEvent(e);
}
});
};
function Editor(doc, renderer)
{
var container = renderer.getContainerElement();
this.renderer = renderer;
this.textInput = new TextInput(container, this);
new KeyBinding(container, this);
lib.addListener(container, "mousedown", lib.bind(this.onMouseDown, this));
lib.addListener(container, "dblclick", lib.bind(this.onMouseDoubleClick, this));
lib.addMouseWheelListener(container, lib.bind(this.onMouseWheel, this));
lib.addTripleClickListener(container, lib.bind(this.selectCurrentLine, this));
this.doc = doc;
doc.addChangeListener(lib.bind(this.onDocumentChange, this));
renderer.setDocument(doc);
this.tokenizer = new BackgroundTokenizer(lib.bind(this.onTokenizerUpdate, this));
this.tokenizer.setLines(doc.lines);
renderer.setTokenizer(this.tokenizer);
this.cursor = {
row: 0,
column: 0
};
this.selectionAnchor = null;
this.selectionLead = null;
this.selection = null;
this.renderer.draw();
}
Editor.prototype =
{
resize : function() {
this.renderer.draw();
},
updateCursor : function() {
this.renderer.updateCursor(this.cursor);
},
onFocus : function() {
this.renderer.showCursor();
this.renderer.visualizeFocus();
},
onBlur : function() {
this.renderer.hideCursor();
this.renderer.visualizeBlur();
},
onDocumentChange : function(startRow, endRow)
{
this.tokenizer.start(startRow);
this.renderer.updateLines(startRow, endRow);
},
onTokenizerUpdate : function(startRow, endRow) {
console.log("token update", startRow, endRow);
this.renderer.updateLines(startRow, endRow);
},
onMouseDown : function(e)
{
this.textInput.focus();
var pos = this.renderer.screenToTextCoordinates(e.pageX, e.pageY);
this.moveCursorTo(pos.row, pos.column);
this.setSelectionAnchor(pos.row, pos.column);
this.renderer.scrollCursorIntoView();
var _self = this;
var mousePageX, mousePageY;
var onMouseSelection = function(e) {
mousePageX = e.pageX;
mousePageY = e.pageY;
};
var onMouseSelectionEnd = function() {
clearInterval(timerId);
};
var onSelectionInterval = function()
{
if (mousePageX === undefined || mousePageY === undefined) return;
selectionLead = _self.renderer.screenToTextCoordinates(mousePageX, mousePageY);
_self._moveSelection(function() {
_self.moveCursorTo(selectionLead.row, selectionLead.column);
});
_self.renderer.scrollCursorIntoView();
};
lib.capture(this.container, onMouseSelection, onMouseSelectionEnd);
var timerId = setInterval(onSelectionInterval, 20 );
return lib.preventDefault(e);
},
onMouseDoubleClick : function(e)
{
var line = this.doc.getLine(this.cursor.row);
var column = this.cursor.column;
var tokenRe = /[a-zA-Z0-9_]+/g;
var nonTokenRe = /[^a-zA-Z0-9_]+/g;
var inToken = false;
if (column > 0) {
inToken = !!line.charAt(column-1).match(tokenRe);
}
if (!inToken) {
inToken = !!line.charAt(column).match(tokenRe);
}
var re = inToken ? tokenRe : nonTokenRe;
var start = column;
if (start > 0)
{
do {
start--;
} while (start >= 0 && line.charAt(start).match(re))
start++;
}
var end = column;
while (end < line.length && line.charAt(end).match(re)) {
end++;
}
this.setSelectionAnchor(this.cursor.row, start);
this._moveSelection(function() {
this.moveCursorTo(this.cursor.row, end);
});
},
onMouseWheel : function(e)
{
var delta = e.wheel;
this.renderer.scrollToY(this.renderer.getScrollTop() - (delta * 15));
return lib.preventDefault(e);
},
getCopyText : function()
{
if (this.hasSelection()) {
return this.doc.getTextRange(this.getSelectionRange());
} else {
return "";
}
},
onCut : function()
{
if (this.hasSelection())
{
this.cursor = this.doc.remove(this.getSelectionRange());
this.clearSelection();
this.renderer.updateCursor(this.cursor);
}
},
onTextInput: function(text)
{
if (this.hasSelection())
{
this.cursor = this.doc.replace(this.getSelectionRange(), text);
this.clearSelection();
} else {
this.cursor = this.doc.insert(this.cursor, text);
}
this.renderer.updateCursor(this.cursor);
this.renderer.scrollCursorIntoView();
},
removeRight : function()
{
if (this.hasSelection())
{
this.cursor = this.doc.remove(this.getSelectionRange());
this.renderer.updateCursor(this.cursor);
this.clearSelection();
}
else
{
var rangeEnd = {
row: this.cursor.row,
column: this.cursor.column + 1
}
if (rangeEnd.column > this.doc.getLine(this.cursor.row).length) {
rangeEnd.row += 1;
rangeEnd.column = 0;
}
this.doc.remove({start: this.cursor, end: renageEnd});
}
this.renderer.scrollCursorIntoView();
},
removeLeft : function()
{
if (this.hasSelection())
{
this.cursor = this.doc.remove(this.getSelectionRange());
this.clearSelection();
}
else
{
if (this.cursor.row == 0 && this.cursor.column == 0) {
return;
}
var rangeStart = {
row: this.cursor.row,
column: this.cursor.column + -1
}
if (rangeStart.column < 0)
{
rangeStart.row -= 1;
rangeStart.column = this.doc.getLine(this.cursor.row-1).length;
}
this.cursor = this.doc.remove({start: rangeStart, end: this.cursor});
}
this.renderer.updateCursor(this.cursor);
this.renderer.scrollCursorIntoView();
},
onCompositionStart : function()
{
this.renderer.showComposition(this.cursor);
this.onTextInput(" ");
},
onCompositionUpdate : function(text) {
this.renderer.setCompositionText(text);
},
onCompositionEnd : function() {
this.renderer.hideComposition();
this.removeLeft();
},
navigateUp : function()
{
this.clearSelection();
this.moveCursorUp();
this.renderer.scrollCursorIntoView();
},
navigateDown : function() {
this.clearSelection();
this.moveCursorDown();
this.renderer.scrollCursorIntoView();
},
navigateLeft : function()
{
if (this.hasSelection()) {
var selectionStart = this.getSelectionRange().start;
this.moveCursorTo(selectionStart.row, selectionStart.column);
} else {
this.moveCursorLeft();
}
this.clearSelection();
this.renderer.scrollCursorIntoView();
},
navigateRight : function()
{
if (this.hasSelection()) {
var selectionEnd = this.getSelectionRange().end;
this.moveCursorTo(selectionEnd.row, selectionEnd.column);
} else {
this.moveCursorRight();
}
this.clearSelection();
this.renderer.scrollCursorIntoView();
},
navigateLineStart : function()
{
this.clearSelection();
this.moveCursorLineStart();
this.renderer.scrollCursorIntoView();
},
navigateLineEnd : function()
{
this.clearSelection();
this.moveCursorLineEnd();
this.renderer.scrollCursorIntoView();
},
moveCursorUp : function() {
this.moveCursorBy(-1, 0);
},
moveCursorDown : function() {
this.moveCursorBy(1, 0);
},
moveCursorLeft : function()
{
if (this.cursor.column == 0) {
if (this.cursor.row > 0) {
this.moveCursorTo(this.cursor.row-1, this.doc.getLine(this.cursor.row-1).length);
}
} else {
this.moveCursorBy(0, -1);
}
},
moveCursorRight : function()
{
if (this.cursor.column == this.doc.getLine(this.cursor.row).length) {
if (this.cursor.row < this.doc.getLength()-1) {
this.moveCursorTo(this.cursor.row+1, 0);
}
} else {
this.moveCursorBy(0, 1);
}
this.renderer.scrollCursorIntoView();
},
moveCursorLineStart : function()
{
this.moveCursorTo(this.cursor.row, 0);
this.renderer.scrollCursorIntoView();
},
moveCursorLineEnd : function() {
this.moveCursorTo(this.cursor.row, this.doc.getLine(this.cursor.row).length);
this.renderer.scrollCursorIntoView();
},
moveCursorBy : function(rows, chars) {
this.moveCursorTo(this.cursor.row+rows, this.cursor.column+chars);
},
moveCursorTo : function(row, column)
{
if (row >= this.doc.getLength()) {
this.cursor.row = this.doc.getLength()-1;
this.cursor.column = this.doc.getLine(this.cursor.row).length;
} else if (row < 0) {
this.cursor.row = 0;
this.cursor.column = 0;
} else {
this.cursor.row = row;
this.cursor.column = Math.min(this.doc.getLine(this.cursor.row).length, Math.max(0, column));
}
this.updateCursor();
},
hasSelection : function() {
return !!this.selectionLead;
},
setSelectionAnchor : function(row, column)
{
this.clearSelection();
this.selectionAnchor = {
row: Math.min(this.doc.getLength()-1, Math.max(0, row)),
column: Math.min(this.doc.getLine(this.cursor.row).length, Math.max(0, column))
};
this.selectionLead = null;
},
getSelectionRange : function()
{
var anchor = this.selectionAnchor;
var lead = this.selectionLead;
if (!anchor) {
return null;
} else {
if (anchor.row > lead.row || (anchor.row == lead.row && anchor.column > lead.column)) {
return {
start: lead,
end: anchor
}
} else {
return {
start: anchor,
end: lead
}
}
}
},
clearSelection : function()
{
this.selectionLead = null;
this.selectionAnchor = null;
if (this.selection) {
this.renderer.removeMarker(this.selection);
this.selection = null;
}
},
selectAll : function()
{
var lastRow = this.doc.getLength()-1;
this.setSelectionAnchor(lastRow, this.doc.getLine(lastRow).length);
this._moveSelection(function() {
this.moveCursorTo(0, 0);
});
},
_moveSelection : function(mover)
{
if (!this.selectionAnchor) {
this.selectionAnchor = {
row: this.cursor.row,
column: this.cursor.column
}
}
mover.call(this);
this.selectionLead = {
row: this.cursor.row,
column: this.cursor.column
}
if (this.selection) {
this.renderer.removeMarker(this.selection);
}
this.selection = this.renderer.addMarker(this.getSelectionRange(), "selection");
this.renderer.scrollCursorIntoView();
},
selectUp : function() {
this._moveSelection(this.moveCursorUp);
},
selectDown : function() {
this._moveSelection(this.moveCursorDown);
},
selectRight : function() {
this._moveSelection(this.moveCursorRight);
},
selectLeft : function() {
this._moveSelection(this.moveCursorLeft);
},
selectLineStart : function() {
this._moveSelection(this.moveCursorLineStart);
},
selectLineEnd : function() {
this._moveSelection(this.moveCursorLineEnd);
},
selectCurrentLine : function()
{
this.setSelectionAnchor(this.cursor.row, 0);
this._moveSelection(function() {
this.moveCursorTo(this.cursor.row+1, 0);
});
}
}