From 43854d7a351e3a8f58635839a54feaafd2f98c00 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sun, 24 Feb 2013 01:17:56 +0400 Subject: [PATCH] fix moving lines with folds --- build | 2 +- lib/ace/edit_session.js | 165 ++++++++++++++++++++++------------------ 2 files changed, 91 insertions(+), 76 deletions(-) diff --git a/build b/build index 75ba742f..1e3407af 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 75ba742f4f00cefadfef1ae451cfb2a4280ad367 +Subproject commit 1e3407af692eaf661800083897c73d46d0a4bc46 diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 3a60e4e6..6ab4d026 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -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