From 77dfd0b29c2f7302a585cb50cdfb08797160fba8 Mon Sep 17 00:00:00 2001 From: nightwing Date: Mon, 28 Nov 2011 00:20:33 +0400 Subject: [PATCH] addFold must not throw if new fold is inside the existing one --- lib/ace/edit_session.js | 30 ++++++++++++++++++++++++++ lib/ace/edit_session/fold.js | 36 +++++++++++++++++++++++++++++++ lib/ace/edit_session/fold_line.js | 2 +- lib/ace/edit_session/folding.js | 29 +++++++++---------------- lib/ace/edit_session_test.js | 36 ++++++++++++++++++------------- lib/ace/range.js | 6 ++++++ lib/ace/virtual_renderer.js | 4 ++-- 7 files changed, 106 insertions(+), 37 deletions(-) diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 864cedad..658174e6 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -837,6 +837,12 @@ var EditSession = function(text, mode) { return Math.max(0, Math.min(row, this.doc.getLength()-1)); }; + this.$clipColumnToRow = function(row, column) { + if (column < 0) + return 0; + return Math.min(this.doc.getLine(row).length, column); + }; + this.$clipPositionToDocument = function(row, column) { column = Math.max(0, column); @@ -859,6 +865,30 @@ var EditSession = function(text, mode) { }; }; + this.$clipRangeToDocument = function(range) { + if (range.start.row < 0) { + range.start.row = 0; + range.start.column = 0 + } else { + range.start.column = this.$clipColumnToRow( + range.start.row, + range.start.column + ); + } + + var len = this.doc.getLength() - 1; + if (range.end.row > len) { + range.end.row = len; + range.end.column = this.doc.getLine(len).length; + } else { + range.end.column = this.$clipColumnToRow( + range.end.row, + range.end.column + ); + } + return range; + }; + // WRAPMODE this.$wrapLimit = 80; this.$useWrapMode = false; diff --git a/lib/ace/edit_session/fold.js b/lib/ace/edit_session/fold.js index bb9d98e7..fcf32dc7 100644 --- a/lib/ace/edit_session/fold.js +++ b/lib/ace/edit_session/fold.js @@ -74,6 +74,42 @@ var Fold = exports.Fold = function(range, placeholder) { return fold; }; + this.addSubFold = function(fold) { + if (this.range.isEequal(fold)) + return this; + + if (!this.range.containsRange(fold)) + throw "A fold can't intersect already existing fold" + fold.range + this.range; + + var row = fold.range.start.row, column = fold.range.start.column; + for (var i = 0, cmp = -1; i < this.subFolds.length; i++) { + cmp = this.subFolds[i].range.compare(row, column); + if (cmp != 1) + break; + } + var afterStart = this.subFolds[i]; + + if (cmp == 0) + return afterStart.addSubFold(fold) + + // cmp == -1 + var row = fold.range.end.row, column = fold.range.end.column; + for (var j = i, cmp = -1; j < this.subFolds.length; j++) { + cmp = this.subFolds[j].range.compare(row, column); + if (cmp != 1) + break; + } + var afterEnd = this.subFolds[j]; + + if (cmp == 0) + throw "A fold can't intersect already existing fold" + fold.range + this.range; + + var consumedFolds = this.subFolds.splice(i, j - i, fold) + fold.setFoldLine(this.foldLine); + + return fold; + } + }).call(Fold.prototype); }); \ No newline at end of file diff --git a/lib/ace/edit_session/fold_line.js b/lib/ace/edit_session/fold_line.js index 03017b9a..54e72a87 100644 --- a/lib/ace/edit_session/fold_line.js +++ b/lib/ace/edit_session/fold_line.js @@ -41,7 +41,7 @@ define(function(require, exports, module) { var Range = require("../range").Range; /** - * If the an array is passed in, the folds are expected to be sorted already. + * If an array is passed in, the folds are expected to be sorted already. */ function FoldLine(foldData, folds) { this.foldData = foldData; diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index e05c7056..dd942fcc 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -247,6 +247,8 @@ function Folding() { else fold = new Fold(range, placeholder); + this.$clipRangeToDocument(fold.range); + var startRow = fold.start.row; var startColumn = fold.start.column; var endRow = fold.end.row; @@ -259,29 +261,18 @@ function Folding() { if (startRow == endRow && endColumn - startColumn < 2) throw "The range has to be at least 2 characters width"; - var existingFold = this.getFoldAt(startRow, startColumn, 1); + var startFold = this.getFoldAt(startRow, startColumn, 1); + var endFold = this.getFoldAt(endRow, endColumn, -1); + if (startFold && endFold == startFold) + return startFold.addSubFold(fold); + if ( - existingFold - && existingFold.range.isEnd(endRow, endColumn) - && existingFold.range.isStart(startRow, startColumn) + (startFold && !startFold.range.isStart(startRow, startColumn)) + || (endFold && !endFold.range.isEnd(endRow, endColumn)) ) { - return fold; + throw "A fold can't intersect already existing fold" + fold.range + startFold.range; } - existingFold = this.getFoldAt(startRow, startColumn, 1); - if (existingFold && !existingFold.range.isStart(startRow, startColumn)) - throw "A fold can't start inside of an already existing fold"; - - existingFold = this.getFoldAt(endRow, endColumn, -1); - if (existingFold && !existingFold.range.isEnd(endRow, endColumn)) - throw "A fold can't end inside of an already existing fold"; - - if (endRow >= this.doc.getLength()) - 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."; - // Check if there are folds in the range we create the new fold for. var folds = this.getFoldsInRange(fold.range); if (folds.length > 0) { diff --git a/lib/ace/edit_session_test.js b/lib/ace/edit_session_test.js index aeb2cef6..cdba3444 100644 --- a/lib/ace/edit_session_test.js +++ b/lib/ace/edit_session_test.js @@ -109,10 +109,10 @@ module.exports = { assert.position(session.findMatchingBracket({row: 6, column: 20}), 1, 15); assert.position(session.findMatchingBracket({row: 1, column: 22}), 1, 20); assert.position(session.findMatchingBracket({row: 3, column: 31}), 3, 21); - assert.position(session.findMatchingBracket({row: 4, column: 24}), 4, 19); + assert.position(session.findMatchingBracket({row: 4, column: 24}), 4, 19); assert.equal(session.findMatchingBracket({row: 0, column: 1}), null); }, - + "test: find matching closing bracket in JavaScript mode" : function() { var lines = [ "function foo() {", @@ -131,7 +131,7 @@ module.exports = { assert.position(session.findMatchingBracket({row: 1, column: 16}), 6, 19); assert.position(session.findMatchingBracket({row: 1, column: 21}), 1, 21); assert.position(session.findMatchingBracket({row: 3, column: 22}), 3, 30); - assert.position(session.findMatchingBracket({row: 4, column: 20}), 4, 23); + assert.position(session.findMatchingBracket({row: 4, column: 20}), 4, 23); }, "test: handle unbalanced brackets in JavaScript mode" : function() { @@ -223,7 +223,7 @@ module.exports = { "12\t\t34", "ぁぁa" ]); - + assert.equal(session.getScreenLastRowColumn(0), 4); assert.equal(session.getScreenLastRowColumn(1), 10); assert.equal(session.getScreenLastRowColumn(2), 5); @@ -267,13 +267,13 @@ module.exports = { "12\t\t34", "ぁぁa" ]); - + assert.position(session.documentToScreenPosition(0, 3), 0, 3); assert.position(session.documentToScreenPosition(1, 3), 1, 4); assert.position(session.documentToScreenPosition(1, 4), 1, 8); assert.position(session.documentToScreenPosition(2, 2), 2, 4); }, - + "test: documentToScreen with soft wrap": function() { var session = new EditSession(["foo bar foo bar"]); session.setUseWrapMode(true); @@ -283,7 +283,7 @@ module.exports = { assert.position(session.documentToScreenPosition(0, 11), 0, 11); assert.position(session.documentToScreenPosition(0, 12), 1, 0); }, - + "test: documentToScreen with soft wrap and multibyte characters": function() { session = new EditSession(["ぁぁa"]); @@ -298,7 +298,7 @@ module.exports = { "test: documentToScreen should clip position to the document boundaries": function() { var session = new EditSession("foo bar\njuhu kinners"); - + assert.position(session.documentToScreenPosition(-1, 4), 0, 0); assert.position(session.documentToScreenPosition(3, 0), 1, 12); }, @@ -340,7 +340,7 @@ module.exports = { assert.position(session.screenToDocumentPosition(0, 12), 0, 11); assert.position(session.screenToDocumentPosition(0, 20), 0, 11); }, - + "test: screenToDocument with soft wrap and multi byte characters": function() { session = new EditSession(["ぁ a"]); session.setUseWrapMode(true); @@ -352,10 +352,10 @@ module.exports = { assert.position(session.screenToDocumentPosition(0, 4), 0, 3); assert.position(session.screenToDocumentPosition(0, 5), 0, 3); }, - + "test: screenToDocument should clip position to the document boundaries": function() { var session = new EditSession("foo bar\njuhu kinners"); - + assert.position(session.screenToDocumentPosition(-1, 4), 0, 0); assert.position(session.screenToDocumentPosition(0, -1), 0, 0); assert.position(session.screenToDocumentPosition(0, 30), 0, 7); @@ -649,7 +649,7 @@ module.exports = { var session = createFoldTestSession(); var undoManager = session.getUndoManager(); var foldLines = session.$foldData; - + function insert(row, column, text) { session.insert({row: row, column: column}, text); @@ -930,7 +930,7 @@ module.exports = { } } - tryAddFold("foo", new Range(0, 13, 0, 17), true); + tryAddFold("foo", new Range(0, 13, 0, 17), false); tryAddFold("foo", new Range(0, 14, 0, 18), true); tryAddFold("foo", new Range(0, 13, 0, 18), false); assert.equal(session.$foldData[0].folds.length, 1); @@ -940,9 +940,9 @@ module.exports = { assert.equal(session.$foldData[0].folds.length, 2); session.removeFold(fold); - tryAddFold("foo", new Range(0, 18, 0, 22), true); + tryAddFold("foo", new Range(0, 18, 0, 22), false); tryAddFold("foo", new Range(0, 18, 0, 19), true); - tryAddFold("foo", new Range(0, 22, 1, 10), true); + tryAddFold("foo", new Range(0, 22, 1, 10), false); }, "test add subfolds": function() { @@ -972,6 +972,12 @@ module.exports = { assert.equal(foldData[0].folds.length, 1); assert.equal(foldData[0].folds[0], oldFold); assert.equal(fold.subFolds.length, 0); + + session.unfold(null, true); + fold = session.addFold("fold0", new Range(0, 0, 0, 21)); + session.addFold("fold0", new Range(0, 1, 0, 5)); + session.addFold("fold0", new Range(0, 6, 0, 8)); + assert.equal(fold.subFolds.length, 2); } }; diff --git a/lib/ace/range.js b/lib/ace/range.js index 596f3f57..0121f8aa 100644 --- a/lib/ace/range.js +++ b/lib/ace/range.js @@ -50,6 +50,12 @@ var Range = function(startRow, startColumn, endRow, endColumn) { }; (function() { + this.isEequal = function(range) { + return this.start.row == range.start.row && + this.end.row == range.end.row && + this.start.column == range.start.column && + this.end.column == range.end.column + }; this.toString = function() { return ("Range: [" + this.start.row + "/" + this.start.column + diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js index b3ac15b3..b491106a 100644 --- a/lib/ace/virtual_renderer.js +++ b/lib/ace/virtual_renderer.js @@ -264,11 +264,11 @@ var VirtualRenderer = function(container, theme) { }; this.$onGutterClick = function(e) { + var pageX = event.getDocumentX(e); var pageY = event.getDocumentY(e); - var row = this.screenToTextCoordinates(0, pageY).row; this._dispatchEvent("gutter" + e.type, { - row: row, + row: this.screenToTextCoordinates(pageX, pageY).row, htmlEvent: e }); };