Fold Based on Indentation

476 views
Skip to first unread message

Scott Newman

unread,
Jun 25, 2015, 2:10:36 PM6/25/15
to ace-d...@googlegroups.com
Hey all,

I'm trying to allow folding only at certain levels of indentation. For example, if I want to fold all code at indent level 2 (or at column 8, given 4 spaces per tab):

function blah() {
   
var insideFunc = function() {
       
for (var i = 0; i < 10; i++) {
            console
.log("I will be folded");
       
}


       
for (var i = 0; i < 10; i++) {
            console
.log("I will also be folded");
       
}
   
};
}


The 2 loops are at level 2, so when the command is executed, only those 2 loops will be folded. I have it working, except the problem is with files that are larger than the document's view. So if the entire document fits on the screen, all of the foldWidgets in the session are calculated. However if the document is very large, only the foldWidgets of the lines on the screen are calculated until the user scrolls to the given lines. Is there anyway I can get the session to figure out all of the foldWidgets without manual input by the user (eg, scrolling to the bottom of the doc or going to a line off screen)?

Here is the function I'm using. My screen only fits the first 37 lines in the editor, so session.foldWidgets.length is always 37 until I scroll down, in which case it becomes the length of the last line visible on my screen.

var foldAtDepth = function(depth) {
   
var tab = tabManager.focussedTab,
        editor
, session, indent, range, fold;
       
   
if (tab.editor.type === "ace") {
        editor
= tab.editor.ace;
        session
= editor.session;
        indent
= 4 * depth;
       
       
if (session.$foldStyle === "markbegin") {
           
for (var i = 0; i< session.foldWidgets.length; i++) {
               
if (session.foldWidgets[i] === "start") {
                    range
= session.getFoldWidgetRange(i);
                   
                   
if (range !== null && range.end.column === indent) {
                        fold
= session.addFold("...", range);
                   
}
               
}
           
}
       
}
       
else if (session.$foldStyle === "markbeginend") {
            console
.log("todo: implement fold style 'markbeginend'");
       
}
       
else {
            console
.log("Unknown fold style " + session.$foldStyle);
       
}
   
}
};


Thanks in advance.

Harutyun Amirjanyan

unread,
Jun 25, 2015, 2:20:29 PM6/25/15
to ace-d...@googlegroups.com
Hi

foldWidgets are computed lazily, add

​if (session.foldWidgets[row] == null)
    session.foldWidgets[row] = session.getFoldWidget(row);


before if (session.foldWidgets[i] === "start") {

see https://github.com/ajaxorg/ace/blob/v1.1.9/lib/ace/edit_session/folding.js#L645-L646

session.$foldStyle === "markbegin" check is unnecessary here, since it is only for displaying upwards triangles 

instead of range.end.column === indent it is better to check
session.getLine(i).search(/\S/) === indent before calling getFoldWidgetRange
since getFoldWidgetRange is expensive especially for large ranges which usually will have smaller indent

set i = range.end.row after fold = session.addFold("...", range); since fold widgets inside folded range will have larger indent anyway


instead of  4 *  it i better to use editor.session.getTabSize() * 

Scott Newman

unread,
Jun 25, 2015, 3:13:27 PM6/25/15
to ace-d...@googlegroups.com
Wow thanks so much. I implemented all the changes you suggested and it's working perfectly. I've got a 25,000+ line document and I can barely notice any lag when folding! Here's the end code in case anyone else stumbles across this:

var foldAtDepth = function(depth) {
   
var tab = tabManager.focussedTab,
        editor
, session, indent, range, fold;
       
   
if (tab.editor.type === "ace") {
        editor
= tab.editor.ace;
        session
= editor.session;

        indent
= depth * session.getTabString().length;
       
       
for (var row = 0; row < session.getLength(); row++) {
           
if (session.foldWidgets[row] === undefined)
                session
.foldWidgets[row] = session.getFoldWidget(row);
           
if (session.foldWidgets[row] === "start") {
                range
= session.getFoldWidgetRange(row);
               
if (range !== null && session.getLine(row).search(/\S/) === indent) {

                    fold
= session.addFold("...", range);

                    row
= range.end.row;
               
}
           
}
       
}
   
}
};
Reply all
Reply to author
Forward
0 new messages