diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index e2d8cec2..d3514930 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -212,9 +212,19 @@ function Folding() { /** * Adds a new fold. + * + * @returns + * The new created Fold object or an existing fold object in case the + * passed in range fits an existing fold exactly. */ this.addFold = function(placeholder, startRow, startColumn, endRow, endColumn) { var range; + var foldData = this.$foldData; + var foldRow = null; + var foldLine; + var fold; + var added = false; + // Normalize parameters. if (!(startRow instanceof Range)) { range = new Range(startRow, startColumn, endRow, endColumn); @@ -224,12 +234,41 @@ function Folding() { endRow = range.end.row; } - var foldData = this.$foldData; - var foldRow = null; - var foldLine; + // --- Some checking --- + if (placeholder.length < 2) { + throw "Placeholder has to be at least 2 characters"; + } - var fold = new Fold(range, placeholder); - var added = false; + if (startRow == endRow && endColumn - startColumn < 2) { + throw "The range has to be at least 2 characters width"; + } + + fold = this.getFoldAt(startRow, startColumn, 1); + if (fold + && fold.range.isEnd(endRow, endColumn) + && fold.range.isStart(startRow, startColumn)) + { + return fold; + } + + if (this.getFoldAt(startRow, startColumn, 1) + || this.getFoldAt(endRow, endColumn, -1)) + { + throw "A fold can't start or end inside of an already existing fold"; + } + + if (endRow >= this.doc.$lines.length) { + throw "End of fold is outside of the document."; + } + + if (endColumn > this.getLine(endRow).length + || startColumn > this.getLine(startRow).length) + { + throw "End of fold is outside of the document."; + } + + // --- Start adding the fold --- + fold = new Fold(range, placeholder); // For now we assume that no two folds are created for the same range! for (var i = 0; i < foldData.length; i++) { @@ -260,7 +299,6 @@ function Folding() { foldLine = this.$addFoldLine(new FoldLine(this.$foldData, fold)); } - // TODO: Recalculate wrapData if (this.$useWrapMode) { this.$updateWrapData(foldLine.start.row, foldLine.start.row); } @@ -268,6 +306,8 @@ function Folding() { // Notify that fold data has changed. this.$modified = true; this._dispatchEvent("changeFold"); + + return fold; }; this.removeFold = function(fold) { diff --git a/lib/ace/edit_session_test.js b/lib/ace/edit_session_test.js index 6f65c54e..bc5b09fb 100644 --- a/lib/ace/edit_session_test.js +++ b/lib/ace/edit_session_test.js @@ -731,7 +731,7 @@ module.exports = { // Adding a fold. The split position is inside of the fold. As placeholder // are not splitable, the split should be before the split. - session.addFold("woot", 0, 4, 0, 16); + session.addFold("woot", 0, 4, 0, 15); assertWrap([4], [8], [8]); // Remove the fold again which should reset the wrapData. @@ -742,35 +742,35 @@ module.exports = { removeFoldAssertWrap(0, 6, [8], [8], [8]); // The fold fits into the wrap limit - no split expected. - session.addFold("woot", 0, 3, 0, 16); + session.addFold("woot", 0, 3, 0, 15); assertWrap([], [8], [8]); removeFoldAssertWrap(0, 4, [8], [8], [8]); // Fold after split position should be all fine. - session.addFold("woot", 0, 8, 0, 16); + session.addFold("woot", 0, 8, 0, 15); assertWrap([8], [8], [8]); removeFoldAssertWrap(0, 8, [8], [8], [8]); // Fold's placeholder is far too long for wrapSplit. - session.addFold("woot0123456789", 0, 8, 0, 16); + session.addFold("woot0123456789", 0, 8, 0, 15); assertWrap([8], [8], [8]); removeFoldAssertWrap(0, 8, [8], [8], [8]); // Fold's placeholder is far too long for wrapSplit // + content at the end of the line - session.addFold("woot0123456789", 0, 7, 0, 8); - assertWrap([7, 21], [8], [8]); + session.addFold("woot0123456789", 0, 6, 0, 8); + assertWrap([6, 20], [8], [8]); removeFoldAssertWrap(0, 8, [8], [8], [8]); - session.addFold("woot0123456789", 0, 7, 0, 8); - session.addFold("woot0123456789", 0, 8, 0, 9); - assertWrap([7, 21, 35], [8], [8]); + session.addFold("woot0123456789", 0, 6, 0, 8); + session.addFold("woot0123456789", 0, 8, 0, 10); + assertWrap([6, 20, 34], [8], [8]); session.removeFold(session.getFoldAt(0, 7)); removeFoldAssertWrap(0, 8, [8], [8], [8]); - session.addFold("woot0123456789", 0, 7, 0, 8); - session.addFold("woot0123456789", 0, 14, 0, 16); - assertWrap([7, 21, 27], [8], [8]); + session.addFold("woot0123456789", 0, 7, 0, 9); + session.addFold("woot0123456789", 0, 13, 0, 15); + assertWrap([7, 21, 25], [8], [8]); session.removeFold(session.getFoldAt(0, 7)); removeFoldAssertWrap(0, 14, [8], [8], [8]); @@ -778,7 +778,7 @@ module.exports = { // Add a fold over two lines. Note, that the wrapData[1] stays the // same. This is an implementation detail and expected behavior. - session.addFold("woot", 0, 8, 1, 16); + session.addFold("woot", 0, 8, 1, 15); assertWrap([8], [8 /* See comments */], [8]); removeFoldAssertWrap(0, 8, [8], [8], [8]); @@ -786,11 +786,46 @@ module.exports = { assertWrap([8, 14], [8 /* See comments */], [8]); removeFoldAssertWrap(0, 9, [8], [8], [8]); - session.addFold("woot", 0, 9, 1, 16); + session.addFold("woot", 0, 9, 1, 15); assertWrap([8], [8 /* See comments */], [8]); removeFoldAssertWrap(0, 9, [8], [8], [8]); return session; + }, + + "test add fold": function() { + var session = createFoldTestSession(); + var fold; + + function tryAddFold( + placeholder, + startRow, startColumn, endRow, endColumn, shouldFail) + { + var fail = false; + try { + fold = session.addFold(placeholder, + startRow, startColumn, endRow, endColumn); + } catch (e) { + fail = true; + } + if (fail != shouldFail) { + throw "Expected to get an exception"; + } + } + + tryAddFold("foo", 0, 13, 0, 17, true); + tryAddFold("foo", 0, 14, 0, 18, true); + tryAddFold("foo", 0, 13, 0, 18, false); + assert.equal(session.$foldData[0].folds.length, 1); + + tryAddFold("f", 0, 13, 0, 18, true); + tryAddFold("foo", 0, 18, 0, 21, false); + assert.equal(session.$foldData[0].folds.length, 2); + session.removeFold(fold); + + tryAddFold("foo", 0, 18, 0, 22, true); + tryAddFold("foo", 0, 18, 0, 19, true); + tryAddFold("foo", 0, 22, 1, 10, true); } };