diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 4fc175a9..0d4efec8 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -31,9 +31,9 @@ define(function(require, exports, module) { "use strict"; -var config = require("./config"); var oop = require("./lib/oop"); var lang = require("./lib/lang"); +var config = require("./config"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Selection = require("./selection").Selection; var TextMode = require("./mode/text").Mode; @@ -41,7 +41,6 @@ var Range = require("./range").Range; var Document = require("./document").Document; var BackgroundTokenizer = require("./background_tokenizer").BackgroundTokenizer; var SearchHighlight = require("./search_highlight").SearchHighlight; -var config = require("./config"); /** * Stores all the data about [[Editor `Editor`]] state providing easy way to change editors state. @@ -1377,8 +1376,8 @@ var EditSession = function(text, mode) { }; this.$moveLines = function(firstRow, lastRow, dir) { - var firstRow = this.getRowFoldStart(firstRow); - var lastRow = this.getRowFoldEnd(lastRow); + firstRow = this.getRowFoldStart(firstRow); + lastRow = this.getRowFoldEnd(lastRow); if (dir < 0) { var row = this.getRowFoldStart(firstRow + dir); if (row < 0) return 0; diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index c9176cfe..765ec81c 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -260,9 +260,10 @@ function Folding() { if (placeholder instanceof Fold) fold = placeholder; - else + else { fold = new Fold(range, placeholder); - + fold.collapseChildren = range.collapseChildren; + } this.$clipRangeToDocument(fold.range); var startRow = fold.start.row; @@ -303,8 +304,7 @@ function Folding() { foldLine.addFold(fold); added = true; break; - } - else if (startRow == foldLine.end.row) { + } else if (startRow == foldLine.end.row) { foldLine.addFold(fold); added = true; if (!fold.sameRow) { @@ -317,8 +317,7 @@ function Folding() { } } break; - } - else if (endRow <= foldLine.start.row) { + } else if (endRow <= foldLine.start.row) { break; } } @@ -411,11 +410,14 @@ function Folding() { }; this.expandFold = function(fold) { - this.removeFold(fold); + this.removeFold(fold); fold.subFolds.forEach(function(subFold) { fold.restoreRange(subFold); this.addFold(subFold); }, this); + if (fold.collapseChildren > 0) { + this.foldAll(fold.start.row+1, fold.end.row, fold.collapseChildren-1); + } fold.subFolds = []; }; @@ -427,9 +429,10 @@ function Folding() { this.unfold = function(location, expandInner) { var range, folds; - if (location == null) + if (location == null) { range = new Range(0, 0, this.getLength(), 0); - else if (typeof location == "number") + expandInner = true; + } else if (typeof location == "number") range = new Range(location, 0, location, this.getLine(location).length); else if ("row" in location) range = Range.fromPoints(location, location); @@ -483,20 +486,20 @@ function Folding() { var textLine = ""; foldLine.walk(function(placeholder, row, column, lastColumn) { - if (row < startRow) { + if (row < startRow) return; - } else if (row == startRow) { - if (column < startColumn) { + if (row == startRow) { + if (column < startColumn) return; - } lastColumn = Math.max(startColumn, lastColumn); } + if (placeholder != null) { textLine += placeholder; } else { textLine += doc.getLine(row).substring(lastColumn, column); } - }.bind(this), endRow, endColumn); + }, endRow, endColumn); return textLine; }; @@ -538,26 +541,22 @@ function Folding() { if (fold) { this.expandFold(fold); return; - } - else if (bracketPos = this.findMatchingBracket(cursor)) { + } else if (bracketPos = this.findMatchingBracket(cursor)) { if (range.comparePoint(bracketPos) == 1) { range.end = bracketPos; - } - else { + } else { range.start = bracketPos; range.start.column++; range.end.column--; } - } - else if (bracketPos = this.findMatchingBracket({row: cursor.row, column: cursor.column + 1})) { + } else if (bracketPos = this.findMatchingBracket({row: cursor.row, column: cursor.column + 1})) { if (range.comparePoint(bracketPos) == 1) range.end = bracketPos; else range.start = bracketPos; range.start.column++; - } - else { + } else { range = this.getCommentFoldRange(cursor.row, cursor.column) || range; } } else { @@ -565,8 +564,7 @@ function Folding() { if (tryToUnfold && folds.length) { this.expandFolds(folds); return; - } - else if (folds.length == 1 ) { + } else if (folds.length == 1 ) { fold = folds[0]; } } @@ -622,7 +620,9 @@ function Folding() { } }; - this.foldAll = function(startRow, endRow) { + this.foldAll = function(startRow, endRow, depth) { + if (depth == undefined) + depth = 100000; // JSON.stringify doesn't hanle Infinity var foldWidgets = this.foldWidgets; endRow = endRow || this.getLength(); for (var row = startRow || 0; row < endRow; row++) { @@ -633,13 +633,16 @@ function Folding() { var range = this.getFoldWidgetRange(row); // sometimes range can be incompatible with existing fold - // wouldn't it be better for addFold to return null istead of throwing? + // TODO change addFold to return null istead of throwing if (range && range.end.row <= endRow) try { - this.addFold("...", range); + var fold = this.addFold("...", range); + fold.collapseChildren = depth; } catch(e) {} + row = range.end.row; } }; + // structured folding this.$foldStyles = { "manual": 1, "markbegin": 1, @@ -664,7 +667,6 @@ function Folding() { this.$setFolding(mode); }; - // structured folding this.$setFolding = function(foldMode) { if (this.$foldMode == foldMode) return; @@ -688,21 +690,46 @@ function Folding() { }; + this.getParentFoldRangeData = function (row, ignoreCurrent) { + var fw = this.foldWidgets; + if (!fw || (ignoreCurrent && fw[row])) + return {}; + + var i = row - 1, firstRange; + while (i >= 0) { + var c = fw[i]; + if (c == null) + c = fw[i] = this.getFoldWidget(i); + + if (c == "start") { + var range = this.getFoldWidgetRange(i); + if (!firstRange) + firstRange = range; + if (range && range.end.row >= row) + break; + } + i--; + } + + return { + range: i !== -1 && range, + firstRange: firstRange + }; + } + this.onFoldWidgetClick = function(row, e) { - e = e.domEvent; var type = this.getFoldWidget(row); var line = this.getLine(row); - var onlySubfolds = e.shiftKey; - var addSubfolds = onlySubfolds || e.ctrlKey || e.altKey || e.metaKey; - var fold; + e = e.domEvent; + var children = e.shiftKey; + var all = e.ctrlKey || e.metaKey; + var siblings = e.altKey; - if (type == "end") - fold = this.getFoldAt(row, 0, -1); - else - fold = this.getFoldAt(row, line.length, 1); + var dir = type === "end" ? -1 : 1; + var fold = this.getFoldAt(row, dir === -1 ? 0 : line.length, dir); if (fold) { - if (addSubfolds) + if (children || all) this.removeFold(fold); else this.expandFold(fold); @@ -710,28 +737,35 @@ function Folding() { } var range = this.getFoldWidgetRange(row); - if (range) { - // sometimes singleline folds can be missed by the code above - if (!range.isMultiLine()) { - fold = this.getFoldAt(range.start.row, range.start.column, 1); - if (fold && range.isEqual(fold.range)) { - this.removeFold(fold); - return; - } + // sometimes singleline folds can be missed by the code above + if (range && !range.isMultiLine()) { + fold = this.getFoldAt(range.start.row, range.start.column, 1); + if (fold && range.isEqual(fold.range)) { + this.removeFold(fold); + return; } - - if (!onlySubfolds) - this.addFold("...", range); - - if (addSubfolds) - this.foldAll(range.start.row + 1, range.end.row); - } else { - if (addSubfolds) - this.foldAll(row + 1, this.getLength()); - (e.target || e.srcElement).className += " ace_invalid" } + + if (siblings) { + var data = this.getParentFoldRangeData(row); + if (data.range) { + var startRow = data.range.start.row + 1; + var endRow = data.range.end.row; + } + this.foldAll(startRow, endRow, all ? 10000 : 0); + } else if (children) { + var endRow = range ? range.end.row : this.getLength(); + this.foldAll(row + 1, range.end.row, all ? 10000 : 0); + } else if (range) { + if (all) + range.collapseChildren = 10000; + this.addFold("...", range); + } + + if (!range) + (e.target || e.srcElement).className += " ace_invalid" }; - + this.updateFoldWidgets = function(e) { var delta = e.data; var range = delta.range; diff --git a/lib/ace/mouse/fold_handler.js b/lib/ace/mouse/fold_handler.js index e785f6f0..3141b26a 100644 --- a/lib/ace/mouse/fold_handler.js +++ b/lib/ace/mouse/fold_handler.js @@ -69,27 +69,8 @@ function FoldHandler(editor) { if (gutterRegion == "foldWidgets") { var row = e.getDocumentPosition().row; var session = editor.session; - var fw = session.foldWidgets; - if (!fw || fw[row]) - return; - - var i = row - 1, firstRange; - while (i >= 0) { - var c = fw[i]; - if (c == null) - c = fw[i] = session.getFoldWidget(i); - - if (c == "start") { - var range = session.getFoldWidgetRange(i); - if (!firstRange) - firstRange = range; - if (range && range.end.row >= row) - break; - } - i--; - } - if (i == -1) - range = firstRange; + var data = session.getParentFoldRangeData(row, true); + var range = data.range || data.firstRange; if (range) { var row = range.start.row; diff --git a/lib/ace/token_iterator.js b/lib/ace/token_iterator.js index ffddafff..74376fb3 100644 --- a/lib/ace/token_iterator.js +++ b/lib/ace/token_iterator.js @@ -85,11 +85,12 @@ var TokenIterator = function(session, initialRow, initialColumn) { * @returns {String} **/ this.stepForward = function() { - var rowCount = this.$session.getLength(); this.$tokenIndex += 1; - + var rowCount; while (this.$tokenIndex >= this.$rowTokens.length) { this.$row += 1; + if (!rowCount) + rowCount = this.$session.getLength(); if (this.$row >= rowCount) { this.$row = rowCount - 1; return null;