lib/gollum/public/gollum/livepreview/js/ace/lib/ace/selection.js in gollum-3.1.2 vs lib/gollum/public/gollum/livepreview/js/ace/lib/ace/selection.js in gollum-3.1.3

- old
+ new

@@ -1,22 +1,22 @@ /* ***** BEGIN LICENSE BLOCK ***** * Distributed under the BSD license: * * Copyright (c) 2010, Ajax.org B.V. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Ajax.org B.V. nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES @@ -35,38 +35,31 @@ var lang = require("./lib/lang"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Range = require("./range").Range; /** - * * Contains the cursor position and the text selection of an edit session. * - * The row/columns used in the selection are in document coordinates representing ths coordinates as thez appear in the document before applying soft wrap and folding. + * The row/columns used in the selection are in document coordinates representing the coordinates as they appear in the document before applying soft wrap and folding. * @class Selection **/ /** * Emitted when the cursor position changes. * @event changeCursor * - * - * **/ /** * Emitted when the cursor selection changes. - * @event changeSelection - * * - * + * @event changeSelection **/ /** * Creates a new `Selection` object. * @param {EditSession} session The session to use - * * - * * @constructor **/ var Selection = function(session) { this.session = session; this.doc = session.getDocument(); @@ -93,22 +86,22 @@ (function() { oop.implement(this, EventEmitter); /** - * + * * Returns `true` if the selection is empty. * @returns {Boolean} **/ this.isEmpty = function() { return (this.$isEmpty || ( this.anchor.row == this.lead.row && this.anchor.column == this.lead.column )); }; - /** + /** * Returns `true` if the selection is a multi-line. * @returns {Boolean} **/ this.isMultiLine = function() { if (this.isEmpty()) { @@ -116,24 +109,24 @@ } return this.getRange().isMultiLine(); }; - /** - * Gets the current position of the cursor. - * @returns {Number} + /** + * Returns an object containing the `row` and `column` current position of the cursor. + * @returns {Object} **/ this.getCursor = function() { return this.lead.getPosition(); }; /** * Sets the row and column position of the anchor. This function also emits the `'changeSelection'` event. * @param {Number} row The new row * @param {Number} column The new column * - * + * **/ this.setSelectionAnchor = function(row, column) { this.anchor.setPosition(row, column); if (this.$isEmpty) { @@ -142,21 +135,23 @@ } }; /** * Returns an object containing the `row` and `column` of the calling selection anchor. + * + * @returns {Object} * @related Anchor.getPosition **/ this.getSelectionAnchor = function() { if (this.$isEmpty) - return this.getSelectionLead() + return this.getSelectionLead(); else return this.anchor.getPosition(); }; /** - * + * * Returns an object containing the `row` and `column` of the calling selection lead. * @returns {Object} **/ this.getSelectionLead = function() { return this.lead.getPosition(); @@ -164,18 +159,18 @@ /** * Shifts the selection up (or down, if [[Selection.isBackwards `isBackwards()`]] is true) the given number of columns. * @param {Number} columns The number of columns to shift by * - * * + * **/ this.shiftSelection = function(columns) { if (this.$isEmpty) { this.moveCursorTo(this.lead.row, this.lead.column + columns); return; - }; + } var anchor = this.getSelectionAnchor(); var lead = this.getSelectionLead(); var isBackwards = this.isBackwards(); @@ -241,22 +236,25 @@ /** * Sets the selection to the provided range. * @param {Range} range The range of text to select * @param {Boolean} reverse Indicates if the range should go backwards (`true`) or not * - * + * * @method setSelectionRange + * @alias setRange **/ this.setRange = this.setSelectionRange = function(range, reverse) { if (reverse) { this.setSelectionAnchor(range.end.row, range.end.column); this.selectTo(range.start.row, range.start.column); } else { this.setSelectionAnchor(range.start.row, range.start.column); this.selectTo(range.end.row, range.end.column); } + if (this.getRange().isEmpty()) + this.$isEmpty = true; this.$desiredColumn = null; }; this.$moveSelection = function(mover) { var lead = this.lead; @@ -269,12 +267,12 @@ /** * Moves the selection cursor to the indicated row and column. * @param {Number} row The row to select to * @param {Number} column The column to select to * - * * + * **/ this.selectTo = function(row, column) { this.$moveSelection(function() { this.moveCursorTo(row, column); }); @@ -282,101 +280,122 @@ /** * Moves the selection cursor to the row and column indicated by `pos`. * @param {Object} pos An object containing the row and column * - * * + * **/ this.selectToPosition = function(pos) { this.$moveSelection(function() { this.moveCursorToPosition(pos); }); }; /** - * + * Moves the selection cursor to the indicated row and column. + * @param {Number} row The row to select to + * @param {Number} column The column to select to + * + **/ + this.moveTo = function(row, column) { + this.clearSelection(); + this.moveCursorTo(row, column); + }; + + /** + * Moves the selection cursor to the row and column indicated by `pos`. + * @param {Object} pos An object containing the row and column + **/ + this.moveToPosition = function(pos) { + this.clearSelection(); + this.moveCursorToPosition(pos); + }; + + + /** + * * Moves the selection up one row. **/ this.selectUp = function() { this.$moveSelection(this.moveCursorUp); }; /** - * + * * Moves the selection down one row. **/ this.selectDown = function() { this.$moveSelection(this.moveCursorDown); }; /** - * * + * * Moves the selection right one column. **/ this.selectRight = function() { this.$moveSelection(this.moveCursorRight); }; /** - * + * * Moves the selection left one column. **/ this.selectLeft = function() { this.$moveSelection(this.moveCursorLeft); }; /** - * + * * Moves the selection to the beginning of the current line. **/ this.selectLineStart = function() { this.$moveSelection(this.moveCursorLineStart); }; /** - * + * * Moves the selection to the end of the current line. **/ this.selectLineEnd = function() { this.$moveSelection(this.moveCursorLineEnd); }; /** - * + * * Moves the selection to the end of the file. **/ this.selectFileEnd = function() { this.$moveSelection(this.moveCursorFileEnd); }; /** - * + * * Moves the selection to the start of the file. **/ this.selectFileStart = function() { this.$moveSelection(this.moveCursorFileStart); }; /** - * + * * Moves the selection to the first word on the right. **/ this.selectWordRight = function() { this.$moveSelection(this.moveCursorWordRight); }; /** - * + * * Moves the selection to the first word on the left. **/ this.selectWordLeft = function() { this.$moveSelection(this.moveCursorWordLeft); }; - /** + /** * Moves the selection to highlight the entire word. * @related EditSession.getWordRange **/ this.getWordRange = function(row, column) { if (typeof column == "undefined") { @@ -384,20 +403,20 @@ row = cursor.row; column = cursor.column; } return this.session.getWordRange(row, column); }; - + /** - * + * * Selects an entire word boundary. **/ this.selectWord = function() { this.setSelectionRange(this.getWordRange()); }; - /** + /** * Selects a word, including its right whitespace. * @related EditSession.getAWordRange **/ this.selectAWord = function() { var cursor = this.getCursor(); @@ -414,11 +433,11 @@ rowStart = foldLine.start.row; rowEnd = foldLine.end.row; } else { rowEnd = rowStart; } - if (excludeLastChar) + if (excludeLastChar === true) return new Range(rowStart, 0, rowEnd, this.session.getLine(rowEnd).length); else return new Range(rowStart, 0, rowEnd + 1, 0); }; @@ -428,36 +447,36 @@ this.selectLine = function() { this.setSelectionRange(this.getLineRange()); }; /** - * + * * Moves the cursor up one row. **/ this.moveCursorUp = function() { this.moveCursorBy(-1, 0); }; /** - * + * * Moves the cursor down one row. **/ this.moveCursorDown = function() { this.moveCursorBy(1, 0); }; /** - * + * * Moves the cursor left one column. **/ this.moveCursorLeft = function() { var cursor = this.lead.getPosition(), fold; if (fold = this.session.getFoldAt(cursor.row, cursor.column, -1)) { this.moveCursorTo(fold.start.row, fold.start.column); - } else if (cursor.column == 0) { + } else if (cursor.column === 0) { // cursor is a line (start if (cursor.row > 0) { this.moveCursorTo(cursor.row - 1, this.doc.getLine(cursor.row - 1).length); } } @@ -469,11 +488,11 @@ this.moveCursorBy(0, -1); } }; /** - * + * * Moves the cursor right one column. **/ this.moveCursorRight = function() { var cursor = this.lead.getPosition(), fold; @@ -494,11 +513,11 @@ this.moveCursorBy(0, 1); } }; /** - * + * * Moves the cursor to the start of the line. **/ this.moveCursorLineStart = function() { var row = this.lead.row; var column = this.lead.column; @@ -512,25 +531,18 @@ row, null, firstColumnPosition.row, firstColumnPosition.column ); var leadingSpace = beforeCursor.match(/^\s*/); - if (leadingSpace[0].length == column) { - this.moveCursorTo( - firstColumnPosition.row, firstColumnPosition.column - ); - } - else { - this.moveCursorTo( - firstColumnPosition.row, - firstColumnPosition.column + leadingSpace[0].length - ); - } + // TODO find better way for emacs mode to override selection behaviors + if (leadingSpace[0].length != column && !this.session.$useEmacsStyleLineStart) + firstColumnPosition.column += leadingSpace[0].length; + this.moveCursorToPosition(firstColumnPosition); }; /** - * + * * Moves the cursor to the end of the line. **/ this.moveCursorLineEnd = function() { var lead = this.lead; var lineEnd = this.session.getDocumentLastRowColumnPosition(lead.row, lead.column); @@ -545,29 +557,29 @@ this.moveCursorTo(lineEnd.row, lineEnd.column); }; /** - * + * * Moves the cursor to the end of the file. **/ this.moveCursorFileEnd = function() { var row = this.doc.getLength() - 1; var column = this.doc.getLine(row).length; this.moveCursorTo(row, column); }; /** - * + * * Moves the cursor to the start of the file. **/ this.moveCursorFileStart = function() { this.moveCursorTo(0, 0); }; /** - * + * * Moves the cursor to the word on the right. **/ this.moveCursorLongWordRight = function() { var row = this.lead.row; var column = this.lead.column; @@ -609,11 +621,11 @@ this.moveCursorTo(row, column); }; /** - * + * * Moves the cursor to the word on the left. **/ this.moveCursorLongWordLeft = function() { var row = this.lead.row; var column = this.lead.column; @@ -625,11 +637,11 @@ return; } var str = this.session.getFoldStringAt(row, column, -1); if (str == null) { - str = this.doc.getLine(row).substring(0, column) + str = this.doc.getLine(row).substring(0, column); } var leftOfCursor = lang.stringReverse(str); var match; this.session.nonTokenRe.lastIndex = 0; @@ -670,24 +682,24 @@ index = this.session.tokenRe.lastIndex; } else { while ((ch = rightOfCursor[index]) && whitespaceRe.test(ch)) index ++; - if (index <= 1) { + if (index < 1) { tokenRe.lastIndex = 0; while ((ch = rightOfCursor[index]) && !tokenRe.test(ch)) { tokenRe.lastIndex = 0; index ++; if (whitespaceRe.test(ch)) { if (index > 2) { - index-- + index--; break; } else { while ((ch = rightOfCursor[index]) && whitespaceRe.test(ch)) index ++; if (index > 2) - break + break; } } } } } @@ -706,17 +718,17 @@ if (fold) return this.moveCursorTo(fold.end.row, fold.end.column); if (column == line.length) { var l = this.doc.getLength(); - do { + do { row++; - rightOfCursor = this.doc.getLine(row) - } while (row < l && /^\s*$/.test(rightOfCursor)) - + rightOfCursor = this.doc.getLine(row); + } while (row < l && /^\s*$/.test(rightOfCursor)); + if (!/^\s+/.test(rightOfCursor)) - rightOfCursor = "" + rightOfCursor = ""; column = 0; } var index = this.$shortWordEndIndex(rightOfCursor); @@ -730,19 +742,19 @@ var fold; if (fold = this.session.getFoldAt(row, column, -1)) return this.moveCursorTo(fold.start.row, fold.start.column); var line = this.session.getLine(row).substring(0, column); - if (column == 0) { - do { + if (column === 0) { + do { row--; line = this.doc.getLine(row); - } while (row > 0 && /^\s*$/.test(line)) - + } while (row > 0 && /^\s*$/.test(line)); + column = line.length; if (!/\s+$/.test(line)) - line = "" + line = ""; } var leftOfCursor = lang.stringReverse(line); var index = this.$shortWordEndIndex(leftOfCursor); @@ -762,15 +774,15 @@ else this.moveCursorShortWordLeft(); }; /** - * Moves the cursor to position indicated by the parameters. Negative numbers move the cursor backwards in the document. + * Moves the cursor to position indicated by the parameters. Negative numbers move the cursor backwards in the document. * @param {Number} rows The number of rows to move by * @param {Number} chars The number of characters to move by * - * + * * @related EditSession.documentToScreenPosition **/ this.moveCursorBy = function(rows, chars) { var screenPos = this.session.documentToScreenPosition( this.lead.row, @@ -783,20 +795,25 @@ else this.$desiredColumn = screenPos.column; } var docPos = this.session.screenToDocumentPosition(screenPos.row + rows, screenPos.column); + + if (rows !== 0 && chars === 0 && docPos.row === this.lead.row && docPos.column === this.lead.column) { + if (this.session.lineWidgets && this.session.lineWidgets[docPos.row]) + docPos.row++; + } // move the cursor and update the desired column this.moveCursorTo(docPos.row, docPos.column + chars, chars === 0); }; /** * Moves the selection to the position indicated by its `row` and `column`. * @param {Object} position The position to move to * - * + * **/ this.moveCursorToPosition = function(position) { this.moveCursorTo(position.row, position.column); }; @@ -804,11 +821,11 @@ * Moves the cursor to the row and column provided. [If `preventUpdateDesiredColumn` is `true`, then the cursor stays in the same column position as its original point.]{: #preventUpdateBoolDesc} * @param {Number} row The row to move to * @param {Number} column The column to move to * @param {Boolean} keepDesiredColumn [If `true`, the cursor move does not respect the previous column]{: #preventUpdateBool} * - * + * **/ this.moveCursorTo = function(row, column, keepDesiredColumn) { // Ensure the row/column is not inside of a fold. var fold = this.session.getFoldAt(row, column, 1); if (fold) { @@ -828,11 +845,11 @@ * Moves the cursor to the screen position indicated by row and column. {:preventUpdateBoolDesc} * @param {Number} row The row to move to * @param {Number} column The column to move to * @param {Boolean} keepDesiredColumn {:preventUpdateBool} * - * + * **/ this.moveCursorToScreen = function(row, column, keepDesiredColumn) { var pos = this.session.screenToDocumentPosition(row, column); this.moveCursorTo(pos.row, pos.column, keepDesiredColumn); }; @@ -840,16 +857,16 @@ // remove listeners from document this.detach = function() { this.lead.detach(); this.anchor.detach(); this.session = this.doc = null; - } + }; this.fromOrientedRange = function(range) { this.setSelectionRange(range, range.cursor == range.start); this.$desiredColumn = range.desiredColumn || this.$desiredColumn; - } + }; this.toOrientedRange = function(range) { var r = this.getRange(); if (range) { range.start.column = r.start.column; @@ -861,10 +878,77 @@ } range.cursor = this.isBackwards() ? range.start : range.end; range.desiredColumn = this.$desiredColumn; return range; - } + }; + + /** + * Saves the current cursor position and calls `func` that can change the cursor + * postion. The result is the range of the starting and eventual cursor position. + * Will reset the cursor position. + * @param {Function} The callback that should change the cursor position + * @returns {Range} + * + **/ + this.getRangeOfMovements = function(func) { + var start = this.getCursor(); + try { + func.call(null, this); + var end = this.getCursor(); + return Range.fromPoints(start,end); + } catch(e) { + return Range.fromPoints(start,start); + } finally { + this.moveCursorToPosition(start); + } + }; + + this.toJSON = function() { + if (this.rangeCount) { + var data = this.ranges.map(function(r) { + var r1 = r.clone(); + r1.isBackwards = r.cursor == r.start; + return r1; + }); + } else { + var data = this.getRange(); + data.isBackwards = this.isBackwards(); + } + return data; + }; + + this.fromJSON = function(data) { + if (data.start == undefined) { + if (this.rangeList) { + this.toSingleRange(data[0]); + for (var i = data.length; i--; ) { + var r = Range.fromPoints(data[i].start, data[i].end); + if (data.isBackwards) + r.cursor = r.start; + this.addRange(r, true); + } + return; + } else + data = data[0]; + } + if (this.rangeList) + this.toSingleRange(data); + this.setSelectionRange(data, data.isBackwards); + }; + + this.isEqual = function(data) { + if ((data.length || this.rangeCount) && data.length != this.rangeCount) + return false; + if (!data.length || !this.ranges) + return this.getRange().isEqual(data); + + for (var i = this.ranges.length; i--; ) { + if (!this.ranges[i].isEqual(data[i])) + return false; + } + return true; + }; }).call(Selection.prototype); exports.Selection = Selection; });