From 46a877e5635ba85b2dcb5c83aa9b991b354aaa55 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Thu, 28 Apr 2011 13:18:46 +0200 Subject: [PATCH] Checkpointing fold-wrap-data work. Mostly done --- lib/ace/edit_session.js | 180 ++++++++++++++++++++++------------- lib/ace/edit_session_test.js | 80 ++++++++++++++++ 2 files changed, 193 insertions(+), 67 deletions(-) diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index c922f115..9bbb6957 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -477,7 +477,7 @@ var EditSession = function(text, mode) { line = lines[i]; if (foldLine) { var end = foldLine.range.end; - line = this.getFoldDisplayLine(foldLine, end.row, line.length); + line = this.getFoldDisplayLine(foldLine); // Continue after the foldLine.end.row. All the lines in // between are folded. i = end.row; @@ -1003,9 +1003,30 @@ var EditSession = function(text, mode) { var wrapData = this.$wrapData; var wrapLimit = this.$wrapLimit; var tokens; + var foldLine; for (var row = firstRow; row <= lastRow; row++) { - tokens = this.$getDisplayTokens(lang.stringTrimRight(lines[row])); + foldLine = this.getFoldLine(row); + if (!foldLine) { + tokens = this.$getDisplayTokens(lang.stringTrimRight(lines[row])); + } else { + tokens = []; + foldLine.walk(function(placeholder, row, column, lastColumn) { + var walkTokens; + if (placeholder) { + walkTokens = this.$getDisplayTokens(placeholder, tokens.length); + walkTokens[0] = PLACEHOLDER_START; + for (var i = 1; i < walkTokens.length; i++) { + walkTokens[i] = PLACEHOLDER_BODY; + } + } else { + walkTokens = this.$getDisplayTokens( + lines[row].substring(lastColumn, column), + tokens.length); + } + tokens = tokens.concat(walkTokens); + }.bind(this), row, lines[row].length); + } wrapData[row] = this.$computeWrapSplits(tokens, wrapLimit, tabSize); } @@ -1251,14 +1272,16 @@ var EditSession = function(text, mode) { }; this.screen2Doc = function(screenRow, screenColumn) { - var line, - docRow = 0, - docColumn = 0, column, - foldLine, - foldLineRowLength; - - var row = 0, - rowLength = 0; + var line; + var docRow = 0; + var docColumn = 0; + var column; + var foldLine; + var foldLineRowLength; + var row = 0; + var rowLength = 0; + var splits = null; + var split = 0; while (row <= screenRow) { rowLength = this.getRowLength(docRow); @@ -1270,58 +1293,37 @@ var EditSession = function(text, mode) { } } - var splits = null; splits = this.$wrapData[docRow] || []; foldLine = this.getFoldLine(docRow); - if (foldLine) { - docColumn = splits[screenRow - row] || 0; - walkScreenColumn = 0; + line = foldLine + ? this.getFoldDisplayLine(foldLine) + : this.getLine(docRow); - foldLine.walk(function(placeholder, row, column, lastColumn, isNewRow) { - var data, str; - if (placeholder) { - data = this.$getStringScreenWidth(placeholder, null, walkScreenColumn); - if (data[0] > screenColumn || data[1] == 0) { - return true; // Stop walk. - } - docColumn += data[1]; - } else { - docColumn = lastColumn; - if (isNewRow) { - docRow = row; - line = this.getLine(row); - } - str = line.substring(lastColumn, column); - data = this.$getStringScreenWidth(str, screenColumn, walkScreenColumn); - docColumn += data[1]; - if (data[0] == screenColumn) { - return true; // Stop walk. - } - } - walkScreenColumn = data[0]; - }.bind(this), foldLine.end.row, this.getLine(foldLine.end.row).length); - } else { - line = this.getLine(docRow); - if (this.$useWrapMode && splits) { - docColumn = splits[screenRow - row - 1] || 0; - line = line.substring(docColumn); - } - - docColumn += this.$getStringScreenWidth(line, screenColumn)[1]; - - // Need to do some clamping action here. - if (this.$useWrapMode) { - column = this.$wrapData[docRow][screenRow - row] - if (docColumn >= column) { - // We remove one character at the end such that the docColumn - // position returned is not associated to the next row on the - // screen. - docColumn = column - 1; - } - } else { - docColumn = Math.min(docColumn, line.length); - } + if (this.$useWrapMode) { + docColumn = split = splits[screenRow - row - 1] || 0; + line = line.substring(split); } + + docColumn += this.$getStringScreenWidth(line, screenColumn)[1]; + + if (foldLine) { + var position = foldLine.idxToPosition(docColumn); + return [position.row, position.column]; + } + + // Need to do some clamping action here. + if (this.$useWrapMode) { + column = splits[screenRow - row] + if (docColumn >= column) { + // We remove one character at the end such that the docColumn + // position returned is not associated to the next row on the + // screen. + docColumn = column - 1; + } + } else { + docColumn = Math.min(docColumn, line.length); + } + return [docRow, docColumn, screenRow, row] } @@ -1388,13 +1390,14 @@ var EditSession = function(text, mode) { foldStartRow = docRow; } else { textLine = this.getFoldDisplayLine(foldLine, docRow, docColumn); + foldStartRow = foldLine.start.row; } // Clamp textLine if in wrapMode. if (this.$useWrapMode) { var wrapRow = wrapData[foldStartRow]; var screenRowOffset = 0; - while (docColumn >= wrapRow[screenRowOffset]) { + while (textLine.length >= wrapRow[screenRowOffset]) { screenRow ++; screenRowOffset++; } @@ -1532,6 +1535,9 @@ var EditSession = function(text, mode) { } (function() { + /** + * Note: This doesn't update wrapData! + */ this.shiftRow = function(shift) { this.start.row += shift; this.end.row += shift; @@ -1602,7 +1608,7 @@ var EditSession = function(text, mode) { } stop = callback(null, fold.start.row, fold.start.column, lastEnd, isNewRow); - stop = stop || callback(fold.placeholder); + stop = stop || callback(fold.placeholder, null, null, lastEnd); if (stop) { return; @@ -1645,8 +1651,7 @@ var EditSession = function(text, mode) { && fold.start.column != column && fold.start.row != row) { - // TODO: Implement adding new characters inside of an - // fold. This should extend/remove the fold etc. + throw "Moving characters inside of a fold should never be reached"; } else if (fold.start.row == row) { folds = this.folds; var i = folds.indexOf(fold); @@ -1683,8 +1688,6 @@ var EditSession = function(text, mode) { // 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; @@ -1710,6 +1713,35 @@ var EditSession = function(text, mode) { ret.push("]") return ret.join("\n"); } + + this.idxToPosition = function(idx) { + var lastFoldEndColumn = 0; + var fold; + + 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); FoldLine.prototype.__defineGetter__("rangeDBG", function() { @@ -1864,6 +1896,7 @@ var EditSession = function(text, mode) { this.$foldData.sort(function(a, b) { return a.start.row - b.start.row; }); + return foldLine; } /** @@ -1874,13 +1907,14 @@ var EditSession = function(text, mode) { endRow = range.end.row, foldData = this.$foldData, foldRow = null; + var foldLine; var fold = new Fold(range, placeholder); var added = false; // For now we assume that no two folds are created for the same range! for (var i = 0; i < foldData.length; i++) { - var foldLine = foldData[i]; + foldLine = foldData[i]; if (endRow == foldLine.start.row) { foldLine.addFold(fold); added = true; @@ -1904,10 +1938,13 @@ var EditSession = function(text, mode) { } if (!added) { - this.$addFoldLine(new FoldLine(this.$foldData, fold)); + foldLine = this.$addFoldLine(new FoldLine(this.$foldData, fold)); } // TODO: Recalculate wrapData + if (this.$useWrapMode) { + this.$updateWrapData(foldLine.start.row, foldLine.start.row); + } // Notify that fold data has changed. this.$modified = true; @@ -1916,6 +1953,8 @@ var EditSession = function(text, mode) { this.removeFold = function(fold) { var foldLine = fold.foldLine; + var startRow = foldLine.start.row; + var endRow = foldLine.end.row; var foldLines = this.$foldData, folds = foldLine.folds; @@ -1953,7 +1992,9 @@ var EditSession = function(text, mode) { this.$addFoldLine(newFoldLine); } - // TODO: Update wrapData. + if (this.$useWrapMode) { + this.$updateWrapData(startRow, endRow); + } // Notify that fold data has changed. this.$modified = true; @@ -1991,6 +2032,11 @@ var EditSession = function(text, mode) { }; this.getFoldDisplayLine = function(foldLine, endRow, endColumn) { + if (endRow == null) { + endRow = foldLine.end.row; + endColumn = this.getLine(endRow).length; + } + // Build the textline using the FoldLine walker. var line = "", textLine = ""; diff --git a/lib/ace/edit_session_test.js b/lib/ace/edit_session_test.js index a7d37ef0..2cefd40c 100644 --- a/lib/ace/edit_session_test.js +++ b/lib/ace/edit_session_test.js @@ -43,6 +43,7 @@ if (typeof process !== "undefined") { define(function(require, exports, module) { +var lang = require("pilot/lang"); var EditSession = require("ace/edit_session").EditSession; var Editor = require("ace/editor").Editor; var UndoManager = require("ace/undomanager").UndoManager; @@ -264,6 +265,7 @@ module.exports = { function computeAndAssert(line, assertEqual, wrapLimit, tabSize) { wrapLimit = wrapLimit || 12; tabSize = tabSize || 4; + line = lang.stringTrimRight(line); var tokens = EditSession.prototype.$getDisplayTokens(line); var splits = EditSession.prototype.$computeWrapSplits(tokens, wrapLimit, tabSize); // console.log("String:", line, "Result:", splits, "Expected:", assertEqual); @@ -373,6 +375,48 @@ module.exports = { assert.equal(session.doc.getValue(), ["", "foo"].join("\n")); }, + "test fold getFoldDisplayLine": function() { + var session = createFoldTestSession(); + function assertDisplayLine(foldLine, str) { + var line = session.getLine(foldLine.end.row); + var displayLine = + session.getFoldDisplayLine(foldLine, foldLine.end.row, line.length); + assert.equal(displayLine, str); + } + + assertDisplayLine(session.$foldData[0], "function foo(args...) {") + assertDisplayLine(session.$foldData[1], " for (vfoo...ert(items[bar...\"juhu\");"); + }, + + "test foldLine idxToPosition": function() { + var session = createFoldTestSession(); + + function assertIdx2Pos(foldLineIdx, idx, row, column) { + var foldLine = session.$foldData[foldLineIdx]; + assert.position(foldLine.idxToPosition(idx), row, column); + } + +// "function foo(items) {", +// " for (var i=0; i