fix moving lines with folds

This commit is contained in:
nightwing 2013-02-24 01:17:56 +04:00
commit 43854d7a35
2 changed files with 91 additions and 76 deletions

2
build

@ -1 +1 @@
Subproject commit 75ba742f4f00cefadfef1ae451cfb2a4280ad367
Subproject commit 1e3407af692eaf661800083897c73d46d0a4bc46

View file

@ -3,7 +3,7 @@
*
* 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
@ -14,7 +14,7 @@
* * 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
@ -44,8 +44,8 @@ var SearchHighlight = require("./search_highlight").SearchHighlight;
var config = require("./config");
/**
* Stores all the data about [[Editor `Editor`]] state providing easy way to change editors state.
*
* Stores all the data about [[Editor `Editor`]] state providing easy way to change editors state.
*
* `EditSession` can be attached to only one [[Document `Document`]]. Same `Document` can be attached to several `EditSession`s.
* @class EditSession
**/
@ -94,19 +94,19 @@ var config = require("./config");
* @param {Object} e An object containing one property, `"data"`, that contains information about the changing rows
*
**/
/**
/**
* Emitted when the current mode changes.
*
* @event changeMode
*
**/
/**
/**
* Emitted when the wrap mode changes.
*
* @event changeWrapMode
*
**/
/**
/**
* Emitted when the wrapping limit changes.
*
* @event changeWrapLimit
@ -148,14 +148,14 @@ var EditSession = function(text, mode) {
this.$backMarkers = {};
this.$markerId = 1;
this.$undoSelect = true;
this.$foldData = [];
this.$foldData.toString = function() {
return this.join("\n");
}
this.on("changeFold", this.onChangeFold.bind(this));
this.$onChange = this.onChange.bind(this);
if (typeof text != "object" || !text.getLine)
text = new Document(text);
@ -194,13 +194,13 @@ var EditSession = function(text, mode) {
/**
* Returns the `Document` associated with this session.
* @return {Document}
* @return {Document}
**/
this.getDocument = function() {
return this.doc;
};
/**
/**
* @param {Number} row The row to work with
*
**/
@ -293,19 +293,19 @@ var EditSession = function(text, mode) {
this.getUndoManager().reset();
};
/**
/**
* Returns the current [[Document `Document`]] as a string.
* @method toString
* @returns {String}
* @alias EditSession.getValue
* @alias EditSession.getValue
*
**/
/**
/**
* Returns the current [[Document `Document`]] as a string.
* @method getValue
* @returns {String}
* @alias EditSession.toString
* @alias EditSession.toString
**/
this.getValue =
this.toString = function() {
@ -319,7 +319,7 @@ var EditSession = function(text, mode) {
return this.selection;
};
/**
/**
* {:BackgroundTokenizer.getState}
* @param {Number} row The row to start at
*
@ -329,7 +329,7 @@ var EditSession = function(text, mode) {
return this.bgTokenizer.getState(row);
};
/**
/**
* Starts tokenizing at the row indicated. Returns a list of objects of the tokenized rows.
* @param {Number} row The row to start at
*
@ -483,7 +483,7 @@ var EditSession = function(text, mode) {
this.$overwrite = false;
/**
* Pass in `true` to enable overwrites in your session, or `false` to disable.
* Pass in `true` to enable overwrites in your session, or `false` to disable.
*
* If overwrites is enabled, any text you enter will type over any text after it. If the value of `overwrite` changes, this function also emites the `changeOverwrite` event.
*
@ -537,7 +537,7 @@ var EditSession = function(text, mode) {
this.$decorations[row] = (this.$decorations[row] || "").replace(" " + className, "");
this._emit("changeBreakpoint", {});
};
/**
* Returns an array of numbers, indicating which rows have breakpoints.
* @returns {[Number]}
@ -635,7 +635,7 @@ var EditSession = function(text, mode) {
* @param {Object} marker object with update method
* @param {Boolean} inFront Set to `true` to establish a front marker
*
*
*
* @return {Object} The added marker
**/
this.addDynamicMarker = function(marker, inFront) {
@ -692,7 +692,7 @@ var EditSession = function(text, mode) {
}
this.$searchHighlight.setRegexp(re);
}
// experimental
this.highlightLines = function(startRow, endRow, clazz, inFront) {
if (typeof endRow != "number") {
@ -701,12 +701,12 @@ var EditSession = function(text, mode) {
}
if (!clazz)
clazz = "ace_step";
var range = new Range(startRow, 0, endRow, Infinity);
range.id = this.addMarker(range, clazz, "fullLine", inFront);
return range;
};
/*
* Error:
* {
@ -741,7 +741,7 @@ var EditSession = function(text, mode) {
this.setAnnotations([]);
};
/**
/**
* If `text` contains either the newline (`\n`) or carriage-return ('\r') characters, `$autoNewLine` stores that value.
* @param {String} text A block of text
*
@ -772,7 +772,7 @@ var EditSession = function(text, mode) {
if (!inToken)
inToken = !!line.charAt(column).match(this.tokenRe);
if (inToken)
var re = this.tokenRe;
else if (/^\s+$/.test(line.slice(column-1, column+1)))
@ -814,7 +814,7 @@ var EditSession = function(text, mode) {
return wordRange;
};
/**
/**
* {:Document.setNewLineMode.desc}
* @param {String} newLineMode {:Document.setNewLineMode.param}
*
@ -825,7 +825,7 @@ var EditSession = function(text, mode) {
this.doc.setNewLineMode(newLineMode);
};
/**
/**
*
* Returns the current new line mode.
* @returns {String}
@ -1061,7 +1061,7 @@ var EditSession = function(text, mode) {
}
};
/**
/**
* Returns a verbatim copy of the given line as it is in the document
* @param {Number} row The row to retrieve from
*
@ -1073,7 +1073,7 @@ var EditSession = function(text, mode) {
return this.doc.getLine(row);
};
/**
/**
* Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`.
* @param {Number} firstRow The first row index to retrieve
* @param {Number} lastRow The final row index to retrieve
@ -1085,7 +1085,7 @@ var EditSession = function(text, mode) {
return this.doc.getLines(firstRow, lastRow);
};
/**
/**
* Returns the number of rows in the document.
* @returns {Number}
**/
@ -1093,7 +1093,7 @@ var EditSession = function(text, mode) {
return this.doc.getLength();
};
/**
/**
* {:Document.getTextRange.desc}
* @param {Range} range The range to work with
*
@ -1103,7 +1103,7 @@ var EditSession = function(text, mode) {
return this.doc.getTextRange(range || this.selection.getRange());
};
/**
/**
* Inserts a block of `text` and the indicated `position`.
* @param {Object} position The position {row, column} to start inserting at
* @param {String} text A chunk of text to insert
@ -1115,7 +1115,7 @@ var EditSession = function(text, mode) {
return this.doc.insert(position, text);
};
/**
/**
* Removes the `range` from the document.
* @param {Range} range A specified Range to remove
* @returns {Object} The new `start` property of the range, which contains `startRow` and `startColumn`. If `range` is empty, this function returns the unmodified value of `range.start`.
@ -1132,7 +1132,7 @@ var EditSession = function(text, mode) {
* @param {Array} deltas An array of previous changes
* @param {Boolean} dontSelect [If `true`, doesn't select the range of where the change occured]{: #dontSelect}
*
*
*
* @returns {Range}
**/
this.undoChanges = function(deltas, dontSelect) {
@ -1254,16 +1254,16 @@ var EditSession = function(text, mode) {
return range;
};
/**
/**
* Replaces a range in the document with the new `text`.
*
* @param {Range} range A specified Range to replace
* @param {String} text The new text to use as a replacement
* @returns {Object} An object containing the final row and column, like this:
* @returns {Object} An object containing the final row and column, like this:
* ```
* {row: endRow, column: 0}
* ```
* If the text and range are empty, this function returns an object containing the current `range.start` value.
* ```
* If the text and range are empty, this function returns an object containing the current `range.start` value.
* If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value.
*
*
@ -1364,7 +1364,39 @@ var EditSession = function(text, mode) {
}
};
/**
this.$moveLines = function(firstRow, lastRow, dir) {
var firstRow = this.getRowFoldStart(firstRow);
var lastRow = this.getRowFoldEnd(lastRow);
if (dir < 0) {
var row = this.getRowFoldStart(firstRow + dir);
if (row < 0) return 0;
var diff = row-firstRow;
} else if (dir > 0) {
var row = this.getRowFoldEnd(lastRow + dir);
if (row > this.doc.getLength()-1) return 0;
var diff = row-lastRow;
} else {
firstRow = this.$clipRowToDocument(firstRow);
lastRow = this.$clipRowToDocument(lastRow);
var diff = lastRow - firstRow + 1;
}
var range = new Range(firstRow, 0, lastRow, Number.MAX_VALUE);
var folds = this.getFoldsInRange(range).map(function(x){
x = x.clone();
x.start.row += diff;
x.end.row += diff;
return x;
});
var lines = dir == 0
? this.doc.getLines(firstRow, lastRow)
: this.doc.removeLines(firstRow, lastRow);
this.doc.insertLines(firstRow+diff, lines);
folds.length && this.addFolds(folds);
return diff;
};
/**
* Shifts all the lines in the document up one, starting from `firstRow` and ending at `lastRow`.
* @param {Number} firstRow The starting row to move up
* @param {Number} lastRow The final row to move up
@ -1374,29 +1406,19 @@ var EditSession = function(text, mode) {
*
**/
this.moveLinesUp = function(firstRow, lastRow) {
if (firstRow <= 0) return 0;
var removed = this.doc.removeLines(firstRow, lastRow);
this.doc.insertLines(firstRow - 1, removed);
return -1;
return this.$moveLines(firstRow, lastRow, -1);
};
/**
/**
* Shifts all the lines in the document down one, starting from `firstRow` and ending at `lastRow`.
* @param {Number} firstRow The starting row to move down
* @param {Number} lastRow The final row to move down
* @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1.
*
*
*
* @related Document.insertLines
**/
this.moveLinesDown = function(firstRow, lastRow) {
if (lastRow >= this.doc.getLength()-1) return 0;
var removed = this.doc.removeLines(firstRow, lastRow);
this.doc.insertLines(firstRow+1, removed);
return 1;
return this.$moveLines(firstRow, lastRow, 1);
};
/**
@ -1408,14 +1430,7 @@ var EditSession = function(text, mode) {
*
**/
this.duplicateLines = function(firstRow, lastRow) {
var firstRow = this.$clipRowToDocument(firstRow);
var lastRow = this.$clipRowToDocument(lastRow);
var lines = this.getLines(firstRow, lastRow);
this.doc.insertLines(firstRow, lines);
var addedRows = lastRow - firstRow + 1;
return addedRows;
return this.$moveLines(firstRow, lastRow, 0);
};
@ -1539,12 +1554,12 @@ var EditSession = function(text, mode) {
}
};
/**
/**
* This should generally only be called by the renderer when a resize is detected.
* @param {Number} desiredLimit The new wrap limit
* @returns {Boolean}
*
*
*
* @private
**/
this.adjustWrapLimit = function(desiredLimit) {
@ -1993,7 +2008,7 @@ var EditSession = function(text, mode) {
}
};
/**
/**
* Returns the position (on screen) for the last character in the provided screen row.
* @param {Number} screenRow The screen row to check
* @returns {Number}
@ -2005,21 +2020,21 @@ var EditSession = function(text, mode) {
return this.documentToScreenColumn(pos.row, pos.column);
};
/**
/**
* For the given document row and column, this returns the column position of the last screen row.
* @param {Number} docRow
* @param {Number} docRow
*
* @param {Number} docColumn
* @param {Number} docColumn
**/
this.getDocumentLastRowColumn = function(docRow, docColumn) {
var screenRow = this.documentToScreenRow(docRow, docColumn);
return this.getScreenLastRowColumn(screenRow);
};
/**
/**
* For the given document row and column, this returns the document position of the last row.
* @param {Number} docRow
* @param {Number} docColumn
* @param {Number} docRow
* @param {Number} docColumn
*
*
**/
@ -2028,7 +2043,7 @@ var EditSession = function(text, mode) {
return this.screenToDocumentPosition(screenRow, Number.MAX_VALUE / 10);
};
/**
/**
* For the given row, this returns the split data.
* @returns {String}
**/
@ -2044,7 +2059,7 @@ var EditSession = function(text, mode) {
* The distance to the next tab stop at the specified screen column.
* @param {Number} screenColumn The screen column to check
*
*
*
* @returns {Number}
**/
this.getScreenTabSize = function(screenColumn) {
@ -2061,7 +2076,7 @@ var EditSession = function(text, mode) {
return this.screenToDocumentPosition(screenRow, screenColumn).column;
};
/**
/**
* Converts characters coordinates on the screen to characters coordinates within the document. [This takes into account code folding, word wrap, tab size, and any other visual modifications.]{: #conversionConsiderations}
* @param {Number} screenRow The screen row to check
* @param {Number} screenColumn The screen column to check
@ -2110,7 +2125,7 @@ var EditSession = function(text, mode) {
foldStart = foldLine ? foldLine.start.row : Infinity;
}
}
if (doCache) {
this.$docRowCache.push(docRow);
this.$screenRowCache.push(row);
@ -2155,7 +2170,7 @@ var EditSession = function(text, mode) {
return {row: docRow, column: docColumn};
};
/**
/**
* Converts document coordinates to screen coordinates. {:conversionConsiderations}
* @param {Number} docRow The document row to check
* @param {Number} docColumn The document column to check