| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- /* ***** 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(require, exports, module) {
- "use strict";
- var Range = require("../range").Range;
- /*
- * If an array is passed in, the folds are expected to be sorted already.
- */
- function FoldLine(foldData, folds) {
- this.foldData = foldData;
- if (Array.isArray(folds)) {
- this.folds = folds;
- } else {
- folds = this.folds = [ folds ];
- }
- var last = folds[folds.length - 1];
- this.range = new Range(folds[0].start.row, folds[0].start.column,
- last.end.row, last.end.column);
- this.start = this.range.start;
- this.end = this.range.end;
- this.folds.forEach(function(fold) {
- fold.setFoldLine(this);
- }, this);
- }
- (function() {
- /*
- * Note: This doesn't update wrapData!
- */
- this.shiftRow = function(shift) {
- this.start.row += shift;
- this.end.row += shift;
- this.folds.forEach(function(fold) {
- fold.start.row += shift;
- fold.end.row += shift;
- });
- };
- this.addFold = function(fold) {
- if (fold.sameRow) {
- if (fold.start.row < this.startRow || fold.endRow > this.endRow) {
- throw new Error("Can't add a fold to this FoldLine as it has no connection");
- }
- this.folds.push(fold);
- this.folds.sort(function(a, b) {
- return -a.range.compareEnd(b.start.row, b.start.column);
- });
- if (this.range.compareEnd(fold.start.row, fold.start.column) > 0) {
- this.end.row = fold.end.row;
- this.end.column = fold.end.column;
- } else if (this.range.compareStart(fold.end.row, fold.end.column) < 0) {
- this.start.row = fold.start.row;
- this.start.column = fold.start.column;
- }
- } else if (fold.start.row == this.end.row) {
- this.folds.push(fold);
- this.end.row = fold.end.row;
- this.end.column = fold.end.column;
- } else if (fold.end.row == this.start.row) {
- this.folds.unshift(fold);
- this.start.row = fold.start.row;
- this.start.column = fold.start.column;
- } else {
- throw new Error("Trying to add fold to FoldRow that doesn't have a matching row");
- }
- fold.foldLine = this;
- };
- this.containsRow = function(row) {
- return row >= this.start.row && row <= this.end.row;
- };
- this.walk = function(callback, endRow, endColumn) {
- var lastEnd = 0,
- folds = this.folds,
- fold,
- cmp, stop, isNewRow = true;
- if (endRow == null) {
- endRow = this.end.row;
- endColumn = this.end.column;
- }
- for (var i = 0; i < folds.length; i++) {
- fold = folds[i];
- cmp = fold.range.compareStart(endRow, endColumn);
- // This fold is after the endRow/Column.
- if (cmp == -1) {
- callback(null, endRow, endColumn, lastEnd, isNewRow);
- return;
- }
- stop = callback(null, fold.start.row, fold.start.column, lastEnd, isNewRow);
- stop = !stop && callback(fold.placeholder, fold.start.row, fold.start.column, lastEnd);
- // If the user requested to stop the walk or endRow/endColumn is
- // inside of this fold (cmp == 0), then end here.
- if (stop || cmp === 0) {
- return;
- }
- // Note the new lastEnd might not be on the same line. However,
- // it's the callback's job to recognize this.
- isNewRow = !fold.sameRow;
- lastEnd = fold.end.column;
- }
- callback(null, endRow, endColumn, lastEnd, isNewRow);
- };
- this.getNextFoldTo = function(row, column) {
- var fold, cmp;
- for (var i = 0; i < this.folds.length; i++) {
- fold = this.folds[i];
- cmp = fold.range.compareEnd(row, column);
- if (cmp == -1) {
- return {
- fold: fold,
- kind: "after"
- };
- } else if (cmp === 0) {
- return {
- fold: fold,
- kind: "inside"
- };
- }
- }
- return null;
- };
- this.addRemoveChars = function(row, column, len) {
- var ret = this.getNextFoldTo(row, column),
- fold, folds;
- if (ret) {
- fold = ret.fold;
- if (ret.kind == "inside"
- && fold.start.column != column
- && fold.start.row != row)
- {
- //throwing here breaks whole editor
- //TODO: properly handle this
- window.console && window.console.log(row, column, fold);
- } else if (fold.start.row == row) {
- folds = this.folds;
- var i = folds.indexOf(fold);
- if (i === 0) {
- this.start.column += len;
- }
- for (i; i < folds.length; i++) {
- fold = folds[i];
- fold.start.column += len;
- if (!fold.sameRow) {
- return;
- }
- fold.end.column += len;
- }
- this.end.column += len;
- }
- }
- };
- this.split = function(row, column) {
- var pos = this.getNextFoldTo(row, column);
-
- if (!pos || pos.kind == "inside")
- return null;
-
- var fold = pos.fold;
- var folds = this.folds;
- var foldData = this.foldData;
-
- var i = folds.indexOf(fold);
- var foldBefore = folds[i - 1];
- this.end.row = foldBefore.end.row;
- this.end.column = foldBefore.end.column;
- // Remove the folds after row/column and create a new FoldLine
- // containing these removed folds.
- folds = folds.splice(i, folds.length - i);
- var newFoldLine = new FoldLine(foldData, folds);
- foldData.splice(foldData.indexOf(this) + 1, 0, newFoldLine);
- return newFoldLine;
- };
- this.merge = function(foldLineNext) {
- var folds = foldLineNext.folds;
- for (var i = 0; i < folds.length; i++) {
- this.addFold(folds[i]);
- }
- // Remove the foldLineNext - no longer needed, as
- // it's merged now with foldLineNext.
- var foldData = this.foldData;
- foldData.splice(foldData.indexOf(foldLineNext), 1);
- };
- this.toString = function() {
- var ret = [this.range.toString() + ": [" ];
- this.folds.forEach(function(fold) {
- ret.push(" " + fold.toString());
- });
- ret.push("]");
- return ret.join("\n");
- };
- this.idxToPosition = function(idx) {
- var lastFoldEndColumn = 0;
- for (var i = 0; i < this.folds.length; i++) {
- var fold = this.folds[i];
- idx -= fold.start.column - lastFoldEndColumn;
- if (idx < 0) {
- return {
- row: fold.start.row,
- column: fold.start.column + idx
- };
- }
- idx -= fold.placeholder.length;
- if (idx < 0) {
- return fold.start;
- }
- lastFoldEndColumn = fold.end.column;
- }
- return {
- row: this.end.row,
- column: this.end.column + idx
- };
- };
- }).call(FoldLine.prototype);
- exports.FoldLine = FoldLine;
- });
|