better folding for coffeescript

This commit is contained in:
nightwing 2012-06-16 13:51:18 +04:00
commit 38eb07df67
6 changed files with 251 additions and 13 deletions

View file

@ -41,7 +41,7 @@ define(function(require, exports, module) {
var Tokenizer = require("../tokenizer").Tokenizer;
var Rules = require("./coffee_highlight_rules").CoffeeHighlightRules;
var Outdent = require("./matching_brace_outdent").MatchingBraceOutdent;
var PythonFoldMode = require("./folding/pythonic").FoldMode;
var PythonFoldMode = require("./folding/coffee").FoldMode;
var Range = require("../range").Range;
var TextMode = require("./text").Mode;
var WorkerClient = require("../worker/worker_client").WorkerClient;

View file

@ -0,0 +1,127 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("../../lib/oop");
var BaseFoldMode = require("./fold_mode").FoldMode;
var Range = require("../../range").Range;
var FoldMode = exports.FoldMode = function() {};
oop.inherits(FoldMode, BaseFoldMode);
(function() {
this.getFoldWidgetRange = function(session, foldStyle, row) {
var range = this.indentationBlock(session, row);
if (range)
return range;
var re = /\S/;
var line = session.getLine(row);
var startLevel = line.search(re);
if (startLevel == -1 || line[startLevel] != "#")
return;
var startColumn = line.length;
var maxRow = session.getLength();
var startRow = row;
var endRow = row;
while (++row < maxRow) {
line = session.getLine(row);
var level = line.search(re);
if (level == -1)
continue;
if (line[level] != "#")
break;
endRow = row;
}
if (endRow > startRow) {
var endColumn = session.getLine(endRow).length;
return new Range(startRow, startColumn, endRow, endColumn);
}
};
// must return "" if there's no fold, to enable caching
this.getFoldWidget = function(session, foldStyle, row) {
var line = session.getLine(row);
var indent = line.search(/\S/);
var next = session.getLine(row + 1);
var prev = session.getLine(row - 1);
var prevIndent = prev.search(/\S/);
var nextIndent = next.search(/\S/);
if (indent == -1) {
session.foldWidgets[row - 1] = prevIndent!= -1 && prevIndent < nextIndent ? "start" : "";
return "";
}
// documentation comments
if (prevIndent == -1) {
if (indent == nextIndent && line[indent] == "#" && next[indent] == "#") {
session.foldWidgets[row - 1] = "";
session.foldWidgets[row + 1] = "";
return "start";
}
} else if (prevIndent == indent && line[indent] == "#" && prev[indent] == "#") {
if (session.getLine(row - 2).search(/\S/) == -1) {
session.foldWidgets[row - 1] = "start";
session.foldWidgets[row + 1] = "";
return ""
}
}
if (prevIndent!= -1 && prevIndent < indent)
session.foldWidgets[row - 1] = "start";
else
session.foldWidgets[row - 1] = "";
if (indent < nextIndent)
return "start";
else
return "";
};
}).call(FoldMode.prototype);
});

View file

@ -0,0 +1,108 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined")
require("amd-loader");
define(function(require, exports, module) {
"use strict";
var CoffeeMode = require("../coffee").Mode;
var EditSession = require("../../edit_session").EditSession;
var assert = require("../../test/assertions");
function testFoldWidgets(array) {
var session = array.filter(function(_, i){return i % 2 == 1});
session = new EditSession(session);
var mode = new CoffeeMode();
session.setFoldStyle("markbeginend");
session.setMode(mode);
var widgets = array.filter(function(_, i){return i % 2 == 0});
widgets.forEach(function(w, i){
session.foldWidgets[i] = session.getFoldWidget(i);
})
widgets.forEach(function(w, i){
w = w.split(",");
var type = w[0] == ">" ? "start" : w[0] == "<" ? "end" : "";
assert.equal(session.foldWidgets[i], type);
if (!type)
return;
var range = session.getFoldWidgetRange(i);
if (!w[1]) {
assert.equal(range, null);
return;
}
assert.equal(range.start.row, i);
assert.equal(range.end.row - range.start.row, parseInt(w[1]));
testColumn(w[2], range.start);
testColumn(w[3], range.end);
});
function testColumn(w, pos) {
if (!w)
return;
if (w == "l")
w = session.getLine(pos.row).length;
else
w = parseInt(w);
assert.equal(pos.column, w);
}
}
module.exports = {
"test: coffee script indentation based folding": function() {
testFoldWidgets([
'>,1,l,l', ' ## indented comment',
'', ' # ',
'', '',
'>,1,l,l', ' # plain comment',
'', ' # ',
'>,2', ' function (x)=>',
'', ' ',
'', ' x++',
'', ' ',
'', ' ',
'>,2', ' bar = ',
'', ' foo: 1',
'', ' baz: lighter'
]);
}
};
});
if (typeof module !== "undefined" && module === require.main)
require("asyncjs").test.testcase(module.exports).exec();

View file

@ -58,25 +58,27 @@ var FoldMode = exports.FoldMode = function() {};
return "end";
return "";
};
this.getFoldWidgetRange = function(session, foldStyle, row) {
return null;
};
this.indentationBlock = function(session, row, column) {
var re = /^\s*/;
var re = /\S/;
var line = session.getLine(row);
var startLevel = line.search(re);
if (startLevel == -1)
return;
var startColumn = column || line.length;
var maxRow = session.getLength();
var startRow = row;
var endRow = row;
var line = session.getLine(row);
var startColumn = column || line.length;
var startLevel = line.match(re)[0].length;
var maxRow = session.getLength()
while (++row < maxRow) {
line = session.getLine(row);
var level = line.match(re)[0].length;
if (level == line.length)
while (++row < maxRow) {
var level = session.getLine(row).search(re);
if (level == -1)
continue;
if (level <= startLevel)

View file

@ -61,7 +61,7 @@ module.exports = {
session.setFoldStyle("markbeginend");
session.setMode(mode);
assert.equal(session.getFoldWidget(0), "start");
assert.equal(session.getFoldWidget(0), "");
assert.equal(session.getFoldWidget(1), "");
assert.equal(session.getFoldWidget(2), "");
assert.equal(session.getFoldWidget(3), "start");

View file

@ -42,6 +42,7 @@ var testNames = [
"ace/mode/folding/html_test",
"ace/mode/folding/pythonic_test",
"ace/mode/folding/xml_test",
"ace/mode/folding/coffee_test",
"ace/multi_select_test",
"ace/range_test",
"ace/range_list_test",