Add fold documentToScreen unit tests and fixed some small bugs
This commit is contained in:
parent
12bfd2ee0c
commit
aea1bc31ea
4 changed files with 221 additions and 144 deletions
|
|
@ -149,6 +149,7 @@ exports.launch = function(env) {
|
|||
|
||||
// BEGING TESTING
|
||||
var Range = require("ace/range").Range;
|
||||
docs.js.addFold(new Range(0, 13, 0, 18), "args...");
|
||||
docs.js.addFold(new Range(1, 10, 2, 10), "foo...");
|
||||
docs.js.addFold(new Range(2, 20, 2, 25), "bar...");
|
||||
window.s = docs.js;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* Mihai Sucan <mihai DOT sucan AT gmail DOT 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
|
||||
|
|
@ -55,6 +56,7 @@ var EditSession = function(text, mode) {
|
|||
this.$backMarkers = {};
|
||||
this.$markerId = 1;
|
||||
this.$wrapData = [];
|
||||
this.$foldData = [];
|
||||
|
||||
if (text instanceof Document) {
|
||||
this.setDocument(text);
|
||||
|
|
@ -875,8 +877,8 @@ var EditSession = function(text, mode) {
|
|||
if (len != 0) {
|
||||
if (action.indexOf("remove") != -1) {
|
||||
useWrapMode && this.$wrapData.splice(firstRow, len);
|
||||
// TODO: More checking needed here.
|
||||
this.$foldData.splice(firstRow, len);
|
||||
// TODO: Remove no longer needed folds here.
|
||||
// TODO: Update row data on folds.
|
||||
lastRow = firstRow;
|
||||
} else {
|
||||
var args;
|
||||
|
|
@ -886,10 +888,8 @@ var EditSession = function(text, mode) {
|
|||
this.$wrapData.splice.apply(this.$wrapData, args);
|
||||
}
|
||||
|
||||
args = [firstRow, 0];
|
||||
for (var i = 0; i < len; i++) args.push(false);
|
||||
// TODO: More checking needed here.
|
||||
this.$foldData.splice.apply(this.$foldData, args);
|
||||
// TODO: Expand folds here if needed.
|
||||
// TODO: Update row data on folds.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1041,7 +1041,7 @@ var EditSession = function(text, mode) {
|
|||
screenColumn += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return screenColumn;
|
||||
}
|
||||
|
||||
|
|
@ -1242,7 +1242,7 @@ var EditSession = function(text, mode) {
|
|||
return this.documentToScreenPosition(docRow, docColumn).row;
|
||||
}
|
||||
|
||||
this.$buildWrappedTextLine = function(row, endRow, endColumn) {
|
||||
this.$buildFoldedTextLine = function(row, endRow, endColumn) {
|
||||
var textLine = "";
|
||||
|
||||
// Build a one line string for the current fold sequence that starts
|
||||
|
|
@ -1273,6 +1273,13 @@ var EditSession = function(text, mode) {
|
|||
}
|
||||
}
|
||||
textLine += line.substring(lastEnd, fold.start.column);
|
||||
|
||||
// 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;
|
||||
|
|
@ -1333,8 +1340,10 @@ var EditSession = function(text, mode) {
|
|||
textLine = this.getLine(docRow).substring(0, docColumn);
|
||||
foldStartRow = docRow;
|
||||
} else {
|
||||
textLine = this.$buildWrappedTextLine(
|
||||
(foldStartRow != null ? foldStartRow : docRow), docRow, docColumn);
|
||||
textLine = this.$buildFoldedTextLine(
|
||||
(foldStartRow != null ? foldStartRow : docRow),
|
||||
docRow,
|
||||
docColumn);
|
||||
}
|
||||
|
||||
// Clamp textLine if in wrapMode.
|
||||
|
|
@ -1381,7 +1390,13 @@ var EditSession = function(text, mode) {
|
|||
}
|
||||
}
|
||||
|
||||
screenRows -= this.getFoldedRowLength(0, length - 1);
|
||||
var foldData = this.$foldData;
|
||||
for (var i = 0; i < foldData.length; i++) {
|
||||
var foldRow = foldData[i];
|
||||
if (foldRow.linkOut) {
|
||||
screenRows -= foldRow.linkOut.end.row - foldRow.linkOut.start.row;
|
||||
}
|
||||
}
|
||||
return screenRows;
|
||||
}
|
||||
|
||||
|
|
@ -1438,35 +1453,86 @@ 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 = [];
|
||||
}
|
||||
|
||||
(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";
|
||||
}
|
||||
this.linkOut = fold;
|
||||
} else if (fold.end.row == this.row) {
|
||||
if (this.linkIn) {
|
||||
throw "There is already a linkIn fold";
|
||||
}
|
||||
this.linkIn = fold;
|
||||
} else {
|
||||
throw "Trying to add fold to FoldRow that doesn't have a matching row";
|
||||
}
|
||||
}
|
||||
}).call(FoldRow.prototype);
|
||||
|
||||
this.getFoldRow = function(docRow, startFoldRow) {
|
||||
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) {
|
||||
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.
|
||||
*/
|
||||
this.addFold = function(range, placeholder) {
|
||||
var startRow = range.start.row,
|
||||
endRow = range.end.row,
|
||||
foldData = this.$foldData;
|
||||
foldData = this.$foldData,
|
||||
foldRow = null;
|
||||
|
||||
// In case there is no fold data for the start row yet.
|
||||
if (!Array.isArray(foldData[startRow])) {
|
||||
foldData[startRow] = [];
|
||||
}
|
||||
foldRow = this.getFoldRowOrCreate(startRow);
|
||||
|
||||
var fold = new Fold(range, placeholder);
|
||||
// TODO: The folds have to be ordered by range.start!
|
||||
foldData[startRow].push(fold);
|
||||
foldRow.addFold(fold);
|
||||
|
||||
// Mark all lines folded by this fold as folded.
|
||||
for (var row = startRow + 1; row < endRow; row++) {
|
||||
foldData[row] = fold;
|
||||
}
|
||||
|
||||
// If this fold folds more then one line, then add the fold at the
|
||||
// beginning of the foldData[endRow] as well.
|
||||
// If this fold folds more then one line, then add this fold as the
|
||||
// linkOut of the FoldRow at endRow.
|
||||
if (!fold.sameLine) {
|
||||
if (!Array.isArray(foldData[endRow])) {
|
||||
foldData[endRow] = [];
|
||||
}
|
||||
foldData[endRow].splice(0, 0, fold);
|
||||
foldRow = this.getFoldRowOrCreate(endRow, foldRow);
|
||||
foldRow.addFold(fold);
|
||||
}
|
||||
|
||||
// TODO: Recalculate wrapData
|
||||
|
|
@ -1481,104 +1547,60 @@ var EditSession = function(text, mode) {
|
|||
* Checks if a given documentRow is folded. This is true if there are some
|
||||
* folded parts such that some parts of the line is still visible.
|
||||
**/
|
||||
this.isRowFolded = function(docRow) {
|
||||
return !!this.$foldData[docRow];
|
||||
this.isRowFolded = function(docRow, startFoldRow) {
|
||||
return !!this.getFoldRow(docRow, startFoldRow);
|
||||
};
|
||||
|
||||
this.getRowLastFold = function(docRow) {
|
||||
var fold = this.$foldData[docRow];
|
||||
if (!fold) {
|
||||
return null;
|
||||
} else if (Array.isArray(fold)) {
|
||||
return fold[fold.length - 1];
|
||||
} else {
|
||||
return fold;
|
||||
}
|
||||
};
|
||||
|
||||
this.getRowFirstFold = function(docRow, skipLastWrap) {
|
||||
var fold = this.$foldData[docRow];
|
||||
if (!fold) {
|
||||
return null;
|
||||
} else if (Array.isArray(fold)) {
|
||||
if (skipLastWrap) {
|
||||
if (fold[0].row.start != docRow) {
|
||||
return fold[1] || null;
|
||||
}
|
||||
}
|
||||
return fold[0];
|
||||
} else {
|
||||
return fold;
|
||||
}
|
||||
};
|
||||
|
||||
this.getRowFoldEnd = function(docRow) {
|
||||
return (this.$foldData[docRow]
|
||||
? this.getRowLastFold(docRow).end.row
|
||||
this.getRowFoldEnd = function(docRow, startFoldRow) {
|
||||
var foldRow = this.getFoldRow(docRow, startFoldRow);
|
||||
return (foldRow
|
||||
? (foldRow.linkOut ? foldRow.linkOut.end.row : docRow)
|
||||
: docRow);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a given documentRow is visible or not. Not beeing visible means
|
||||
* it's folded completly.
|
||||
**/
|
||||
this.isRowVisible = function(docRow) {
|
||||
var fold = this.$foldData[docRow];
|
||||
return !fold || Array.isArray(fold);
|
||||
};
|
||||
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!";
|
||||
}
|
||||
|
||||
this.getFoldData = function(docRow) {
|
||||
return this.$foldData[docRow];
|
||||
var foldData = this.$foldData;
|
||||
for (var i = foldData.indexOf(foldRow); foldRow; i++) {
|
||||
if (foldRow.linkIn) {
|
||||
folds.push(foldRow.linkIn);
|
||||
}
|
||||
|
||||
foldRow = foldRow.linkOut;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of folded lines between start and end row.
|
||||
*/
|
||||
this.getFoldedRowLength = function(start, end) {
|
||||
var row = start;
|
||||
var count = 0;
|
||||
while (row <= end) {
|
||||
row = this.findRowFoldedForward(row, end);
|
||||
if (row != null) {
|
||||
var fold = this.getRowLastFold(row);
|
||||
if (!fold.sameLine) {
|
||||
if (row == start) {
|
||||
count += fold.end.row - start;
|
||||
} else {
|
||||
count += fold.end.row - fold.start.row;
|
||||
}
|
||||
row = fold.end.row + 1;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
this.findRowFoldedForward = function(start, limit) {
|
||||
if (limit == null) {
|
||||
limit = this.getLength();
|
||||
}
|
||||
for (var row = start; row != limit; row++) {
|
||||
if (this.isRowFolded(row)) {
|
||||
return row;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
this.findRowFoldedBackwards = function(start, limit) {
|
||||
if (limit == null) {
|
||||
limit = -1;
|
||||
}
|
||||
for (var row = start; row != limit; row--) {
|
||||
if (this.isRowFolded(row)) {
|
||||
return row;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// this.findRowFoldedForward = function(start, limit) {
|
||||
// if (limit == null) {
|
||||
// limit = this.getLength();
|
||||
// }
|
||||
// for (var row = start; row != limit; row++) {
|
||||
// if (this.isRowFolded(row)) {
|
||||
// return row;
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// this.findRowFoldedBackwards = function(start, limit) {
|
||||
// if (limit == null) {
|
||||
// limit = -1;
|
||||
// }
|
||||
// for (var row = start; row != limit; row--) {
|
||||
// if (this.isRowFolded(row)) {
|
||||
// return row;
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
}).call(EditSession.prototype);
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Fabian Jakobs <fabian AT ajax DOT org>
|
||||
* 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
|
||||
|
|
@ -49,6 +50,21 @@ var MockRenderer = require("ace/test/mockrenderer");
|
|||
var Range = require("ace/range").Range;
|
||||
var assert = require("ace/test/assertions");
|
||||
|
||||
function createFoldTestSession() {
|
||||
var lines = [
|
||||
"function foo(items) {",
|
||||
" for (var i=0; i<items.length; i++) {",
|
||||
" alert(items[i] + \"juhu\");",
|
||||
" } // Real Tab.",
|
||||
"}"
|
||||
];
|
||||
var session = new EditSession(lines.join("\n"));
|
||||
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;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
"test: find matching opening bracket" : function() {
|
||||
|
|
@ -353,6 +369,44 @@ module.exports = {
|
|||
session.setValue("\nfoo");
|
||||
|
||||
assert.equal(session.doc.getValue(), ["", "foo"].join("\n"));
|
||||
},
|
||||
|
||||
"test fold documentToScreen": function() {
|
||||
var session = createFoldTestSession();
|
||||
function assertDoc2Screen(docRow, docCol, screenRow, screenCol) {
|
||||
assert.position(
|
||||
session.documentToScreenPosition(docRow, docCol),
|
||||
screenRow, screenCol
|
||||
);
|
||||
}
|
||||
|
||||
// One fold ending in the same row.
|
||||
assertDoc2Screen(0, 0, 0, 0);
|
||||
assertDoc2Screen(0, 13, 0, 13);
|
||||
assertDoc2Screen(0, 14, 0, 13);
|
||||
assertDoc2Screen(0, 17, 0, 13);
|
||||
assertDoc2Screen(0, 18, 0, 20);
|
||||
|
||||
// Fold ending on some other row.
|
||||
assertDoc2Screen(1, 0, 1, 0);
|
||||
assertDoc2Screen(1, 10, 1, 10);
|
||||
assertDoc2Screen(1, 11, 1, 10);
|
||||
assertDoc2Screen(1, 99, 1, 10);
|
||||
|
||||
assertDoc2Screen(2, 0, 1, 10);
|
||||
assertDoc2Screen(2, 9, 1, 10);
|
||||
assertDoc2Screen(2, 10, 1, 16);
|
||||
assertDoc2Screen(2, 11, 1, 17);
|
||||
|
||||
// Fold in the same row with fold over more then one row in the same row.
|
||||
assertDoc2Screen(2, 19, 1, 25);
|
||||
assertDoc2Screen(2, 20, 1, 26);
|
||||
assertDoc2Screen(2, 21, 1, 26);
|
||||
|
||||
assertDoc2Screen(2, 24, 1, 26);
|
||||
assertDoc2Screen(2, 25, 1, 32);
|
||||
assertDoc2Screen(2, 26, 1, 33);
|
||||
assertDoc2Screen(2, 99, 1, 40);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -10,27 +10,27 @@ var failed = 0
|
|||
var log = document.getElementById("log")
|
||||
|
||||
var tests = [
|
||||
require("ace/editor_change_document_test"),
|
||||
require("ace/editor_navigation_test"),
|
||||
require("ace/editor_highlight_selected_word_test"),
|
||||
require("ace/editor_text_edit_test"),
|
||||
require("ace/document_test"),
|
||||
require("ace/edit_session_test"),
|
||||
require("ace/test/event_emitter_test"),
|
||||
require("ace/range_test"),
|
||||
require("ace/search_test"),
|
||||
require("ace/selection_test"),
|
||||
require("ace/virtual_renderer_test"),
|
||||
require("ace/anchor_test"),
|
||||
require("ace/mode/css_test"),
|
||||
require("ace/mode/css_tokenizer_test"),
|
||||
require("ace/mode/html_test"),
|
||||
require("ace/mode/html_tokenizer_test"),
|
||||
require("ace/mode/javascript_test"),
|
||||
require("ace/mode/javascript_tokenizer_test"),
|
||||
require("ace/mode/text_test"),
|
||||
require("ace/mode/xml_test"),
|
||||
require("ace/mode/xml_tokenizer_test")
|
||||
// require("ace/editor_change_document_test"),
|
||||
// require("ace/editor_navigation_test"),
|
||||
// require("ace/editor_highlight_selected_word_test"),
|
||||
// require("ace/editor_text_edit_test"),
|
||||
// require("ace/document_test"),
|
||||
require("ace/edit_session_test") //,
|
||||
// require("ace/test/event_emitter_test"),
|
||||
// require("ace/range_test"),
|
||||
// require("ace/search_test"),
|
||||
// require("ace/selection_test"),
|
||||
// require("ace/virtual_renderer_test"),
|
||||
// require("ace/anchor_test"),
|
||||
// require("ace/mode/css_test"),
|
||||
// require("ace/mode/css_tokenizer_test"),
|
||||
// require("ace/mode/html_test"),
|
||||
// require("ace/mode/html_tokenizer_test"),
|
||||
// require("ace/mode/javascript_test"),
|
||||
// require("ace/mode/javascript_tokenizer_test"),
|
||||
// require("ace/mode/text_test"),
|
||||
// require("ace/mode/xml_test"),
|
||||
// require("ace/mode/xml_tokenizer_test")
|
||||
]
|
||||
|
||||
async.list(tests)
|
||||
|
|
@ -41,21 +41,21 @@ async.list(tests)
|
|||
.each(function(test, next) {
|
||||
var node = document.createElement("div");
|
||||
node.className = test.passed ? "passed" : "failed";
|
||||
|
||||
|
||||
var name = test.name
|
||||
if (test.suiteName)
|
||||
name = test.suiteName + ": " + test.name
|
||||
|
||||
|
||||
var msg = "[" + test.count + "/" + test.index + "] " + name + " " + (test.passed ? "OK" : "FAIL")
|
||||
if (!test.passed) {
|
||||
if (test.err.stack)
|
||||
var err = test.err.stack
|
||||
else
|
||||
var err = test.err
|
||||
|
||||
|
||||
msg += "<pre class='error'>" + err + "</pre>";
|
||||
}
|
||||
|
||||
|
||||
node.innerHTML = msg;
|
||||
log.appendChild(node);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue