123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 |
- /* ***** 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
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ***** END LICENSE BLOCK ***** */
- define(function(ace_require, exports, module) {
- "use strict";
- var comparePoints = function(p1, p2) {
- return p1.row - p2.row || p1.column - p2.column;
- };
- /**
- * This object is used in various places to indicate a region within the editor. To better visualize how this works, imagine a rectangle. Each quadrant of the rectangle is analogous to a range, as ranges contain a starting row and starting column, and an ending row, and ending column.
- * @class Range
- **/
- /**
- * Creates a new `Range` object with the given starting and ending row and column points.
- * @param {Number} startRow The starting row
- * @param {Number} startColumn The starting column
- * @param {Number} endRow The ending row
- * @param {Number} endColumn The ending column
- *
- * @constructor
- **/
- var Range = function(startRow, startColumn, endRow, endColumn) {
- this.start = {
- row: startRow,
- column: startColumn
- };
- this.end = {
- row: endRow,
- column: endColumn
- };
- };
- (function() {
- /**
- * Returns `true` if and only if the starting row and column, and ending row and column, are equivalent to those given by `range`.
- * @param {Range} range A range to check against
- *
- * @return {Boolean}
- **/
- this.isEqual = function(range) {
- return this.start.row === range.start.row &&
- this.end.row === range.end.row &&
- this.start.column === range.start.column &&
- this.end.column === range.end.column;
- };
- /**
- *
- * Returns a string containing the range's row and column information, given like this:
- * ```
- * [start.row/start.column] -> [end.row/end.column]
- * ```
- * @return {String}
- **/
- this.toString = function() {
- return ("Range: [" + this.start.row + "/" + this.start.column +
- "] -> [" + this.end.row + "/" + this.end.column + "]");
- };
- /**
- *
- * Returns `true` if the `row` and `column` provided are within the given range. This can better be expressed as returning `true` if:
- * ```javascript
- * this.start.row <= row <= this.end.row &&
- * this.start.column <= column <= this.end.column
- * ```
- * @param {Number} row A row to check for
- * @param {Number} column A column to check for
- * @returns {Boolean}
- * @related Range.compare
- **/
- this.contains = function(row, column) {
- return this.compare(row, column) == 0;
- };
- /**
- * Compares `this` range (A) with another range (B).
- * @param {Range} range A range to compare with
- *
- * @related Range.compare
- * @returns {Number} This method returns one of the following numbers:<br/>
- * <br/>
- * * `-2`: (B) is in front of (A), and doesn't intersect with (A)<br/>
- * * `-1`: (B) begins before (A) but ends inside of (A)<br/>
- * * `0`: (B) is completely inside of (A) OR (A) is completely inside of (B)<br/>
- * * `+1`: (B) begins inside of (A) but ends outside of (A)<br/>
- * * `+2`: (B) is after (A) and doesn't intersect with (A)<br/>
- * * `42`: FTW state: (B) ends in (A) but starts outside of (A)
- **/
- this.compareRange = function(range) {
- var cmp,
- end = range.end,
- start = range.start;
- cmp = this.compare(end.row, end.column);
- if (cmp == 1) {
- cmp = this.compare(start.row, start.column);
- if (cmp == 1) {
- return 2;
- } else if (cmp == 0) {
- return 1;
- } else {
- return 0;
- }
- } else if (cmp == -1) {
- return -2;
- } else {
- cmp = this.compare(start.row, start.column);
- if (cmp == -1) {
- return -1;
- } else if (cmp == 1) {
- return 42;
- } else {
- return 0;
- }
- }
- };
- /**
- * Checks the row and column points of `p` with the row and column points of the calling range.
- *
- * @param {Range} p A point to compare with
- *
- * @related Range.compare
- * @returns {Number} This method returns one of the following numbers:<br/>
- * * `0` if the two points are exactly equal<br/>
- * * `-1` if `p.row` is less then the calling range<br/>
- * * `1` if `p.row` is greater than the calling range<br/>
- * <br/>
- * If the starting row of the calling range is equal to `p.row`, and:<br/>
- * * `p.column` is greater than or equal to the calling range's starting column, this returns `0`<br/>
- * * Otherwise, it returns -1<br/>
- *<br/>
- * If the ending row of the calling range is equal to `p.row`, and:<br/>
- * * `p.column` is less than or equal to the calling range's ending column, this returns `0`<br/>
- * * Otherwise, it returns 1<br/>
- **/
- this.comparePoint = function(p) {
- return this.compare(p.row, p.column);
- };
- /**
- * Checks the start and end points of `range` and compares them to the calling range. Returns `true` if the `range` is contained within the caller's range.
- * @param {Range} range A range to compare with
- *
- * @returns {Boolean}
- * @related Range.comparePoint
- **/
- this.containsRange = function(range) {
- return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
- };
- /**
- * Returns `true` if passed in `range` intersects with the one calling this method.
- * @param {Range} range A range to compare with
- *
- * @returns {Boolean}
- **/
- this.intersects = function(range) {
- var cmp = this.compareRange(range);
- return (cmp == -1 || cmp == 0 || cmp == 1);
- };
- /**
- * Returns `true` if the caller's ending row point is the same as `row`, and if the caller's ending column is the same as `column`.
- * @param {Number} row A row point to compare with
- * @param {Number} column A column point to compare with
- *
- * @returns {Boolean}
- **/
- this.isEnd = function(row, column) {
- return this.end.row == row && this.end.column == column;
- };
- /**
- * Returns `true` if the caller's starting row point is the same as `row`, and if the caller's starting column is the same as `column`.
- * @param {Number} row A row point to compare with
- * @param {Number} column A column point to compare with
- *
- * @returns {Boolean}
- **/
- this.isStart = function(row, column) {
- return this.start.row == row && this.start.column == column;
- };
- /**
- * Sets the starting row and column for the range.
- * @param {Number} row A row point to set
- * @param {Number} column A column point to set
- *
- **/
- this.setStart = function(row, column) {
- if (typeof row == "object") {
- this.start.column = row.column;
- this.start.row = row.row;
- } else {
- this.start.row = row;
- this.start.column = column;
- }
- };
- /**
- * Sets the starting row and column for the range.
- * @param {Number} row A row point to set
- * @param {Number} column A column point to set
- *
- **/
- this.setEnd = function(row, column) {
- if (typeof row == "object") {
- this.end.column = row.column;
- this.end.row = row.row;
- } else {
- this.end.row = row;
- this.end.column = column;
- }
- };
- /**
- * Returns `true` if the `row` and `column` are within the given range.
- * @param {Number} row A row point to compare with
- * @param {Number} column A column point to compare with
- *
- *
- * @returns {Boolean}
- * @related Range.compare
- **/
- this.inside = function(row, column) {
- if (this.compare(row, column) == 0) {
- if (this.isEnd(row, column) || this.isStart(row, column)) {
- return false;
- } else {
- return true;
- }
- }
- return false;
- };
- /**
- * Returns `true` if the `row` and `column` are within the given range's starting points.
- * @param {Number} row A row point to compare with
- * @param {Number} column A column point to compare with
- *
- * @returns {Boolean}
- * @related Range.compare
- **/
- this.insideStart = function(row, column) {
- if (this.compare(row, column) == 0) {
- if (this.isEnd(row, column)) {
- return false;
- } else {
- return true;
- }
- }
- return false;
- };
- /**
- * Returns `true` if the `row` and `column` are within the given range's ending points.
- * @param {Number} row A row point to compare with
- * @param {Number} column A column point to compare with
- *
- * @returns {Boolean}
- * @related Range.compare
- *
- **/
- this.insideEnd = function(row, column) {
- if (this.compare(row, column) == 0) {
- if (this.isStart(row, column)) {
- return false;
- } else {
- return true;
- }
- }
- return false;
- };
- /**
- * Checks the row and column points with the row and column points of the calling range.
- * @param {Number} row A row point to compare with
- * @param {Number} column A column point to compare with
- *
- *
- * @returns {Number} This method returns one of the following numbers:<br/>
- * `0` if the two points are exactly equal <br/>
- * `-1` if `p.row` is less then the calling range <br/>
- * `1` if `p.row` is greater than the calling range <br/>
- * <br/>
- * If the starting row of the calling range is equal to `p.row`, and: <br/>
- * `p.column` is greater than or equal to the calling range's starting column, this returns `0`<br/>
- * Otherwise, it returns -1<br/>
- * <br/>
- * If the ending row of the calling range is equal to `p.row`, and: <br/>
- * `p.column` is less than or equal to the calling range's ending column, this returns `0` <br/>
- * Otherwise, it returns 1
- **/
- this.compare = function(row, column) {
- if (!this.isMultiLine()) {
- if (row === this.start.row) {
- return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0);
- }
- }
- if (row < this.start.row)
- return -1;
- if (row > this.end.row)
- return 1;
- if (this.start.row === row)
- return column >= this.start.column ? 0 : -1;
- if (this.end.row === row)
- return column <= this.end.column ? 0 : 1;
- return 0;
- };
- /**
- * Checks the row and column points with the row and column points of the calling range.
- * @param {Number} row A row point to compare with
- * @param {Number} column A column point to compare with
- *
- * @returns {Number} This method returns one of the following numbers:<br/>
- * <br/>
- * `0` if the two points are exactly equal<br/>
- * `-1` if `p.row` is less then the calling range<br/>
- * `1` if `p.row` is greater than the calling range, or if `isStart` is `true`.<br/>
- * <br/>
- * If the starting row of the calling range is equal to `p.row`, and:<br/>
- * `p.column` is greater than or equal to the calling range's starting column, this returns `0`<br/>
- * Otherwise, it returns -1<br/>
- * <br/>
- * If the ending row of the calling range is equal to `p.row`, and:<br/>
- * `p.column` is less than or equal to the calling range's ending column, this returns `0`<br/>
- * Otherwise, it returns 1
- *
- **/
- this.compareStart = function(row, column) {
- if (this.start.row == row && this.start.column == column) {
- return -1;
- } else {
- return this.compare(row, column);
- }
- };
- /**
- * Checks the row and column points with the row and column points of the calling range.
- * @param {Number} row A row point to compare with
- * @param {Number} column A column point to compare with
- *
- *
- * @returns {Number} This method returns one of the following numbers:<br/>
- * `0` if the two points are exactly equal<br/>
- * `-1` if `p.row` is less then the calling range<br/>
- * `1` if `p.row` is greater than the calling range, or if `isEnd` is `true.<br/>
- * <br/>
- * If the starting row of the calling range is equal to `p.row`, and:<br/>
- * `p.column` is greater than or equal to the calling range's starting column, this returns `0`<br/>
- * Otherwise, it returns -1<br/>
- *<br/>
- * If the ending row of the calling range is equal to `p.row`, and:<br/>
- * `p.column` is less than or equal to the calling range's ending column, this returns `0`<br/>
- * Otherwise, it returns 1
- */
- this.compareEnd = function(row, column) {
- if (this.end.row == row && this.end.column == column) {
- return 1;
- } else {
- return this.compare(row, column);
- }
- };
- /**
- * Checks the row and column points with the row and column points of the calling range.
- * @param {Number} row A row point to compare with
- * @param {Number} column A column point to compare with
- *
- *
- * @returns {Number} This method returns one of the following numbers:<br/>
- * * `1` if the ending row of the calling range is equal to `row`, and the ending column of the calling range is equal to `column`<br/>
- * * `-1` if the starting row of the calling range is equal to `row`, and the starting column of the calling range is equal to `column`<br/>
- * <br/>
- * Otherwise, it returns the value after calling [[Range.compare `compare()`]].
- *
- **/
- this.compareInside = function(row, column) {
- if (this.end.row == row && this.end.column == column) {
- return 1;
- } else if (this.start.row == row && this.start.column == column) {
- return -1;
- } else {
- return this.compare(row, column);
- }
- };
- /**
- * Returns the part of the current `Range` that occurs within the boundaries of `firstRow` and `lastRow` as a new `Range` object.
- * @param {Number} firstRow The starting row
- * @param {Number} lastRow The ending row
- *
- *
- * @returns {Range}
- **/
- this.clipRows = function(firstRow, lastRow) {
- if (this.end.row > lastRow)
- var end = {row: lastRow + 1, column: 0};
- else if (this.end.row < firstRow)
- var end = {row: firstRow, column: 0};
- if (this.start.row > lastRow)
- var start = {row: lastRow + 1, column: 0};
- else if (this.start.row < firstRow)
- var start = {row: firstRow, column: 0};
- return Range.fromPoints(start || this.start, end || this.end);
- };
- /**
- * Changes the row and column points for the calling range for both the starting and ending points.
- * @param {Number} row A new row to extend to
- * @param {Number} column A new column to extend to
- *
- *
- * @returns {Range} The original range with the new row
- **/
- this.extend = function(row, column) {
- var cmp = this.compare(row, column);
- if (cmp == 0)
- return this;
- else if (cmp == -1)
- var start = {row: row, column: column};
- else
- var end = {row: row, column: column};
- return Range.fromPoints(start || this.start, end || this.end);
- };
- this.isEmpty = function() {
- return (this.start.row === this.end.row && this.start.column === this.end.column);
- };
- /**
- *
- * Returns `true` if the range spans across multiple lines.
- * @returns {Boolean}
- **/
- this.isMultiLine = function() {
- return (this.start.row !== this.end.row);
- };
- /**
- *
- * Returns a duplicate of the calling range.
- * @returns {Range}
- **/
- this.clone = function() {
- return Range.fromPoints(this.start, this.end);
- };
- /**
- *
- * Returns a range containing the starting and ending rows of the original range, but with a column value of `0`.
- * @returns {Range}
- **/
- this.collapseRows = function() {
- if (this.end.column == 0)
- return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0);
- else
- return new Range(this.start.row, 0, this.end.row, 0);
- };
- /**
- * Given the current `Range`, this function converts those starting and ending points into screen positions, and then returns a new `Range` object.
- * @param {EditSession} session The `EditSession` to retrieve coordinates from
- *
- *
- * @returns {Range}
- **/
- this.toScreenRange = function(session) {
- var screenPosStart = session.documentToScreenPosition(this.start);
- var screenPosEnd = session.documentToScreenPosition(this.end);
- return new Range(
- screenPosStart.row, screenPosStart.column,
- screenPosEnd.row, screenPosEnd.column
- );
- };
-
-
- /* experimental */
- this.moveBy = function(row, column) {
- this.start.row += row;
- this.start.column += column;
- this.end.row += row;
- this.end.column += column;
- };
- }).call(Range.prototype);
- /**
- * Creates and returns a new `Range` based on the row and column of the given parameters.
- * @param {Range} start A starting point to use
- * @param {Range} end An ending point to use
- *
- * @returns {Range}
- **/
- Range.fromPoints = function(start, end) {
- return new Range(start.row, start.column, end.row, end.column);
- };
- Range.comparePoints = comparePoints;
- Range.comparePoints = function(p1, p2) {
- return p1.row - p2.row || p1.column - p2.column;
- };
- exports.Range = Range;
- });
|