Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

improve folding #1042

Closed
wants to merge 20 commits into from

4 participants

@nightwing
Owner

added special folding for lua, latex, markdown
enabled folding for several other modes
added ability to fold by double clicking on the gutter
+ some minor cleanup

@ajaxorg/liskov @gjtorikian

@mostafaeweda mostafaeweda commented on the diff
lib/ace/mode/ruby.js
@@ -37,10 +37,12 @@ var Tokenizer = require("../tokenizer").Tokenizer;
var RubyHighlightRules = require("./ruby_highlight_rules").RubyHighlightRules;
var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
var Range = require("../range").Range;
+var FoldMode = require("./folding/coffee").FoldMode;
@mostafaeweda Collaborator

Why would the ruby has coffee folding mode ?
Ruby may not follow the indentation rules as coffee --> I guess ruby must have its own folding rules

@nightwing Owner

Unfortunately rules for Ruby blocks seem to be rather complex, and i couldn't make it work.
Using indentation is the next best thing, much better than no folding at all.
btw Sublime Text uses indentation for all languages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@gjtorikian
Collaborator

I continue to be completely baffled by how the fold modes work. I just can't wrap my head around it. It seems like it ought to be trivial--define a start regex, and an end regex, and that's it ! But no.... :(

Anyway, for that reason, I don't really feel comfortable reviewing this.

@bootstraponline

:thumbsup: The markdown folding is wonderful. It looks like there's no support for the alternate GitHub style code block ~~~.

~~~ { .ruby #is .valid }
puts 'ruby!'
~~~~
puts 'ruby!'

I recently added this to gollum. GitHub.com has supported it for a while.

@nightwing
Owner

It seems like it ought to be trivial--define a start regex, and an end regex, and that's it !
almost, you also need to use rather complex alghorithm to try filter out false positives based on indentation
https://github.com/textmate/textmate/blob/master/Frameworks/layout/src/folds.cc#L279

but even with that, markdown and latex foldings won't work.

@bootstraponline i didn't know about ~~~ blocks, i'll try to add that soon but support for nested blocks requires bigish changes to tokenizer, so it will take some time.

@gjtorikian
Collaborator

for the alternate GitHub style code block

Does ~~~ { .ruby #is .valid } render as <pre id="is" class="ruby valid">? This is the first time I've seen ~~~ over ```

but even with that, markdown and latex foldings won't work.

Yeah, I get that. My brain just has a hard time seeing how all the start/stop/block/keyword/first-level/second-level rules work. One day it'll click, but that day is not now :crying_cat_face:

@bootstraponline

@gjtorikian Only the first class is used on GitHub. {} is optional and ~~~ can be more than three. Here's the gollum implementation. Pandoc has a good write up of the syntax.

@nightwing nightwing closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 26, 2012
  1. @gjtorikian @nightwing

    Start work on lua fodmode

    gjtorikian authored nightwing committed
  2. @nightwing

    add folding for ruby

    nightwing authored
  3. @nightwing
  4. @nightwing
  5. @nightwing
  6. @nightwing

    fix php autoindent

    nightwing authored
  7. @nightwing
  8. @nightwing
  9. @nightwing

    fix several typos

    nightwing authored
  10. @nightwing
  11. @nightwing
  12. @nightwing

    improve comment folding

    nightwing authored
  13. @nightwing
  14. @nightwing

    add latex folding

    nightwing authored
  15. @nightwing

    finish lua folding

    nightwing authored
  16. @nightwing

    nicer mouse behavior for foldwigets

    nightwing authored
      activate on mousedown and on double click
  17. @nightwing
  18. @nightwing
  19. @nightwing

    quick fix for comment folding issue

    nightwing authored
    //comment
    /*this fold widget was consuming the line above
     */
Commits on Nov 3, 2012
  1. @nightwing

    simplify lua folding

    nightwing authored
This page is out of date. Refresh to see the latest.
View
5 lib/ace/edit_session.js
@@ -1876,10 +1876,9 @@ var EditSession = function(text, mode) {
row ++;
} else {
tokens = [];
- foldLine.walk(
- function(placeholder, row, column, lastColumn) {
+ foldLine.walk(function(placeholder, row, column, lastColumn) {
var walkTokens;
- if (placeholder) {
+ if (placeholder != null) {
walkTokens = this.$getDisplayTokens(
placeholder, tokens.length);
walkTokens[0] = PLACEHOLDER_START;
View
37 lib/ace/edit_session/folding.js
@@ -274,9 +274,6 @@ function Folding() {
var endColumn = fold.end.column;
// --- Some checking ---
- if (fold.placeholder.length < 2)
- throw "Placeholder has to be at least 2 characters";
-
if (startRow == endRow && endColumn - startColumn < 2)
throw "The range has to be at least 2 characters width";
@@ -489,7 +486,7 @@ function Folding() {
}
lastColumn = Math.max(startColumn, lastColumn);
}
- if (placeholder) {
+ if (placeholder != null) {
textLine += placeholder;
} else {
textLine += doc.getLine(row).substring(lastColumn, column);
@@ -588,30 +585,34 @@ function Folding() {
this.addFold(placeholder, range);
};
- this.getCommentFoldRange = function(row, column) {
+ this.getCommentFoldRange = function(row, column, dir) {
var iterator = new TokenIterator(this, row, column);
var token = iterator.getCurrentToken();
if (token && /^comment|string/.test(token.type)) {
var range = new Range();
var re = new RegExp(token.type.replace(/\..*/, "\\."));
- do {
- token = iterator.stepBackward();
- } while(token && re.test(token.type));
-
- iterator.stepForward();
+ if (dir != 1) {
+ do {
+ token = iterator.stepBackward();
+ } while(token && re.test(token.type));
+ iterator.stepForward();
+ }
+
range.start.row = iterator.getCurrentTokenRow();
range.start.column = iterator.getCurrentTokenColumn() + 2;
iterator = new TokenIterator(this, row, column);
-
- do {
- token = iterator.stepForward();
- } while(token && re.test(token.type));
- token = iterator.stepBackward();
+ if (dir != -1) {
+ do {
+ token = iterator.stepForward();
+ } while(token && re.test(token.type));
+ token = iterator.stepBackward();
+ } else
+ token = iterator.getCurrentToken();
range.end.row = iterator.getCurrentTokenRow();
- range.end.column = iterator.getCurrentTokenColumn() + token.value.length;
+ range.end.column = iterator.getCurrentTokenColumn() + token.value.length - 2;
return range;
}
};
@@ -628,7 +629,7 @@ function Folding() {
var range = this.getFoldWidgetRange(row);
// sometimes range can be incompatible with existing fold
// wouldn't it be better for addFold to return null istead of throwing?
- if (range && range.end.row < endRow) try {
+ if (range && range.end.row <= endRow) try {
this.addFold("...", range);
} catch(e) {}
}
@@ -722,7 +723,7 @@ function Folding() {
} else {
if (addSubfolds)
this.foldAll(row + 1, this.getLength());
- (e.target || e.srcElement).className += " invalid"
+ (e.target || e.srcElement).className += " ace_invalid"
}
};
View
2  lib/ace/edit_session_test.js
@@ -920,7 +920,7 @@ module.exports = {
tryAddFold("foo", new Range(0, 13, 0, 18), false);
assert.equal(session.$foldData[0].folds.length, 1);
- tryAddFold("f", new Range(0, 13, 0, 18), true);
+ tryAddFold("f", new Range(0, 13, 0, 18), false);
tryAddFold("foo", new Range(0, 18, 0, 21), false);
assert.equal(session.$foldData[0].folds.length, 2);
session.removeFold(fold);
View
10 lib/ace/editor.js
@@ -665,7 +665,6 @@ var Editor = function(renderer, session) {
this.insert = function(text) {
var session = this.session;
var mode = session.getMode();
-
var cursor = this.getCursorPosition();
if (this.getBehavioursEnabled()) {
@@ -692,9 +691,8 @@ var Editor = function(renderer, session) {
var start = cursor.column;
var lineState = session.getState(cursor.row);
- var shouldOutdent = mode.checkOutdent(lineState, session.getLine(cursor.row), text);
var line = session.getLine(cursor.row);
- var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString());
+ var shouldOutdent = mode.checkOutdent(lineState, line, text);
var end = session.insert(cursor, text);
if (transform && transform.selection) {
@@ -711,12 +709,12 @@ var Editor = function(renderer, session) {
}
}
- var lineState = session.getState(cursor.row);
-
// TODO disabled multiline auto indent
// possibly doing the indent before inserting the text
// if (cursor.row !== end.row) {
if (session.getDocument().isNewLine(text)) {
+ var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString());
+
this.moveCursorTo(cursor.row+1, 0);
var size = session.getTabSize();
@@ -2126,4 +2124,4 @@ var Editor = function(renderer, session) {
exports.Editor = Editor;
-});
+});
View
2  lib/ace/layer/text.js
@@ -616,7 +616,7 @@ var Text = function(parentEl) {
var tokens = session.getTokens(row);
foldLine.walk(function(placeholder, row, column, lastColumn, isNewRow) {
- if (placeholder) {
+ if (placeholder != null) {
renderTokens.push({
type: "fold",
value: placeholder
View
2  lib/ace/mode/folding/asciidoc.js
@@ -39,7 +39,7 @@ var FoldMode = exports.FoldMode = function() {};
oop.inherits(FoldMode, BaseFoldMode);
(function() {
- this.foldingStartMarker = /^(?:\|={10,}|[\.\/=\-~^+]{4,}|={1,5} )/;
+ this.foldingStartMarker = /^(?:\|={10,}|[\.\/=\-~^+]{4,}\s*$|={1,5} )/;
this.singleLineHeadingRe = /^={1,5}(?=\s+\S)/;
this.getFoldWidget = function(session, foldStyle, row) {
View
32 lib/ace/mode/folding/cstyle.js
@@ -3,7 +3,7 @@
*
* Copyright (c) 2010, 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
@@ -42,7 +42,7 @@ oop.inherits(FoldMode, BaseFoldMode);
this.foldingStartMarker = /(\{|\[)[^\}\]]*$|^\s*(\/\*)/;
this.foldingStopMarker = /^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/;
-
+
this.getFoldWidgetRange = function(session, foldStyle, row) {
var line = session.getLine(row);
var match = line.match(this.foldingStartMarker);
@@ -52,37 +52,23 @@ oop.inherits(FoldMode, BaseFoldMode);
if (match[1])
return this.openingBracketBlock(session, match[1], row, i);
- var range = session.getCommentFoldRange(row, i + match[0].length);
- range.end.column -= 2;
- return range;
+ return session.getCommentFoldRange(row, i + match[0].length, 1);
}
if (foldStyle !== "markbeginend")
return;
-
+
var match = line.match(this.foldingStopMarker);
if (match) {
var i = match.index + match[0].length;
- if (match[2]) {
- var range = session.getCommentFoldRange(row, i);
- range.end.column -= 2;
- return range;
- }
-
- var end = {row: row, column: i};
- var start = session.$findOpeningBracket(match[1], end);
-
- if (!start)
- return;
-
- start.column++;
- end.column--;
+ if (match[1])
+ return this.closingBracketBlock(session, match[1], row, i);
- return Range.fromPoints(start, end);
+ return session.getCommentFoldRange(row, i, -1);
}
};
-
+
}).call(FoldMode.prototype);
});
View
16 lib/ace/mode/folding/fold_mode.js
@@ -3,7 +3,7 @@
*
* Copyright (c) 2010, 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
@@ -103,6 +103,18 @@ var FoldMode = exports.FoldMode = function() {};
return Range.fromPoints(start, end);
};
+ this.closingBracketBlock = function(session, bracket, row, column, typeRe) {
+ var end = {row: row, column: column};
+ var start = session.$findOpeningBracket(bracket, end);
+
+ if (!start)
+ return;
+
+ start.column++;
+ end.column--;
+
+ return Range.fromPoints(start, end);
+ };
}).call(FoldMode.prototype);
});
View
162 lib/ace/mode/folding/latex.js
@@ -0,0 +1,162 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * 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
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * 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
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** 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 TokenIterator = require("ace/token_iterator").TokenIterator;
+
+var FoldMode = exports.FoldMode = function() {};
+
+oop.inherits(FoldMode, BaseFoldMode);
+
+(function() {
+
+ this.foldingStartMarker = /^\s*\\(begin)|(section|subsection)\b|{\s*$/;
+ this.foldingStopMarker = /^\s*\\(end)\b|^\s*}/;
+
+ this.getFoldWidgetRange = function(session, foldStyle, row) {
+ var line = session.doc.getLine(row);
+ var match = this.foldingStartMarker.exec(line);
+ if (match) {
+ if (match[1])
+ return this.latexBlock(session, row, match[0].length - 1);
+ if (match[2])
+ return this.latexSection(session, row, match[0].length - 1);
+
+ return this.openingBracketBlock(session, "{", row, match.index);
+ }
+
+ var match = this.foldingStopMarker.exec(line);
+ if (match) {
+ if (match[1])
+ return this.latexBlock(session, row, match[0].length - 1);
+
+ return this.closingBracketBlock(session, "}", row, match.index + match[0].length);
+ }
+ };
+
+ this.latexBlock = function(session, row, column) {
+ var keywords = {
+ "\\begin": 1,
+ "\\end": -1
+ };
+
+ var stream = new TokenIterator(session, row, column);
+ var token = stream.getCurrentToken();
+ if (!token || token.type !== "keyword")
+ return;
+
+ var val = token.value;
+ var dir = keywords[val];
+
+ var getType = function() {
+ var token = stream.stepForward();
+ var type = token.type == "lparen" ?stream.stepForward().value : "";
+ if (dir === -1) {
+ stream.stepBackward();
+ if (type)
+ stream.stepBackward();
+ }
+ return type;
+ };
+ var stack = [getType()];
+ 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 = keywords[token.value];
+ if (!level)
+ continue;
+ var type = getType();
+ if (level === dir)
+ stack.unshift(type);
+ else if (stack.shift() !== type || !stack.length)
+ break;
+ }
+
+ if (stack.length)
+ return;
+
+ 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());
+ };
+
+ this.latexSection = function(session, row, column) {
+ var keywords = ["\\subsection", "\\section", "\\begin", "\\end"];
+
+ var stream = new TokenIterator(session, row, column);
+ var token = stream.getCurrentToken();
+ if (!token || token.type != "keyword")
+ return;
+
+ var startLevel = keywords.indexOf(token.value);
+ var stackDepth = 0
+ var endRow = row;
+
+ while(token = stream.stepForward()) {
+ if (token.type !== "keyword")
+ continue;
+ var level = keywords.indexOf(token.value);
+
+ if (level >= 2) {
+ if (!stackDepth)
+ endRow = stream.getCurrentTokenRow() - 1;
+ stackDepth += level == 2 ? 1 : - 1;
+ if (stackDepth < 0)
+ break
+ } else if (level >= startLevel)
+ break;
+ }
+
+ if (!stackDepth)
+ endRow = stream.getCurrentTokenRow() - 1;
+
+ while (endRow > row && !/\S/.test(session.getLine(endRow)))
+ endRow--;
+
+ return new Range(
+ row, session.getLine(row).length,
+ endRow, session.getLine(endRow).length
+ );
+ };
+
+}).call(FoldMode.prototype);
+
+});
View
163 lib/ace/mode/folding/lua.js
@@ -0,0 +1,163 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * 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
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * 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
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** 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 TokenIterator = require("ace/token_iterator").TokenIterator;
+
+
+var FoldMode = exports.FoldMode = function() {};
+
+oop.inherits(FoldMode, BaseFoldMode);
+
+(function() {
+
+ this.foldingStartMarker = /\b(function|then|do|repeat)\b|{\s*$|(\[=*\[)/;
+ this.foldingStopMarker = /\bend\b|^\s*}|\]=*\]/;
+
+ this.getFoldWidget = function(session, foldStyle, row) {
+ var line = session.getLine(row);
+ var isStart = this.foldingStartMarker.test(line);
+ var isEnd = this.foldingStopMarker.test(line);
+
+ if (isStart && !isEnd) {
+ var match = line.match(this.foldingStartMarker);
+ if (match[1] == "then" && /\belseif\b/test(line))
+ return;
+ if (match[1]) {
+ if (session.getTokenAt(row, match.index + 1).type === "keyword")
+ return "start";
+ } else if (match[2]) {
+ var type = session.bgTokenizer.getState(row) || "";
+ if (type.indexOf("comment") != -1 || type.indexOf("string") != -1)
+ return "start";
+ } else {
+ return "start";
+ }
+ }
+ if (foldStyle != "markbeginend" || !isEnd || isStart && isEnd)
+ return "";
+
+ var match = line.match(this.foldingStopMarker);
+ if (match[0] === "end") {
+ if (session.getTokenAt(row, match.index + 1).type === "keyword")
+ return "end";
+ } 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 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 (match[2])
+ return session.getCommentFoldRange(row, match.index + 1);
+
+ return this.openingBracketBlock(session, "{", row, match.index);
+ }
+
+ 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);
+ }
+
+ 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,
+ "end": -1,
+ "repeat": 1,
+ "until": -1,
+ };
+
+ var token = stream.getCurrentToken();
+ if (!token || token.type != "keyword")
+ return;
+
+ var val = token.value;
+ var stack = [val];
+ var 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 && token.value != "elseif")
+ 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);
+
+});
View
125 lib/ace/mode/folding/markdown.js
@@ -0,0 +1,125 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, 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
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * 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
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** 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.foldingStartMarker = /^(?:[=-]+\s*$|#{1,6} |`{3})/;
+
+ this.getFoldWidget = function(session, foldStyle, row) {
+ var line = session.getLine(row);
+ if (!this.foldingStartMarker.test(line))
+ return "";
+
+ if (line[0] == "`") {
+ if (session.bgTokenizer.getState(row) == "start")
+ return "end";
+ return "start";
+ }
+
+ return "start";
+ };
+
+ this.getFoldWidgetRange = function(session, foldStyle, row) {
+ var line = session.getLine(row);
+ var startColumn = line.length;
+ var maxRow = session.getLength();
+ var startRow = row;
+ var endRow = row;
+ if (!line.match(this.foldingStartMarker))
+ return;
+
+ if (line[0] == "`") {
+ if (session.bgTokenizer.getState(row) !== "start") {
+ while (++row < maxRow) {
+ line = session.getLine(row);
+ if (line[0] == "`" & line.substring(0, 3) == "```")
+ break;
+ }
+ return new Range(startRow, startColumn, row, 0);
+ } else {
+ while (row -- > 0) {
+ line = session.getLine(row);
+ if (line[0] == "`" & line.substring(0, 3) == "```")
+ break;
+ }
+ return new Range(row, line.length, startRow, 0);
+ }
+ }
+
+ var token;
+ function isHeading(row) {
+ token = session.getTokens(row)[0];
+ return token && token.type.lastIndexOf(heading, 0) === 0;
+ }
+
+ var heading = "markup.heading";
+ function getLevel() {
+ var ch = token.value[0];
+ if (ch == "=") return 6;
+ if (ch == "-") return 5;
+ return 7 - token.value.search(/[^#]/);
+ }
+
+ if (isHeading(row)) {
+ var startHeadingLevel = getLevel();
+ while (++row < maxRow) {
+ if (!isHeading(row))
+ continue;
+ var level = getLevel();
+ if (level >= startHeadingLevel)
+ break;
+ }
+
+ endRow = row - (!token || ["=", "-"].indexOf(token.value[0]) == -1 ? 1 : 2);
+
+ if (endRow > startRow) {
+ while (endRow > startRow && /^\s*$/.test(session.getLine(endRow)))
+ endRow--;
+ }
+
+ if (endRow > startRow) {
+ var endColumn = session.getLine(endRow).length;
+ return new Range(startRow, startColumn, endRow, endColumn);
+ }
+ }
+ };
+
+}).call(FoldMode.prototype);
+
+});
View
4 lib/ace/mode/jade.js
@@ -40,13 +40,13 @@ var oop = require("../lib/oop");
var TextMode = require("./text").Mode;
var Tokenizer = require("../tokenizer").Tokenizer;
var JadeHighlightRules = require("./jade_highlight_rules").JadeHighlightRules;
-// var JavascriptMode = require("../mode/javascript").Mode;
-// var CssMode = require("../mode/css").Mode;
+var FoldMode = require("./folding/coffee").FoldMode;
var Mode = function() {
var highlighter = new JadeHighlightRules();
this.$tokenizer = new Tokenizer(highlighter.getRules());
+ this.foldingRules = new FoldMode();
};
oop.inherits(Mode, TextMode);
View
5 lib/ace/mode/latex.js
@@ -5,11 +5,12 @@ var oop = require("../lib/oop");
var TextMode = require("./text").Mode;
var Tokenizer = require("../tokenizer").Tokenizer;
var LatexHighlightRules = require("./latex_highlight_rules").LatexHighlightRules;
+var LatexFoldMode = require("./folding/latex").FoldMode;
var Range = require("../range").Range;
-var Mode = function()
-{
+var Mode = function() {
this.$tokenizer = new Tokenizer(new LatexHighlightRules().getRules());
+ this.foldingRules = new LatexFoldMode();
};
oop.inherits(Mode, TextMode);
View
2  lib/ace/mode/lua.js
@@ -35,10 +35,12 @@ var oop = require("../lib/oop");
var TextMode = require("./text").Mode;
var Tokenizer = require("../tokenizer").Tokenizer;
var LuaHighlightRules = require("./lua_highlight_rules").LuaHighlightRules;
+var LuaFoldMode = require("./folding/lua").FoldMode;
var Range = require("../range").Range;
var Mode = function() {
this.$tokenizer = new Tokenizer(new LuaHighlightRules().getRules());
+ this.foldingRules = new LuaFoldMode();
};
oop.inherits(Mode, TextMode);
View
14 lib/ace/mode/markdown.js
@@ -38,6 +38,7 @@ var XmlMode = require("./xml").Mode;
var HtmlMode = require("./html").Mode;
var Tokenizer = require("../tokenizer").Tokenizer;
var MarkdownHighlightRules = require("./markdown_highlight_rules").MarkdownHighlightRules;
+var MarkdownFoldMode = require("./folding/markdown").FoldMode;
var Mode = function() {
var highlighter = new MarkdownHighlightRules();
@@ -49,18 +50,21 @@ var Mode = function() {
"xml-": XmlMode,
"html-": HtmlMode
});
+
+ this.foldingRules = new MarkdownFoldMode();
};
oop.inherits(Mode, TextMode);
(function() {
this.getNextLineIndent = function(state, line, tab) {
if (state == "listblock") {
- var match = /^((?:.+)?)(([-+*]|\d+\.)\s+)/.exec(line);
- if (match) {
- return new Array(match[1].length + 1).join(" ") + match[2];
- } else {
+ var match = /^(\s*)(?:([-+*])|(\d+)\.)(\s+)/.exec(line);
+ if (!match)
return "";
- }
+ var marker = match[2];
+ if (!marker)
+ marker = parseInt(match[3], 10) + 1 + ".";
+ return match[1] + marker + match[4];
} else {
return this.$getIndent(line);
}
View
2  lib/ace/mode/markdown_highlight_rules.js
@@ -78,7 +78,7 @@ var MarkdownHighlightRules = function() {
github_embed("css", "css-"),
{ // Github style block
token : "support.function",
- regex : "^```[a-zA-Z]+\\s*$",
+ regex : "^```[a-zA-Z]*\\s*$",
next : "githubblock"
}, { // block quote
token : "string",
View
15 lib/ace/mode/php.js
@@ -98,16 +98,29 @@ oop.inherits(Mode, TextMode);
var tokenizedLine = this.$tokenizer.getLineTokens(line, state);
var tokens = tokenizedLine.tokens;
+ var endState = tokenizedLine.state;
+
if (tokens.length && tokens[tokens.length-1].type == "comment") {
return indent;
}
- if (state == "start") {
+ if (state == "php-start") {
var match = line.match(/^.*[\{\(\[\:]\s*$/);
if (match) {
indent += tab;
}
+ } else if (state == "php-doc-start") {
+ if (endState != "php-doc-start") {
+ return "";
+ }
+ var match = line.match(/^\s*(\/?)\*/);
+ if (match) {
+ if (match[1]) {
+ indent += " ";
+ }
+ indent += "* ";
+ }
}
return indent;
View
20 lib/ace/mode/powershell_highlight_rules.js
@@ -74,6 +74,10 @@ var PowershellHighlightRules = function() {
token : "comment",
regex : "#.*$"
}, {
+ token : "comment.start",
+ regex : "<#",
+ next : "comment"
+ }, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
@@ -118,13 +122,21 @@ var PowershellHighlightRules = function() {
],
"comment" : [
{
- token : "comment", // closing comment
- regex : ".*?\\*\\/",
+ token : "comment.end",
+ regex : "#>",
next : "start"
}, {
- token : "comment", // comment spanning whole line
+ token : "doc.comment.tag",
+ merge : true,
+ regex : "^\\.\\w+"
+ }, {
+ token : "comment",
+ merge : true,
+ regex : "\\w+"
+ }, {
+ token : "comment",
merge : true,
- regex : ".+"
+ regex : "."
}
]
};
View
2  lib/ace/mode/ruby.js
@@ -37,10 +37,12 @@ var Tokenizer = require("../tokenizer").Tokenizer;
var RubyHighlightRules = require("./ruby_highlight_rules").RubyHighlightRules;
var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
var Range = require("../range").Range;
+var FoldMode = require("./folding/coffee").FoldMode;
@mostafaeweda Collaborator

Why would the ruby has coffee folding mode ?
Ruby may not follow the indentation rules as coffee --> I guess ruby must have its own folding rules

@nightwing Owner

Unfortunately rules for Ruby blocks seem to be rather complex, and i couldn't make it work.
Using indentation is the next best thing, much better than no folding at all.
btw Sublime Text uses indentation for all languages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
var Mode = function() {
this.$tokenizer = new Tokenizer(new RubyHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
+ this.foldingRules = new FoldMode();
};
oop.inherits(Mode, TextMode);
View
14 lib/ace/mode/typescript.js
@@ -41,19 +41,27 @@ define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
-var TextMode = require("./text").Mode;
+var jsMode = require("./javascript").Mode;
var Tokenizer = require("../tokenizer").Tokenizer;
var TypeScriptHighlightRules = require("./typescript_highlight_rules").TypeScriptHighlightRules;
+var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour;
+var CStyleFoldMode = require("./folding/cstyle").FoldMode;
+var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
var Mode = function() {
var highlighter = new TypeScriptHighlightRules();
this.$tokenizer = new Tokenizer(highlighter.getRules());
+ this.$outdent = new MatchingBraceOutdent();
+ this.$behaviour = new CstyleBehaviour();
+ this.foldingRules = new CStyleFoldMode();
};
-oop.inherits(Mode, TextMode);
+oop.inherits(Mode, jsMode);
(function() {
- // Extra logic goes here.
+ this.createWorker = function(session) {
+ return null;
+ };
}).call(Mode.prototype);
exports.Mode = Mode;
View
4 lib/ace/mouse/default_gutter_handler.js
@@ -3,7 +3,7 @@
*
* Copyright (c) 2010, 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
View
57 lib/ace/mouse/fold_handler.js
@@ -3,7 +3,7 @@
*
* Copyright (c) 2010, 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
@@ -32,11 +32,11 @@ define(function(require, exports, module) {
"use strict";
function FoldHandler(editor) {
-
+
editor.on("click", function(e) {
var position = e.getDocumentPosition();
var session = editor.session;
-
+
// If the user clicked on a fold, then expand it.
var fold = session.getFoldAt(position.row, position.column, 1);
if (fold) {
@@ -44,12 +44,12 @@ function FoldHandler(editor) {
session.removeFold(fold);
else
session.expandFold(fold);
-
+
e.stop();
}
});
-
- editor.on("gutterclick", function(e) {
+
+ editor.on("guttermousedown", function(e) {
var gutterRegion = editor.renderer.$gutterLayer.getRegion(e);
if (gutterRegion == "foldWidgets") {
@@ -60,6 +60,49 @@ function FoldHandler(editor) {
e.stop();
}
});
+
+ editor.on("gutterdblclick", function(e) {
+ var gutterRegion = editor.renderer.$gutterLayer.getRegion(e);
+
+ if (gutterRegion == "foldWidgets") {
+ var row = e.getDocumentPosition().row;
+ var session = editor.session;
+ var fw = session.foldWidgets;
+ if (!fw || fw[row])
+ return;
+
+ var i = row - 1, firstRange;
+ while (i >= 0) {
+ var c = fw[i];
+ if (c == null)
+ c = fw[i] = session.getFoldWidget();
+
+ if (c == "start") {
+ var range = session.getFoldWidgetRange(i);
+ if (!firstRange)
+ firstRange = range;
+ if (range && range.end.row >= row)
+ break;
+ }
+ i--;
+ }
+ if (i == -1)
+ range = firstRange;
+
+ if (range) {
+ var row = range.start.row;
+ var fold = session.getFoldAt(row, session.getLine(row).length, 1);
+
+ if (fold) {
+ session.removeFold(fold);
+ } else {
+ session.addFold("...", range);
+ editor.renderer.scrollCursorIntoView({row: range.start.row, column: 0});
+ }
+ }
+ e.stop();
+ }
+ });
}
exports.FoldHandler = FoldHandler;
Something went wrong with that request. Please try again.