diff --git a/lib/ace/mode/folding/lua.js b/lib/ace/mode/folding/lua.js index 73a6a37c..369eed9e 100644 --- a/lib/ace/mode/folding/lua.js +++ b/lib/ace/mode/folding/lua.js @@ -3,7 +3,7 @@ * * Copyright (c) 2012, Ajax.org B.V. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright @@ -14,7 +14,7 @@ * * Neither the name of Ajax.org B.V. nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -34,6 +34,8 @@ define(function(require, exports, module) { var oop = require("../../lib/oop"); var BaseFoldMode = require("./fold_mode").FoldMode; var Range = require("../../range").Range; +var TokenIterator = require("ace/token_iterator").TokenIterator; + var FoldMode = exports.FoldMode = function() {}; @@ -52,11 +54,11 @@ oop.inherits(FoldMode, BaseFoldMode); if (isStart && !isEnd) { var match = line.match(this.foldingStartMarker); if (match[1]) { - if (session.getTokenAt(row, match.index + 1).type == "keyword") + if (session.getTokenAt(row, match.index + 1).type === "keyword") return "start"; } else if (match[2]) { - var type = session.getTokenAt(row + 1, 0).type - if (type == "comment" || type == "string") + var type = session.bgTokenizer.getState(row) || ""; + if (type.indexOf("comment") != -1 || type.indexOf("string") != -1) return "start"; } else { return "start"; @@ -66,43 +68,108 @@ oop.inherits(FoldMode, BaseFoldMode); return ""; var match = line.match(this.foldingStopMarker); - if (match[0] == "end") { - if (session.getTokenAt(row, match.index + 1).type == "keyword") + if (match[0] === "end") { + if (session.getTokenAt(row, match.index + 1).type === "keyword") return "end"; - } else if (match[0][0] == "]") { - var type = session.getTokenAt(row - 1, 0).type - if (type == "comment" || type == "string") + } else if (match[0][0] === "]") { + var type = session.bgTokenizer.getState(row - 1) || ""; + if (type.indexOf("comment") != -1 || type.indexOf("string") != -1) return "end"; } else return "end"; }; this.getFoldWidgetRange = function(session, foldStyle, row) { - var lines = session.doc.getAllLines(row); - var line = lines[row]; - - var re = this.foldingStartMarker.test(line) ? this.foldingStartMarker : this.foldingStopMarker; + var line = session.doc.getLine(row); + var match = this.foldingStartMarker.exec(line); + if (match) { + if (match[1]) + return this.luaBlock(session, row, match.index + 1); - if (this.foldingStartMarker.test(line)) { - for (var i = row + 1, l = session.getLength(); i < l; i++) { - if (re.test(lines[i])) - break; - } + if (match[2]) + return session.getCommentFoldRange(row, match.index + 1); - return new Range(row, line.length, i, 0); + return this.openingBracketBlock(session, "{", row, match.index); } - if (this.foldingStopMarker.test(line)) { - for (var i = row - 1; i >= 0; i--) { - line = lines[i]; - if (re.test(line)) - break; + var match = this.foldingStopMarker.exec(line); + if (match) { + if (match[0] === "end") { + if (session.getTokenAt(row, match.index + 1).type === "keyword") + return this.luaBlock(session, row, match.index + 1); } - return new Range(i, line.length, row, 0); + if (match[0][0] === "]") + return session.getCommentFoldRange(row, match.index + 1); + + return this.closingBracketBlock(session, "}", row, match.index + match[0].length); } }; - + + this.luaBlock = function(session, row, column) { + var stream = new TokenIterator(session, row, column); + var indentKeywords = { + "function": 1, + "do": 1, + "then": 1, + "elseif": -1, + "else": 0, + "end": -1, + "repeat": 1, + "until": -1, + }; + var voidKeywords = { + "elseif": 1, + "if": 1, + "for": 1 + }; + + var token = stream.getCurrentToken(); + if (!token || token.type != "keyword") + return; + + var val = token.value; + var stack = [val]; + var dir; + if (voidKeywords[val]) { + stack = []; + dir = 1; + } else if (val === "else") { + dir = 1; + } else { + dir = indentKeywords[val]; + } + + if (!dir) + return; + + var startColumn = dir === -1 ? stream.getCurrentTokenColumn() : session.getLine(row).length; + var startRow = row; + + stream.step = dir === -1 ? stream.stepBackward : stream.stepForward; + while(token = stream.step()) { + if (token.type !== "keyword") + continue; + var level = dir * indentKeywords[token.value]; + + if (level > 0) { + stack.unshift(token.value); + } else if (level <= 0) { + stack.shift(); + if (!stack.length) + break; + if (level === 0) + stack.unshift(token.value); + } + } + + var row = stream.getCurrentTokenRow(); + if (dir === -1) + return new Range(row, session.getLine(row).length, startRow, startColumn); + else + return new Range(startRow, startColumn, row, stream.getCurrentTokenColumn()); + }; + }).call(FoldMode.prototype); });