better folding commands

This commit is contained in:
nightwing 2013-11-05 20:43:30 +04:00
commit d689636771
7 changed files with 161 additions and 42 deletions

View file

@ -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) {

View file

@ -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) {

View file

@ -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)
};
};

View file

@ -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);

View file

@ -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 --;

View file

@ -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);

View file

@ -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) {