ace/lib/ace/editor.js

1073 lines
33 KiB
JavaScript

/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("pilot/oop");
var event = require("pilot/event");
var lang = require("pilot/lang");
var TextInput = require("ace/keyboard/textinput").TextInput;
var KeyBinding = require("ace/keyboard/keybinding").KeyBinding;
var EditSession = require("ace/edit_session").EditSession;
var Search = require("ace/search").Search;
var BackgroundTokenizer = require("ace/background_tokenizer").BackgroundTokenizer;
var Range = require("ace/range").Range;
var EventEmitter = require("pilot/event_emitter").EventEmitter;
var Editor =function(renderer, session) {
var container = renderer.getContainerElement();
this.container = container;
this.renderer = renderer;
this.textInput = new TextInput(renderer.getTextAreaContainer(), this);
this.keyBinding = new KeyBinding(this);
var self = this;
event.addListener(container, "mousedown", function(e) {
self.focus();
return event.preventDefault(e);
});
event.addListener(container, "selectstart", function(e) {
return event.preventDefault(e);
});
var mouseTarget = renderer.getMouseEventTarget();
event.addListener(mouseTarget, "mousedown", this.onMouseDown.bind(this));
event.addMultiMouseDownListener(mouseTarget, 0, 2, 500, this.onMouseDoubleClick.bind(this));
event.addMultiMouseDownListener(mouseTarget, 0, 3, 600, this.onMouseTripleClick.bind(this));
event.addMouseWheelListener(mouseTarget, this.onMouseWheel.bind(this));
this.$selectionMarker = null;
this.$highlightLineMarker = null;
this.$blockScrolling = false;
this.$search = new Search().set({
wrap: true
});
this.setSession(session || new EditSession(""));
this.focus();
};
(function(){
oop.implement(this, EventEmitter);
this.$forwardEvents = {
gutterclick: 1,
gutterdblclick: 1
};
this.$originalAddEventListener = this.addEventListener;
this.$originalRemoveEventListener = this.removeEventListener;
this.addEventListener = function(eventName, callback) {
if (this.$forwardEvents[eventName]) {
return this.renderer.addEventListener(eventName, callback);
} else {
return this.$originalAddEventListener(eventName, callback);
}
};
this.removeEventListener = function(eventName, callback) {
if (this.$forwardEvents[eventName]) {
return this.renderer.removeEventListener(eventName, callback);
} else {
return this.$originalRemoveEventListener(eventName, callback);
}
};
this.setKeyboardHandler = function(keyboardHandler) {
this.keyBinding.setKeyboardHandler(keyboardHandler);
};
this.getKeyboardHandler = function() {
return this.keyBinding.getKeyboardHandler();
}
this.setSession = function(session) {
if (this.session == session) return;
if (this.session) {
var oldSession = this.session;
this.session.removeEventListener("change", this.$onDocumentChange);
this.session.removeEventListener("changeMode", this.$onDocumentModeChange);
this.session.removeEventListener("changeTabSize", this.$onDocumentChangeTabSize);
this.session.removeEventListener("changeWrapMode", this.$onDocumentChangeWrapMode);
this.session.removeEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
this.session.removeEventListener("changeAnnotation", this.$onDocumentChangeAnnotation);
var selection = this.session.getSelection();
selection.removeEventListener("changeCursor", this.$onCursorChange);
selection.removeEventListener("changeSelection", this.$onSelectionChange);
this.session.setScrollTopRow(this.renderer.getScrollTopRow());
}
this.session = session;
this.$onDocumentChange = this.onDocumentChange.bind(this);
session.addEventListener("change", this.$onDocumentChange);
this.renderer.setSession(session);
this.$onDocumentModeChange = this.onDocumentModeChange.bind(this);
session.addEventListener("changeMode", this.$onDocumentModeChange);
this.$onDocumentChangeTabSize = this.renderer.updateText.bind(this.renderer);
session.addEventListener("changeTabSize", this.$onDocumentChangeTabSize);
this.$onDocumentChangeWrapMode = this.renderer.updateFull.bind(this.renderer);
session.addEventListener("changeWrapMode", this.$onDocumentChangeWrapMode);
this.$onDocumentChangeBreakpoint = this.onDocumentChangeBreakpoint.bind(this);
this.session.addEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
this.$onDocumentChangeAnnotation = this.onDocumentChangeAnnotation.bind(this);
this.session.addEventListener("changeAnnotation", this.$onDocumentChangeAnnotation);
this.selection = session.getSelection();
this.$onCursorChange = this.onCursorChange.bind(this);
this.selection.addEventListener("changeCursor", this.$onCursorChange);
this.$onSelectionChange = this.onSelectionChange.bind(this);
this.selection.addEventListener("changeSelection", this.$onSelectionChange);
this.onDocumentModeChange();
this.bgTokenizer.setDocument(session.getDocument());
this.bgTokenizer.start(0);
this.onCursorChange();
this.onSelectionChange();
this.onDocumentChangeBreakpoint();
this.onDocumentChangeAnnotation();
this.renderer.scrollToRow(session.getScrollTopRow());
this.renderer.updateFull();
this._dispatchEvent("changeSession", {
session: session,
oldSession: oldSession
});
};
this.getSession = function() {
return this.session;
};
this.getSelection = function() {
return this.selection;
};
this.resize = function() {
this.renderer.onResize();
};
this.setTheme = function(theme) {
this.renderer.setTheme(theme);
};
this.setStyle = function(style) {
this.renderer.setStyle(style)
};
this.unsetStyle = function(style) {
this.renderer.unsetStyle(style)
}
this.$highlightBrackets = function() {
if (this.$bracketHighlight) {
this.renderer.removeMarker(this.$bracketHighlight);
this.$bracketHighlight = null;
}
if (this.$highlightPending) {
return;
}
// perform highlight async to not block the browser during navigation
var self = this;
this.$highlightPending = true;
setTimeout(function() {
self.$highlightPending = false;
var pos = self.session.findMatchingBracket(self.getCursorPosition());
if (pos) {
var range = new Range(pos.row, pos.column, pos.row, pos.column+1);
self.$bracketHighlight = self.renderer.addMarker(range, "ace_bracket");
}
}, 10);
};
this.focus = function() {
// Safari need the timeout
// iOS and Firefox need it called immediately
// to be on the save side we do both
var _self = this;
setTimeout(function() {
_self.textInput.focus();
});
this.textInput.focus();
};
this.blur = function() {
this.textInput.blur();
};
this.onFocus = function() {
this.renderer.showCursor();
this.renderer.visualizeFocus();
};
this.onBlur = function() {
this.renderer.hideCursor();
this.renderer.visualizeBlur();
};
this.onDocumentChange = function(e) {
var delta = e.data;
var range = delta.range;
this.bgTokenizer.start(range.start.row);
if (range.start.row == range.end.row)
var lastRow = range.end.row;
else
lastRow = Infinity;
this.renderer.updateLines(range.start.row, lastRow);
// update cursor because tab characters can influence the cursor position
this.renderer.updateCursor(this.getCursorPosition(), this.$overwrite);
};
this.onTokenizerUpdate = function(e) {
var rows = e.data;
this.renderer.updateLines(rows.first, rows.last);
};
this.onCursorChange = function(e) {
this.$highlightBrackets();
// move text input over the cursor
// this is required for iOS and IME
this.renderer.moveTextAreaToCursor(this.textInput.getElement());
this.renderer.updateCursor(this.getCursorPosition(), this.$overwrite);
if (!this.$blockScrolling && (!e || !e.blockScrolling)) {
this.renderer.scrollCursorIntoView();
}
this.$updateHighlightActiveLine();
};
this.$updateHighlightActiveLine = function() {
if (this.$highlightLineMarker) {
this.renderer.removeMarker(this.$highlightLineMarker);
}
this.$highlightLineMarker = null;
if (this.getHighlightActiveLine() && (this.getSelectionStyle() != "line" || !this.selection.isMultiLine())) {
var cursor = this.getCursorPosition();
var range = new Range(cursor.row, 0, cursor.row+1, 0);
this.$highlightLineMarker = this.renderer.addMarker(range, "ace_active_line", "line");
}
};
this.onSelectionChange = function(e) {
if (this.$selectionMarker) {
this.renderer.removeMarker(this.$selectionMarker);
}
this.$selectionMarker = null;
if (!this.selection.isEmpty()) {
var range = this.selection.getRange();
var style = this.getSelectionStyle();
this.$selectionMarker = this.renderer.addMarker(range, "ace_selection", style);
}
this.onCursorChange(e);
};
this.onDocumentChangeBreakpoint = function() {
this.renderer.setBreakpoints(this.session.getBreakpoints());
};
this.onDocumentChangeAnnotation = function() {
this.renderer.setAnnotations(this.session.getAnnotations());
};
this.onDocumentModeChange = function() {
var mode = this.session.getMode();
if (this.mode == mode)
return;
this.mode = mode;
var tokenizer = mode.getTokenizer();
if (!this.bgTokenizer) {
var onUpdate = this.onTokenizerUpdate.bind(this);
this.bgTokenizer = new BackgroundTokenizer(tokenizer, this);
this.bgTokenizer.addEventListener("update", onUpdate);
} else {
this.bgTokenizer.setTokenizer(tokenizer);
}
this.renderer.setTokenizer(this.bgTokenizer);
};
this.onMouseDown = function(e) {
var pageX = event.getDocumentX(e);
var pageY = event.getDocumentY(e);
var pos = this.renderer.screenToTextCoordinates(pageX, pageY);
pos.row = Math.max(0, Math.min(pos.row, this.session.getLength()-1));
if (event.getButton(e) != 0) {
if (this.selection.isEmpty()) {
this.moveCursorToPosition(pos);
}
return;
}
if (e.shiftKey)
this.selection.selectToPosition(pos)
else {
this.moveCursorToPosition(pos);
if (!this.$clickSelection)
this.selection.clearSelection(pos.row, pos.column);
}
this.renderer.scrollCursorIntoView();
var self = this;
var mousePageX, mousePageY;
var onMouseSelection = function(e) {
mousePageX = event.getDocumentX(e);
mousePageY = event.getDocumentY(e);
};
var onMouseSelectionEnd = function() {
clearInterval(timerId);
self.$clickSelection = null;
};
var onSelectionInterval = function() {
if (mousePageX === undefined || mousePageY === undefined)
return;
var cursor = self.renderer.screenToTextCoordinates(mousePageX, mousePageY);
cursor.row = Math.max(0, Math.min(cursor.row, self.session.getLength()-1));
if (self.$clickSelection) {
if (self.$clickSelection.contains(cursor.row, cursor.column)) {
self.selection.setSelectionRange(self.$clickSelection);
} else {
if (self.$clickSelection.compare(cursor.row, cursor.column) == -1) {
var anchor = self.$clickSelection.end;
} else {
var anchor = self.$clickSelection.start;
}
self.selection.setSelectionAnchor(anchor.row, anchor.column);
self.selection.selectToPosition(cursor);
}
}
else {
self.selection.selectToPosition(cursor);
}
self.renderer.scrollCursorIntoView();
};
event.capture(this.container, onMouseSelection, onMouseSelectionEnd);
var timerId = setInterval(onSelectionInterval, 20);
return event.preventDefault(e);
};
this.onMouseDoubleClick = function(e) {
this.selection.selectWord();
this.$clickSelection = this.getSelectionRange();
};
this.onMouseTripleClick = function(e) {
this.selection.selectLine();
this.$clickSelection = this.getSelectionRange();
};
this.onMouseWheel = function(e) {
var speed = this.$scrollSpeed * 2;
this.renderer.scrollBy(e.wheelX * speed, e.wheelY * speed);
return event.preventDefault(e);
};
this.getCopyText = function() {
if (!this.selection.isEmpty()) {
return this.session.getTextRange(this.getSelectionRange());
}
else {
return "";
}
};
this.onCut = function() {
if (this.$readOnly)
return;
if (!this.selection.isEmpty()) {
this.moveCursorToPosition(this.session.remove(this.getSelectionRange()));
this.clearSelection();
}
};
this.insert = function(text) {
if (this.$readOnly)
return;
var cursor = this.getCursorPosition();
text = text.replace("\t", this.session.getTabString());
// remove selected text
if (!this.selection.isEmpty()) {
var cursor = this.session.remove(this.getSelectionRange());
this.clearSelection();
} else if (this.$overwrite){
var range = new Range.fromPoints(cursor, cursor);
range.end.column += text.length;
this.session.remove(range);
}
this.clearSelection();
var lineState = this.bgTokenizer.getState(cursor.row);
var shouldOutdent = this.mode.checkOutdent(lineState, this.session.getLine(cursor.row), text);
var line = this.session.getLine(cursor.row);
var lineIndent = this.mode.getNextLineIndent(lineState, line.slice(0, cursor.column), this.session.getTabString());
var end = this.session.insert(cursor, text);
/* TODO: This shortcut is somehow broken
if (!shouldOutdent && line != this.session.getLine(row) && text != "\n") {
this.moveCursorToPosition(end);
this.renderer.scrollCursorIntoView();
return;
}
*/
var lineState = this.bgTokenizer.getState(cursor.row);
// multi line insert
if (cursor.row !== end.row) {
var size = this.session.getTabSize(),
minIndent = Number.MAX_VALUE;
for (var row = cursor.row + 1; row <= end.row; ++row) {
var indent = 0;
line = this.session.getLine(row);
for (var i = 0; i < line.length; ++i)
if (line.charAt(i) == '\t')
indent += size;
else if (line.charAt(i) == ' ')
indent += 1;
else
break;
if (/[^\s]/.test(line))
minIndent = Math.min(indent, minIndent);
}
for (var row = cursor.row + 1; row <= end.row; ++row) {
var outdent = minIndent;
line = this.session.getLine(row);
for (var i = 0; i < line.length && outdent > 0; ++i)
if (line.charAt(i) == '\t')
outdent -= size;
else if (line.charAt(i) == ' ')
outdent -= 1;
this.session.replace(new Range(row, 0, row, line.length), line.substr(i));
}
end.column += this.session.indentRows(cursor.row + 1, end.row, lineIndent);
} else {
if (shouldOutdent) {
end.column += this.mode.autoOutdent(lineState, this.session, cursor.row);
}
}
this.moveCursorToPosition(end);
this.renderer.scrollCursorIntoView();
}
this.onTextInput = function(text) {
this.keyBinding.onTextInput(text);
};
this.onCommandKey = function(e, hashId, keyCode) {
this.keyBinding.onCommandKey(e, hashId, keyCode);
};
this.$overwrite = false;
this.setOverwrite = function(overwrite) {
if (this.$overwrite == overwrite) return;
this.$overwrite = overwrite;
this.$blockScrolling = true;
this.onCursorChange();
this.$blockScrolling = false;
this._dispatchEvent("changeOverwrite", {data: overwrite});
};
this.getOverwrite = function() {
return this.$overwrite;
};
this.toggleOverwrite = function() {
this.setOverwrite(!this.$overwrite);
};
this.$scrollSpeed = 1;
this.setScrollSpeed = function(speed) {
this.$scrollSpeed = speed;
}
this.getScrollSpeed = function() {
return this.$scrollSpeed;
}
this.$selectionStyle = "line";
this.setSelectionStyle = function(style) {
if (this.$selectionStyle == style) return;
this.$selectionStyle = style;
this.onSelectionChange();
this._dispatchEvent("changeSelectionStyle", {data: style});
};
this.getSelectionStyle = function() {
return this.$selectionStyle;
};
this.$highlightActiveLine = true;
this.setHighlightActiveLine = function(shouldHighlight) {
if (this.$highlightActiveLine == shouldHighlight) return;
this.$highlightActiveLine = shouldHighlight;
this.$updateHighlightActiveLine();
};
this.getHighlightActiveLine = function() {
return this.$highlightActiveLine;
};
this.setShowInvisibles = function(showInvisibles) {
if (this.getShowInvisibles() == showInvisibles)
return;
this.renderer.setShowInvisibles(showInvisibles);
};
this.getShowInvisibles = function() {
return this.renderer.getShowInvisibles();
};
this.setShowPrintMargin = function(showPrintMargin) {
this.renderer.setShowPrintMargin(showPrintMargin);
};
this.getShowPrintMargin = function() {
return this.renderer.getShowPrintMargin();
};
this.setPrintMarginColumn = function(showPrintMargin) {
this.renderer.setPrintMarginColumn(showPrintMargin);
};
this.getPrintMarginColumn = function() {
return this.renderer.getPrintMarginColumn();
};
this.$readOnly = false;
this.setReadOnly = function(readOnly) {
this.$readOnly = readOnly;
};
this.getReadOnly = function() {
return this.$readOnly;
};
this.removeRight = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty()) {
this.selection.selectRight();
}
this.moveCursorToPosition(this.session.remove(this.getSelectionRange()));
this.clearSelection();
};
this.removeLeft = function() {
if (this.$readOnly)
return;
if (this.selection.isEmpty())
this.selection.selectLeft();
this.moveCursorToPosition(this.session.remove(this.getSelectionRange()));
this.clearSelection();
};
this.indent = function() {
if (this.$readOnly)
return;
var session = this.session;
var range = this.getSelectionRange();
if (range.start.row < range.end.row || range.start.column < range.end.column) {
var rows = this.$getSelectedRows();
var count = session.indentRows(rows.first, rows.last, "\t");
this.selection.shiftSelection(count);
} else {
var indentString;
if (this.session.getUseSoftTabs()) {
var size = session.getTabSize(),
position = this.getCursorPosition(),
column = session.documentToScreenColumn(position.row, position.column),
count = (size - column % size);
indentString = lang.stringRepeat(" ", count);
} else
indentString = "\t";
return this.onTextInput(indentString);
}
};
this.blockOutdent = function() {
if (this.$readOnly)
return;
var selection = this.session.getSelection();
var range = this.session.outdentRows(selection.getRange());
selection.setSelectionRange(range, selection.isBackwards());
};
this.toggleCommentLines = function() {
if (this.$readOnly)
return;
var state = this.bgTokenizer.getState(this.getCursorPosition().row);
var rows = this.$getSelectedRows()
var addedColumns = this.mode.toggleCommentLines(state, this.session, rows.first, rows.last);
this.selection.shiftSelection(addedColumns);
};
this.removeLines = function() {
if (this.$readOnly)
return;
var rows = this.$getSelectedRows();
this.selection.setSelectionAnchor(rows.last+1, 0);
this.selection.selectTo(rows.first, 0);
this.session.remove(this.getSelectionRange());
this.clearSelection();
};
this.moveLinesDown = function() {
if (this.$readOnly)
return;
this.$moveLines(function(firstRow, lastRow) {
return this.session.moveLinesDown(firstRow, lastRow);
});
};
this.moveLinesUp = function() {
if (this.$readOnly)
return;
this.$moveLines(function(firstRow, lastRow) {
return this.session.moveLinesUp(firstRow, lastRow);
});
};
this.copyLinesUp = function() {
if (this.$readOnly)
return;
this.$moveLines(function(firstRow, lastRow) {
this.session.duplicateLines(firstRow, lastRow);
return 0;
});
};
this.copyLinesDown = function() {
if (this.$readOnly)
return;
this.$moveLines(function(firstRow, lastRow) {
return this.session.duplicateLines(firstRow, lastRow);
});
};
this.$moveLines = function(mover) {
var rows = this.$getSelectedRows();
var linesMoved = mover.call(this, rows.first, rows.last);
var selection = this.selection;
selection.setSelectionAnchor(rows.last+linesMoved+1, 0);
selection.$moveSelection(function() {
selection.moveCursorTo(rows.first+linesMoved, 0);
});
};
this.$getSelectedRows = function() {
var range = this.getSelectionRange().collapseRows();
return {
first: range.start.row,
last: range.end.row
};
};
this.onCompositionStart = function(text) {
this.renderer.showComposition(this.getCursorPosition());
//this.onTextInput(text);
};
this.onCompositionUpdate = function(text) {
this.renderer.setCompositionText(text);
};
this.onCompositionEnd = function() {
this.renderer.hideComposition();
//this.removeLeft();
};
this.getFirstVisibleRow = function() {
return this.renderer.getFirstVisibleRow();
};
this.getLastVisibleRow = function() {
return this.renderer.getLastVisibleRow();
};
this.isRowVisible = function(row) {
return (row >= this.getFirstVisibleRow() && row <= this.getLastVisibleRow());
};
this.getVisibleRowCount = function() {
return this.getLastVisibleRow() - this.getFirstVisibleRow() + 1;
};
this.getPageDownRow = function() {
return this.renderer.getLastVisibleRow() - 1;
};
this.getPageUpRow = function() {
var firstRow = this.renderer.getFirstVisibleRow();
var lastRow = this.renderer.getLastVisibleRow();
return firstRow - (lastRow - firstRow) + 1;
};
this.selectPageDown = function() {
var row = this.getPageDownRow() + Math.floor(this.getVisibleRowCount() / 2);
this.scrollPageDown();
var selection = this.getSelection();
selection.$moveSelection(function() {
selection.moveCursorTo(row, selection.getSelectionLead().column);
});
};
this.selectPageUp = function() {
var visibleRows = this.getLastVisibleRow() - this.getFirstVisibleRow();
var row = this.getPageUpRow() + Math.round(visibleRows / 2);
this.scrollPageUp();
var selection = this.getSelection();
selection.$moveSelection(function() {
selection.moveCursorTo(row, selection.getSelectionLead().column);
});
};
this.gotoPageDown = function() {
var row = this.getPageDownRow(),
column = Math.min(this.getCursorPosition().column,
this.session.getLine(row).length);
this.scrollToRow(row);
this.getSelection().moveCursorTo(row, column);
};
this.gotoPageUp = function() {
var row = this.getPageUpRow(),
column = Math.min(this.getCursorPosition().column,
this.session.getLine(row).length);
this.scrollToRow(row);
this.getSelection().moveCursorTo(row, column);
};
this.scrollPageDown = function() {
this.scrollToRow(this.getPageDownRow());
};
this.scrollPageUp = function() {
this.renderer.scrollToRow(this.getPageUpRow());
};
this.scrollToRow = function(row) {
this.renderer.scrollToRow(row);
};
this.getCursorPosition = function() {
return this.selection.getCursor();
};
this.getSelectionRange = function() {
return this.selection.getRange();
};
this.clearSelection = function() {
this.selection.clearSelection();
};
this.moveCursorTo = function(row, column) {
this.selection.moveCursorTo(row, column);
};
this.moveCursorToPosition = function(pos) {
this.selection.moveCursorToPosition(pos);
};
this.gotoLine = function(lineNumber, row) {
this.selection.clearSelection();
this.$blockScrolling = true;
this.moveCursorTo(lineNumber-1, row || 0);
this.$blockScrolling = false;
if (!this.isRowVisible(this.getCursorPosition().row)) {
this.scrollToRow(lineNumber - 1 - Math.floor(this.getVisibleRowCount() / 2));
}
},
this.navigateTo = function(row, column) {
this.clearSelection();
this.moveCursorTo(row, column);
};
this.navigateUp = function(times) {
this.selection.clearSelection();
this.selection.moveCursorBy(-1, 0);
};
this.navigateDown = function(times) {
this.selection.clearSelection();
this.selection.moveCursorBy(1, 0);
};
this.navigateLeft = function(times) {
if (!this.selection.isEmpty()) {
var selectionStart = this.getSelectionRange().start;
this.moveCursorToPosition(selectionStart);
}
else {
times = times || 1;
while (times--) {
this.selection.moveCursorLeft();
}
}
this.clearSelection();
};
this.navigateRight = function(times) {
if (!this.selection.isEmpty()) {
var selectionEnd = this.getSelectionRange().end;
this.moveCursorToPosition(selectionEnd);
}
else {
times = times || 1;
while (times--) {
this.selection.moveCursorRight();
}
}
this.clearSelection();
};
this.navigateLineStart = function() {
this.selection.moveCursorLineStart();
this.clearSelection();
};
this.navigateLineEnd = function() {
this.selection.moveCursorLineEnd();
this.clearSelection();
};
this.navigateFileEnd = function() {
this.selection.moveCursorFileEnd();
this.clearSelection();
};
this.navigateFileStart = function() {
this.selection.moveCursorFileStart();
this.clearSelection();
};
this.navigateWordRight = function() {
this.selection.moveCursorWordRight();
this.clearSelection();
};
this.navigateWordLeft = function() {
this.selection.moveCursorWordLeft();
this.clearSelection();
};
this.replace = function(replacement, options) {
if (options)
this.$search.set(options);
var range = this.$search.find(this.session);
this.$tryReplace(range, replacement);
if (range !== null)
this.selection.setSelectionRange(range);
},
this.replaceAll = function(replacement, options) {
if (options) {
this.$search.set(options);
}
var ranges = this.$search.findAll(this.session);
if (!ranges.length)
return;
this.clearSelection();
this.selection.moveCursorTo(0, 0);
for (var i = ranges.length - 1; i >= 0; --i)
this.$tryReplace(ranges[i], replacement);
if (ranges[0] !== null)
this.selection.setSelectionRange(ranges[0]);
},
this.$tryReplace = function(range, replacement) {
var input = this.session.getTextRange(range);
var replacement = this.$search.replace(input, replacement);
if (replacement !== null) {
range.end = this.session.replace(range, replacement);
return range;
} else {
return null;
}
};
this.getLastSearchOptions = function() {
return this.$search.getOptions();
};
this.find = function(needle, options) {
this.clearSelection();
options = options || {};
options.needle = needle;
this.$search.set(options);
this.$find();
},
this.findNext = function(options) {
options = options || {};
if (typeof options.backwards == "undefined")
options.backwards = false;
this.$search.set(options);
this.$find();
};
this.findPrevious = function(options) {
options = options || {};
if (typeof options.backwards == "undefined")
options.backwards = true;
this.$search.set(options);
this.$find();
};
this.$find = function(backwards) {
if (!this.selection.isEmpty()) {
this.$search.set({needle: this.session.getTextRange(this.getSelectionRange())});
}
if (typeof backwards != "undefined")
this.$search.set({backwards: backwards});
var range = this.$search.find(this.session);
if (range) {
this.gotoLine(range.end.row+1, range.end.column);
this.selection.setSelectionRange(range);
}
};
this.undo = function() {
this.session.getUndoManager().undo();
};
this.redo = function() {
this.session.getUndoManager().redo();
};
}).call(Editor.prototype);
exports.Editor = Editor;
});