Checkpointing fold-wrap-data work. Mostly done

This commit is contained in:
Julian Viereck 2011-04-28 13:18:46 +02:00
commit 46a877e563
2 changed files with 193 additions and 67 deletions

View file

@ -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 = "";

View file

@ -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<items.length; i++) {",
// " alert(items[i] + \"juhu\");",
// " } // Real Tab.",
// "}"
assertIdx2Pos(0, 12, 0, 12);
assertIdx2Pos(0, 13, 0, 13);
assertIdx2Pos(0, 14, 0, 13);
assertIdx2Pos(0, 19, 0, 13);
assertIdx2Pos(0, 20, 0, 18);
assertIdx2Pos(1, 10, 1, 10);
assertIdx2Pos(1, 11, 1, 10);
assertIdx2Pos(1, 15, 1, 10);
assertIdx2Pos(1, 16, 2, 10);
assertIdx2Pos(1, 26, 2, 20);
assertIdx2Pos(1, 27, 2, 20);
assertIdx2Pos(1, 32, 2, 25);
},
"test fold documentToScreen": function() {
var session = createFoldTestSession();
function assertDoc2Screen(docRow, docCol, screenRow, screenCol) {
@ -647,6 +691,42 @@ module.exports = {
assert.range(foldLines[0].range, 0, 13, 0, 18);
assert.range(foldLines[1].range, 1, 10, 2, 25);
// TODO: Add test for inseration inside of folds.
},
"test fold wrap data compution": function() {
function assertArray(a, b) {
assert.ok(a.length == b.length);
for (var i = 0; i < a.length; i++) {
assert.ok(a[i] == b[i]);
}
}
function assertWrap(line0, line1, line2) {
line0 && assertArray(wrapData[0], line0);
line1 && assertArray(wrapData[1], line1);
line2 && assertArray(wrapData[2], line2);
}
var lines = [
"foo bar foo bar",
"foo bar foo bar",
"foo bar foo bar"
];
var session = new EditSession(lines.join("\n"));
var wrapData = session.$wrapData;
session.setUseWrapMode(true);
session.$wrapLimit = 7;
session.$updateWrapData(0, 2);
assertWrap([7], [7], [7]);
session.addFold(new Range(0, 13, 0, 18), "args...");
session.addFold(new Range(1, 10, 2, 10), "foo...");
session.addFold(new Range(2, 20, 2, 25), "bar...");
return session;
}
};