From 38eb07df67459c0a9b2e42612159c5820e8ba938 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 16 Jun 2012 13:51:18 +0400 Subject: [PATCH] better folding for coffeescript --- lib/ace/mode/coffee.js | 2 +- lib/ace/mode/folding/coffee.js | 127 ++++++++++++++++++++++++++ lib/ace/mode/folding/coffee_test.js | 108 ++++++++++++++++++++++ lib/ace/mode/folding/fold_mode.js | 24 ++--- lib/ace/mode/folding/pythonic_test.js | 2 +- lib/ace/test/all_browser.js | 1 + 6 files changed, 251 insertions(+), 13 deletions(-) create mode 100644 lib/ace/mode/folding/coffee.js create mode 100644 lib/ace/mode/folding/coffee_test.js diff --git a/lib/ace/mode/coffee.js b/lib/ace/mode/coffee.js index 4afc2896..9d265b67 100644 --- a/lib/ace/mode/coffee.js +++ b/lib/ace/mode/coffee.js @@ -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; diff --git a/lib/ace/mode/folding/coffee.js b/lib/ace/mode/folding/coffee.js new file mode 100644 index 00000000..b502afc4 --- /dev/null +++ b/lib/ace/mode/folding/coffee.js @@ -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 + * + * 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); + +}); diff --git a/lib/ace/mode/folding/coffee_test.js b/lib/ace/mode/folding/coffee_test.js new file mode 100644 index 00000000..41c440a2 --- /dev/null +++ b/lib/ace/mode/folding/coffee_test.js @@ -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 + * + * 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(); diff --git a/lib/ace/mode/folding/fold_mode.js b/lib/ace/mode/folding/fold_mode.js index 9dcbda13..25407569 100644 --- a/lib/ace/mode/folding/fold_mode.js +++ b/lib/ace/mode/folding/fold_mode.js @@ -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) diff --git a/lib/ace/mode/folding/pythonic_test.js b/lib/ace/mode/folding/pythonic_test.js index ca853715..f0f93799 100644 --- a/lib/ace/mode/folding/pythonic_test.js +++ b/lib/ace/mode/folding/pythonic_test.js @@ -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"); diff --git a/lib/ace/test/all_browser.js b/lib/ace/test/all_browser.js index 934149e4..f1f68c81 100644 --- a/lib/ace/test/all_browser.js +++ b/lib/ace/test/all_browser.js @@ -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",