Rewrote the handling of . Now there is one FoldLine per folded line/row as it's displayed on the screen.
This commit is contained in:
parent
aea1bc31ea
commit
7b58e782a7
4 changed files with 180 additions and 158 deletions
|
|
@ -896,9 +896,6 @@ var EditSession = function(text, mode) {
|
|||
if (useWrapMode && this.$wrapData.length != this.doc.$lines.length) {
|
||||
console.error("The length of doc.$lines and $wrapData have to be the same!");
|
||||
}
|
||||
if (this.$foldData.length != this.doc.$lines.length) {
|
||||
console.error("The length of doc.$lines and $foldData have to be the same!");
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// this.$updateFoldData(firstRow, lastRow);
|
||||
|
|
@ -1242,65 +1239,45 @@ var EditSession = function(text, mode) {
|
|||
return this.documentToScreenPosition(docRow, docColumn).row;
|
||||
}
|
||||
|
||||
this.$buildFoldedTextLine = function(row, endRow, endColumn) {
|
||||
this.$buildFoldedTextLine = function(foldLine, endRow, endColumn) {
|
||||
var textLine = "";
|
||||
|
||||
// Build a one line string for the current fold sequence that starts
|
||||
// at foldStartRow.
|
||||
var lastEnd = 0,
|
||||
line = this.getLine(foldLine.start.row),
|
||||
comp,
|
||||
folds = foldLine.folds,
|
||||
fold;
|
||||
|
||||
while_loop:
|
||||
while (true) {
|
||||
var folds = this.getFoldData(row);
|
||||
var line = this.getLine(row);
|
||||
for (var i = 0; i < folds.length; i++) {
|
||||
fold = folds[i];
|
||||
|
||||
var lastEnd = 0;
|
||||
var startIdx = 0;
|
||||
if (folds[0].start.row != row) {
|
||||
startIdx = 1;
|
||||
lastEnd = folds[0].end.column;
|
||||
comp = fold.compare(endRow, endColumn);
|
||||
// This fold is after the endRow/Column.
|
||||
if (comp == -1) {
|
||||
textLine += line.substring(lastEnd, endColumn);
|
||||
return textLine;
|
||||
}
|
||||
fold = null;
|
||||
for (var i = startIdx; i < folds.length; i++) {
|
||||
fold = folds[i];
|
||||
// STOP
|
||||
if (row == endRow) {
|
||||
if (endColumn <= fold.start.column) {
|
||||
textLine += line.substring(lastEnd, endColumn);
|
||||
break while_loop;
|
||||
} else if (!fold.sameLine || endColumn < fold.end.column) {
|
||||
textLine += line.substring(lastEnd, fold.start.column);
|
||||
break while_loop;
|
||||
}
|
||||
}
|
||||
// The endRow/Column is inside of the current fold.
|
||||
else if (comp == 0) {
|
||||
textLine += line.substring(lastEnd, fold.start.column);
|
||||
return textLine;
|
||||
}
|
||||
|
||||
// Stop if the end position is inside of this fold.
|
||||
if (endRow < fold.end.row ||
|
||||
endRow == fold.end.row && endColumn < fold.end.column
|
||||
) {
|
||||
break while_loop;
|
||||
}
|
||||
textLine += fold.placeholder;
|
||||
if (fold.sameLine) {
|
||||
lastEnd = fold.end.column;
|
||||
} else {
|
||||
row = fold.end.row;
|
||||
// STOP
|
||||
if (row == endRow && endColumn <= fold.end.column) {
|
||||
break while_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (row > endRow) {
|
||||
break;
|
||||
}
|
||||
if (row == endRow && (!fold || fold.sameLine)) {
|
||||
if (fold) {
|
||||
textLine += line.substring(lastEnd, endColumn);
|
||||
}
|
||||
break;
|
||||
textLine += line.substring(lastEnd, fold.start.column);
|
||||
textLine += fold.placeholder;
|
||||
|
||||
if (fold.sameLine) {
|
||||
lastEnd = fold.end.column;
|
||||
} else {
|
||||
row = fold.end.row;
|
||||
|
||||
line = this.getLine(row);
|
||||
lastEnd = fold.end.column;
|
||||
}
|
||||
}
|
||||
textLine += line.substring(lastEnd, endColumn);
|
||||
return textLine;
|
||||
}
|
||||
|
||||
|
|
@ -1308,40 +1285,53 @@ var EditSession = function(text, mode) {
|
|||
var screenRow = 0,
|
||||
screenColumn = 0,
|
||||
foldStartRow = null,
|
||||
fold = null;
|
||||
fold = null,
|
||||
folds,
|
||||
comp,
|
||||
foldLine = null;
|
||||
|
||||
// Clamp the docRow position in case it's inside of a folded block.
|
||||
if (!this.isRowVisible(docRow)) {
|
||||
// As the line is not visible, getFoldData will return only a
|
||||
// single fold and also not an array.
|
||||
var lfold = this.getFoldData(docRow);
|
||||
docRow = lfold.start.row;
|
||||
docColumn = lfold.start.column;
|
||||
foldLine = this.getFoldLine(docRow);
|
||||
if (foldLine) {
|
||||
folds = foldLine.folds;
|
||||
for (var i = 0; i < folds.length; i++) {
|
||||
fold = folds[i];
|
||||
comp = fold.compare(docRow, docColumn);
|
||||
if (comp == 0) {
|
||||
docRow = fold.start.row;
|
||||
docColumn = fold.start.column;
|
||||
break;
|
||||
} else if (comp == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
foldLine = null;
|
||||
}
|
||||
|
||||
for (var row = 0; row < docRow; row++) {
|
||||
var fold = this.getRowLastFold(row);
|
||||
if (fold && !fold.sameLine) {
|
||||
if (foldStartRow == null) {
|
||||
foldStartRow = row;
|
||||
foldLine = this.getFoldLine(row);
|
||||
if (foldLine) {
|
||||
if (foldLine.end.row >= docRow) {
|
||||
break;
|
||||
}
|
||||
row = fold.end.row - 1;
|
||||
row = foldLine.end.row;
|
||||
screenRow += foldLine.getRowLength();
|
||||
} else {
|
||||
screenRow += this.getRowLength(row);
|
||||
foldStartRow = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the text line that is displayed in docRow on the screen.
|
||||
var textLine = "";
|
||||
|
||||
foldLine = this.getFoldLine(docRow);
|
||||
// Check if the final row we want to reach is inside of a fold.
|
||||
if (!this.isRowFolded(docRow)) {
|
||||
if (!foldLine) {
|
||||
textLine = this.getLine(docRow).substring(0, docColumn);
|
||||
foldStartRow = docRow;
|
||||
} else {
|
||||
textLine = this.$buildFoldedTextLine(
|
||||
(foldStartRow != null ? foldStartRow : docRow),
|
||||
foldLine,
|
||||
docRow,
|
||||
docColumn);
|
||||
}
|
||||
|
|
@ -1453,67 +1443,87 @@ var EditSession = function(text, mode) {
|
|||
this.sameLine = range.start.row == range.end.row;
|
||||
}
|
||||
|
||||
function FoldRow(row) {
|
||||
this.row = row;
|
||||
this.linkIn = null;
|
||||
this.linkOut = null;
|
||||
this.inRow = [];
|
||||
Fold.prototype.contains = function(row, column) {
|
||||
if (this.end.row == row && this.end.column == column) {
|
||||
return false;
|
||||
}
|
||||
return this.range.contains(row, column);
|
||||
}
|
||||
|
||||
Fold.prototype.compare = function(row, column) {
|
||||
if (this.end.row == row && this.end.column == column) {
|
||||
return 1;
|
||||
}
|
||||
return this.range.compare(row, column);
|
||||
}
|
||||
|
||||
function FoldLine(fold) {
|
||||
this.folds = [fold];
|
||||
this.range = fold.range.clone();
|
||||
this.start = this.range.start;
|
||||
this.end = this.range.end;
|
||||
}
|
||||
|
||||
(function() {
|
||||
this.addInRowFold = function(fold) {
|
||||
if (!fold.sameLine || fold.start.row != this.row) {
|
||||
throw "NOPE: Can't add fold here!";
|
||||
}
|
||||
this.inRow.push(fold);
|
||||
this.inRow.sort(function(a, b) {
|
||||
return a.start.column - b.start.column;
|
||||
});
|
||||
}
|
||||
|
||||
this.addFold = function(fold) {
|
||||
if (fold.sameLine) {
|
||||
this.addInRowFold(fold)
|
||||
} else if (fold.start.row == this.row) {
|
||||
if (this.linkOut) {
|
||||
throw "There is already a linkOut fold";
|
||||
if (fold.start.row < this.startRow || fold.endRow > this.endRow) {
|
||||
throw "Can't add a fold to this FoldLine as it has no connection";
|
||||
}
|
||||
this.linkOut = fold;
|
||||
} else if (fold.end.row == this.row) {
|
||||
if (this.linkIn) {
|
||||
throw "There is already a linkIn fold";
|
||||
}
|
||||
this.linkIn = fold;
|
||||
this.folds.push(fold);
|
||||
this.folds.sort(function(a, b) {
|
||||
if (a.sameLine && b.sameLine) {
|
||||
if (a.start.row == b.start.row) {
|
||||
return a.start.colun - b.start.column;
|
||||
} else {
|
||||
return a.start.row - b.start.row;
|
||||
}
|
||||
} else if (!a.sameLine && !b.sameLine) {
|
||||
return a.end.row - b.start.row;
|
||||
} else if (!a.sameLine) {
|
||||
return a.end.row - b.start.row;
|
||||
} else if (!b.sameLine) {
|
||||
return b.end.row - a.start.row;
|
||||
}
|
||||
});
|
||||
} else if (fold.start.row == this.endRow) {
|
||||
this.folds.push(fold);
|
||||
this.end.row = fold.end.row;
|
||||
this.end.column = fold.end.column;
|
||||
} else if (fold.end.row == this.startRow) {
|
||||
this.folds.unshift(fold);
|
||||
this.start.row = fold.start.row;
|
||||
this.start.column = fold.start.column;
|
||||
} else {
|
||||
throw "Trying to add fold to FoldRow that doesn't have a matching row";
|
||||
}
|
||||
}
|
||||
}).call(FoldRow.prototype);
|
||||
|
||||
this.getFoldRow = function(docRow, startFoldRow) {
|
||||
this.getRowLength = function() {
|
||||
// TODO: Add support for wrapped lines here.
|
||||
return 1;
|
||||
}
|
||||
|
||||
this.getSplitData = function() {
|
||||
// TODO: Add support for wrapped lines here.
|
||||
return undefined;
|
||||
}
|
||||
}).call(FoldLine.prototype);
|
||||
|
||||
this.getFoldLine = function(docRow, startFoldLine) {
|
||||
var foldData = this.$foldData;
|
||||
for (var i = foldData.indexOf(startFoldRow) || 0; i < foldData.length; i++) {
|
||||
var foldRow = foldData[i];
|
||||
if (foldRow.row == docRow) {
|
||||
return foldRow;
|
||||
} else if (foldRow.row > docRow) {
|
||||
var i = Math.max(foldData.indexOf(startFoldLine), 0);
|
||||
for (i; i < foldData.length; i++) {
|
||||
var foldLine = foldData[i];
|
||||
if (foldLine.start.row >= docRow || foldLine.end.row >= docRow) {
|
||||
return foldLine;
|
||||
} else if (foldLine.end.row > docRow) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
this.getFoldRowOrCreate = function(docRow, startFoldRow) {
|
||||
var foldRow = this.getFoldRow(docRow, startFoldRow);
|
||||
if (!foldRow) {
|
||||
foldRow = new FoldRow(startRow);
|
||||
this.$foldData.push(foldRow);
|
||||
this.$foldData.sort(function(a, b) {
|
||||
return a.row - b.row;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new fold.
|
||||
*/
|
||||
|
|
@ -1523,16 +1533,46 @@ var EditSession = function(text, mode) {
|
|||
foldData = this.$foldData,
|
||||
foldRow = null;
|
||||
|
||||
foldRow = this.getFoldRowOrCreate(startRow);
|
||||
|
||||
var fold = new Fold(range, placeholder);
|
||||
foldRow.addFold(fold);
|
||||
var added = false;
|
||||
|
||||
// If this fold folds more then one line, then add this fold as the
|
||||
// linkOut of the FoldRow at endRow.
|
||||
if (!fold.sameLine) {
|
||||
foldRow = this.getFoldRowOrCreate(endRow, foldRow);
|
||||
foldRow.addFold(fold);
|
||||
// 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];
|
||||
if (endRow == foldLine.start.row) {
|
||||
foldLine.addFold(fold);
|
||||
added = true;
|
||||
break;
|
||||
} else if (startRow == foldLine.end.row) {
|
||||
foldLine.addFold(fold);
|
||||
added = true;
|
||||
if (!fold.sameLine) {
|
||||
// Check if we might have to merge two FoldLines.
|
||||
foldLineNext = foldData[i + 1];
|
||||
if (foldLineNext && foldLineNext.start.row == endRow) {
|
||||
// We need to merge!
|
||||
var nextFolds = foldLineNext.folds;
|
||||
for (var i = 0; i < nextFolds.length; i++) {
|
||||
foldLine.addFold(nextFolds[i]);
|
||||
}
|
||||
// Remove the foldLineNext - no longer needed, as
|
||||
// it's merged now with foldLine.
|
||||
foldData.splice(foldData.indexOf(foldLineNext), 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else if (endRow <= foldLine.start.row) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!added) {
|
||||
foldLine = new FoldLine(fold);
|
||||
foldData.push(foldLine);
|
||||
foldData.sort(function(a, b) {
|
||||
return a.start.row - b.start.row;
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Recalculate wrapData
|
||||
|
|
@ -1548,36 +1588,16 @@ var EditSession = function(text, mode) {
|
|||
* folded parts such that some parts of the line is still visible.
|
||||
**/
|
||||
this.isRowFolded = function(docRow, startFoldRow) {
|
||||
return !!this.getFoldRow(docRow, startFoldRow);
|
||||
return !!this.getFoldLine(docRow, startFoldRow);
|
||||
};
|
||||
|
||||
this.getRowFoldEnd = function(docRow, startFoldRow) {
|
||||
var foldRow = this.getFoldRow(docRow, startFoldRow);
|
||||
return (foldRow
|
||||
? (foldRow.linkOut ? foldRow.linkOut.end.row : docRow)
|
||||
: docRow);
|
||||
var foldLine = this.getFoldLine(docRow, startFoldRow);
|
||||
return (foldLine
|
||||
? foldLine.end.row
|
||||
: docRow)
|
||||
};
|
||||
|
||||
this.buildFoldRowLine = function(docRow, startFoldRow) {
|
||||
var foldRow = this.getFoldRow(docRow, startFoldRow);
|
||||
var folds = [];
|
||||
if (!foldRow) {
|
||||
throw "Passed in docRow doesn't have a foldRow";
|
||||
}
|
||||
if (foldRow.linkIn) {
|
||||
throw "Can't build a single fold line starting at a FoldRow that is linked in!";
|
||||
}
|
||||
|
||||
var foldData = this.$foldData;
|
||||
for (var i = foldData.indexOf(foldRow); foldRow; i++) {
|
||||
if (foldRow.linkIn) {
|
||||
folds.push(foldRow.linkIn);
|
||||
}
|
||||
|
||||
foldRow = foldRow.linkOut;
|
||||
}
|
||||
}
|
||||
|
||||
// this.findRowFoldedForward = function(start, limit) {
|
||||
// if (limit == null) {
|
||||
// limit = this.getLength();
|
||||
|
|
|
|||
|
|
@ -407,6 +407,9 @@ module.exports = {
|
|||
assertDoc2Screen(2, 25, 1, 32);
|
||||
assertDoc2Screen(2, 26, 1, 33);
|
||||
assertDoc2Screen(2, 99, 1, 40);
|
||||
|
||||
// Test one position after the folds. Should be all like normal.
|
||||
assertDoc2Screen(3, 0, 2, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
* Julian Viereck <julian DOT viereck AT gmail DOT com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Julian Viereck <julian.viereck@gmail.com>
|
||||
* Julian Viereck <julian DOT viereck AT gmail DOT com>
|
||||
* Mihai Sucan <mihai.sucan@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
|
|
@ -401,9 +401,9 @@ var Text = function(parentEl) {
|
|||
// Nothing to do if the entire line is folded.
|
||||
// TODO: Remove this, once the folding feature is done. Only for
|
||||
// developing stuff at the moment.
|
||||
if (!this.session.isRowVisible(row)) {
|
||||
throw "Calling renderLine on folded line doesn't make sense?";
|
||||
}
|
||||
// if (!this.session.isRowVisible(row)) {
|
||||
// throw "Calling renderLine on folded line doesn't make sense?";
|
||||
// }
|
||||
|
||||
// Check if the line to render is folded or not. If not, things are
|
||||
// simple, otherwise, we need to fake some things...
|
||||
|
|
@ -417,7 +417,8 @@ var Text = function(parentEl) {
|
|||
|
||||
this.$renderFoldLine = function(stringBuilder, row, tokens) {
|
||||
var session = this.session,
|
||||
folds = session.getFoldData(row);
|
||||
foldLine = session.getFoldLine(row),
|
||||
folds = foldLine.folds;
|
||||
|
||||
var renderTokens = [];
|
||||
|
||||
|
|
@ -461,9 +462,11 @@ var Text = function(parentEl) {
|
|||
}
|
||||
}
|
||||
|
||||
var lastCol = 0;
|
||||
var lastCol = 0,
|
||||
fold = null;
|
||||
|
||||
for (var i = 0; i < folds.length; i++) {
|
||||
var fold = folds[i];
|
||||
fold = folds[i];
|
||||
addTokens(tokens, lastCol, fold.start.column);
|
||||
renderTokens.push({
|
||||
type: "fold",
|
||||
|
|
@ -471,21 +474,17 @@ var Text = function(parentEl) {
|
|||
});
|
||||
|
||||
if (fold.start.row != fold.end.row) {
|
||||
row = fold.end.row;
|
||||
tokens = this.tokenizer.getTokens(row, row)[0].tokens;
|
||||
folds = session.getFoldData(row);
|
||||
// Skip the first fold as it's only referencing to the current
|
||||
// fold that is already rendered.
|
||||
i = 0;
|
||||
tokens = this.tokenizer.getTokens(
|
||||
fold.end.row, fold.end.row)[0].tokens;
|
||||
}
|
||||
|
||||
lastCol = fold.end.column;
|
||||
}
|
||||
// Add the rest of the line
|
||||
addTokens(tokens, lastCol, session.getLine(row).length);
|
||||
addTokens(tokens, lastCol, session.getLine(foldLine.end.row).length);
|
||||
|
||||
// TODO: Build a fake splits array!
|
||||
var splits = false;
|
||||
var splits = foldLine.getSplitData();
|
||||
this.$renderLineCore(stringBuilder, row, renderTokens, splits);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue