diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index 9c663d18..dcbf6ba8 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -35,12 +35,13 @@ var lang = require("../lib/lang"); var config = require("../config"); function bindKey(win, mac) { - return { - win: win, - mac: mac - }; + return {win: win, mac: mac}; } +/* + multiSelectAction: "forEach"|"forEachLine"|function|undefined, + scrollIntoView: true|"cursor"|"center"|"selectionPart" +*/ exports.commands = [{ name: "showSettingsMenu", bindKey: bindKey("Ctrl-,", "Command-,"), @@ -75,21 +76,46 @@ exports.commands = [{ name: "fold", bindKey: bindKey("Alt-L|Ctrl-F1", "Command-Alt-L|Command-F1"), exec: function(editor) { editor.session.toggleFold(false); }, + scrollIntoView: "center", readOnly: true }, { name: "unfold", bindKey: bindKey("Alt-Shift-L|Ctrl-Shift-F1", "Command-Alt-Shift-L|Command-Shift-F1"), exec: function(editor) { editor.session.toggleFold(true); }, + scrollIntoView: "center", + readOnly: true +}, { + name: "toggleFoldWidget", + bindKey: bindKey("F2", "F2"), + exec: function(editor) { editor.session.toggleFoldWidget(); }, + scrollIntoView: "center", + readOnly: true +}, { + name: "toggleParentFoldWidget", + bindKey: bindKey("Alt-F2", "Alt-F2"), + exec: function(editor) { editor.session.toggleFoldWidget(true); }, + scrollIntoView: "center", readOnly: true }, { name: "foldall", - bindKey: bindKey("Alt-0", "Command-Option-0"), + bindKey: bindKey("Ctrl-Alt-0", "Ctrl-Command-Option-0"), exec: function(editor) { editor.session.foldAll(); }, + scrollIntoView: "center", + readOnly: true +}, { + name: "foldOther", + bindKey: bindKey("Alt-0", "Command-Option-0"), + exec: function(editor) { + editor.session.foldAll(); + editor.session.unfold(editor.selection.getAllRanges()); + }, + scrollIntoView: "center", readOnly: true }, { name: "unfoldall", bindKey: bindKey("Alt-Shift-0", "Command-Option-Shift-0"), exec: function(editor) { editor.session.unfold(); }, + scrollIntoView: "center", readOnly: true }, { name: "findnext", @@ -125,6 +151,7 @@ exports.commands = [{ bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"), exec: function(editor) { editor.navigateFileStart(); }, multiSelectAction: "forEach", + scrollIntoView: "cursor", readOnly: true, group: "fileJump" }, { @@ -345,7 +372,8 @@ exports.commands = [{ name: "togglecomment", bindKey: bindKey("Ctrl-/", "Command-/"), exec: function(editor) { editor.toggleCommentLines(); }, - multiSelectAction: "forEachLine" + multiSelectAction: "forEachLine", + scrollIntoView: "selectionPart" }, { name: "toggleBlockComment", bindKey: bindKey("Ctrl-Shift-/", "Command-Shift-/"), @@ -439,26 +467,31 @@ exports.commands = [{ name: "outdent", bindKey: bindKey("Shift-Tab", "Shift-Tab"), exec: function(editor) { editor.blockOutdent(); }, - multiSelectAction: "forEach" + multiSelectAction: "forEach", + scrollIntoView: "selectionPart" }, { name: "indent", bindKey: bindKey("Tab", "Tab"), exec: function(editor) { editor.indent(); }, - multiSelectAction: "forEach" -},{ + multiSelectAction: "forEach", + scrollIntoView: "selectionPart" +}, { name: "blockoutdent", bindKey: bindKey("Ctrl-[", "Ctrl-["), exec: function(editor) { editor.blockOutdent(); }, - multiSelectAction: "forEachLine" -},{ + multiSelectAction: "forEachLine", + scrollIntoView: "selectionPart" +}, { name: "blockindent", bindKey: bindKey("Ctrl-]", "Ctrl-]"), exec: function(editor) { editor.blockIndent(); }, - multiSelectAction: "forEachLine" + multiSelectAction: "forEachLine", + scrollIntoView: "selectionPart" }, { name: "insertstring", exec: function(editor, str) { editor.insert(str); }, - multiSelectAction: "forEach" + multiSelectAction: "forEach", + scrollIntoView: "cursor" }, { name: "inserttext", exec: function(editor, args) { diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index a9b2ddd1..6886118b 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -108,6 +108,18 @@ function Folding() { return foundFolds; }; + + this.getFoldsInRangeList = function(ranges) { + if (Array.isArray(ranges)) { + var folds = []; + ranges.forEach(function(range) { + folds = folds.concat(this.getFoldsInRange(range)); + }, this); + } else { + var folds = this.getFoldsInRange(ranges); + } + return folds; + } /* * Returns all folds in the document @@ -273,7 +285,7 @@ function Folding() { // --- Some checking --- if (!(startRow < endRow || - startRow == endRow && startColumn <= endColumn - 2)) + startRow == endRow && startColumn < endColumn - 2)) throw new Error("The range has to be at least 2 characters width"); var startFold = this.getFoldAt(startRow, startColumn, 1); @@ -413,7 +425,7 @@ function Folding() { }; this.expandFold = function(fold) { - this.removeFold(fold); + this.removeFold(fold); fold.subFolds.forEach(function(subFold) { fold.restoreRange(subFold); this.addFold(subFold); @@ -441,8 +453,8 @@ function Folding() { range = Range.fromPoints(location, location); else range = location; - - folds = this.getFoldsInRange(range); + + folds = this.getFoldsInRangeList(range); if (expandInner) { this.removeFolds(folds); } else { @@ -450,7 +462,7 @@ function Folding() { // expandFolds several times. while (folds.length) { this.expandFolds(folds); - folds = this.getFoldsInRange(range); + folds = this.getFoldsInRangeList(range); } } }; @@ -636,17 +648,16 @@ function Folding() { continue; var range = this.getFoldWidgetRange(row); - var rangeEndRow = range.end.row; // sometimes range can be incompatible with existing fold // TODO change addFold to return null istead of throwing if (range && range.isMultiLine() - && rangeEndRow <= endRow + && range.end.row <= endRow && range.start.row >= startRow ) try { var fold = this.addFold("...", range); fold.collapseChildren = depth; // addFold can change the range - row = rangeEndRow; + row = range.end.row; } catch(e) {} } }; @@ -727,25 +738,34 @@ function Folding() { } this.onFoldWidgetClick = function(row, e) { + e = e.domEvent; + var options = { + children: e.shiftKey, + all: e.ctrlKey || e.metaKey, + siblings: e.altKey + }; + + var range = this.$toggleFoldWidget(row, options); + if (!range) + (e.target || e.srcElement).className += " ace_invalid"; + }; + + this.$toggleFoldWidget = function(row, options) { var type = this.getFoldWidget(row); var line = this.getLine(row); - e = e.domEvent; - var children = e.shiftKey; - var all = e.ctrlKey || e.metaKey; - var siblings = e.altKey; var dir = type === "end" ? -1 : 1; var fold = this.getFoldAt(row, dir === -1 ? 0 : line.length, dir); if (fold) { - if (children || all) + if (options.children || options.all) this.removeFold(fold); else this.expandFold(fold); return; } - var range = this.getFoldWidgetRange(row); + var range = this.getFoldWidgetRange(row, true); // sometimes singleline folds can be missed by the code above if (range && !range.isMultiLine()) { fold = this.getFoldAt(range.start.row, range.start.column, 1); @@ -755,24 +775,48 @@ function Folding() { } } - if (siblings) { + if (options.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); + this.foldAll(startRow, endRow, options.all ? 10000 : 0); + } else if (options.children) { + endRow = range ? range.end.row : this.getLength(); + this.foldAll(row + 1, range.end.row, options.all ? 10000 : 0); } else if (range) { - if (all) + if (options.all) range.collapseChildren = 10000; this.addFold("...", range); } - if (!range) - (e.target || e.srcElement).className += " ace_invalid" + return range; + }; + + + + this.toggleFoldWidget = function(toggleParent) { + var row = this.selection.getCursor().row; + row = this.getRowFoldStart(row); + var range = this.$toggleFoldWidget(row, {}); + + if (range) + return; + // handle toggleParent + var data = this.getParentFoldRangeData(row, true); + range = data.range || data.firstRange; + + if (range) { + row = range.start.row; + var fold = this.getFoldAt(row, this.getLine(row).length, 1); + + if (fold) { + this.removeFold(fold); + } else { + this.addFold("...", range); + } + } }; this.updateFoldWidgets = function(e) { diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 4ff568c9..ff781507 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -1643,8 +1643,8 @@ var Editor = function(renderer, session) { var range = this.getSelectionRange().collapseRows(); return { - first: range.start.row, - last: range.end.row + first: this.session.getRowFoldStart(range.start.row), + last: this.session.getRowFoldEnd(range.end.row) }; }; diff --git a/lib/ace/mode/folding/cstyle.js b/lib/ace/mode/folding/cstyle.js index 8be20d27..9ffb3438 100644 --- a/lib/ace/mode/folding/cstyle.js +++ b/lib/ace/mode/folding/cstyle.js @@ -52,7 +52,7 @@ oop.inherits(FoldMode, BaseFoldMode); this.foldingStartMarker = /(\{|\[)[^\}\]]*$|^\s*(\/\*)/; this.foldingStopMarker = /^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/; - this.getFoldWidgetRange = function(session, foldStyle, row) { + this.getFoldWidgetRange = function(session, foldStyle, row, forceMultiline) { var line = session.getLine(row); var match = line.match(this.foldingStartMarker); if (match) { @@ -60,8 +60,17 @@ oop.inherits(FoldMode, BaseFoldMode); if (match[1]) return this.openingBracketBlock(session, match[1], row, i); - - return session.getCommentFoldRange(row, i + match[0].length, 1); + + var range = session.getCommentFoldRange(row, i + match[0].length, 1); + + if (range && !range.isMultiLine()) { + if (forceMultiline) { + range = this.getSectionRange(session, row); + } else if (foldStyle != "all") + range = null; + } + + return range; } if (foldStyle !== "markbeginend") @@ -77,6 +86,37 @@ oop.inherits(FoldMode, BaseFoldMode); return session.getCommentFoldRange(row, i, -1); } }; + + this.getSectionRange = function(session, row) { + var line = session.getLine(row); + var startIndent = line.search(/\S/); + var startRow = row; + var startColumn = line.length; + row = row + 1; + var endRow = row; + var maxRow = session.getLength(); + while (++row < maxRow) { + line = session.getLine(row); + var indent = line.search(/\S/); + if (indent === -1) + continue; + if (startIndent > indent) + break; + var subRange = this.getFoldWidgetRange(session, "all", row); + + if (subRange) { + if (subRange.isMultiLine()) { + row = subRange.end.row; + } else if (startIndent == indent) { + endRow = row - 1; + break; + } + } + endRow = row; + } + + return new Range(startRow, startColumn, endRow, session.getLine(endRow).length); + }; }).call(FoldMode.prototype); diff --git a/lib/ace/mode/folding/fold_mode.js b/lib/ace/mode/folding/fold_mode.js index 9272cdcd..7a6e9ec8 100644 --- a/lib/ace/mode/folding/fold_mode.js +++ b/lib/ace/mode/folding/fold_mode.js @@ -94,7 +94,7 @@ var FoldMode = exports.FoldMode = function() {}; var fw = session.foldWidgets[end.row]; if (fw == null) - fw = this.getFoldWidget(session, end.row); + fw = session.getFoldWidget(end.row); if (fw == "start" && end.row > start.row) { end.row --; diff --git a/lib/ace/mode/sh.js b/lib/ace/mode/sh.js index c66c2619..7620deee 100644 --- a/lib/ace/mode/sh.js +++ b/lib/ace/mode/sh.js @@ -36,9 +36,11 @@ var TextMode = require("./text").Mode; var Tokenizer = require("../tokenizer").Tokenizer; var ShHighlightRules = require("./sh_highlight_rules").ShHighlightRules; var Range = require("../range").Range; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; var Mode = function() { this.HighlightRules = ShHighlightRules; + this.foldingRules = new CStyleFoldMode(); }; oop.inherits(Mode, TextMode); diff --git a/lib/ace/mouse/fold_handler.js b/lib/ace/mouse/fold_handler.js index d47f6d53..45aae96f 100644 --- a/lib/ace/mouse/fold_handler.js +++ b/lib/ace/mouse/fold_handler.js @@ -73,7 +73,7 @@ function FoldHandler(editor) { var range = data.range || data.firstRange; if (range) { - var row = range.start.row; + row = range.start.row; var fold = session.getFoldAt(row, session.getLine(row).length, 1); if (fold) {