Code Folding

The code folding mode specifies to Ace (Cloud9's editor) how to place fold UI in the gutter for your mode.

Adding new folding rules to your mode can be a little tricky. First, insert the following lines of code into your mode definition:

var MyFoldMode = require("./folding/newrules").FoldMode;
...
var MyMode = function() {
    ...
    this.foldingRules = new MyFoldMode();
};

You'll be defining your code folding rules into the lib/ace/mode/folding folder. Here's a template that you can use to get started:

define(function(require, exports, module) {
"use strict";

var oop = require("../../lib/oop");
var Range = require("../../range").Range;
var BaseFoldMode = require("./fold_mode").FoldMode;

var FoldMode = exports.FoldMode = function() {};
oop.inherits(FoldMode, BaseFoldMode);

(function() {

    // regular expressions that identify starting and stopping points
    this.foldingStartMarker; 
    this.foldingStopMarker;

    this.getFoldWidgetRange = function(session, foldStyle, row) {
        var line = session.getLine(row);

        // test each line, and return a range of segments to collapse
    };

}).call(FoldMode.prototype);

});

Just like with TextMode for syntax highlighting, BaseFoldMode contains the starting point for code folding logic. foldingStartMarker defines your opening folding point, while foldingStopMarker defines the stopping point. For example, for a C-style folding system, these values might look like this:

this.foldingStartMarker = /(\{|\[)[^\}\]]*$|^\s*(\/\*)/;
this.foldingStopMarker = /^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/;

These regular expressions identify various symbols {, [, // to pay attention to. getFoldWidgetRange matches on these regular expressions, and when found, returns the range of relevant folding points. For more information on the Range object, see the Ace API documentation.

Again, for a C-style folding mechanism, a range to return for the starting fold might look like this:

var line = session.getLine(row);
var match = line.match(this.foldingStartMarker);
if (match) {
    var i = match.index;

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

Let's say we stumble across the code block hello_world() {. Our range object here becomes:

{
  startRow: 0,
  endRow: 0,
  startColumn: 0,
  endColumn: 13
}