increasing fold efficiency

Looking at the code I see that on every keypress we get the equivalent of:

function onChange(cm) {
    var state = cm.state.foldGutter;
    ...
    clearTimeout(state.changeUpdate);
    state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, ..opts.foldOnChangeTimeSpan || 600);
  }

  function updateInViewport(cm) {
    var vp = cm.getViewport(), state = cm.state.foldGutter;
   ...
    cm.operation(function() {  updateFoldInfo(cm, vp.from, vp.to);  });
   ...
  }

Basically once cm.state.foldGutter.changeUpdate tmeouts, updateFoldInfo will invoke the fold function for every line in view even if onChange is called again.

In my case the folding logic is complex and expensive. To determine if a line is foldable I need to iterate on lines before and after, check for indentation, wrapping, bullets etc … so it is inefficient to keep going over the viewport if another change is done to the document and that can delay the next onChange etc.

What is needed is for cm to stop updateFoldInfo iteration on the viewport if a new onChange arrives since updateInViewport will anyway start it again from the beginning.

I hope that makes sense.
Thanks!

You seem to be asking whether the running fold computation can be aborted when something happens? That’s not something that JavaScript can do – as long as a (synchronous) computation happens, no new events are delivered, so even that computation itself can not determine whether the user did something.

If your folding computation is that expensive, maybe don’t show the fold gutter, since that will definitely have a negative impact on responsiveness.

Thank you !

I understand the difficulty with aborting the computation. However there is no point in completing updateFoldInfo over the whole viewport if a new onChange will again run it from the start.

What is needed is for updateInViewport, instead of doing updateFoldInfo(cm, vp.from, vp.to), to start an async loop of some sort from vp.from to vp.to … For example maybe starting updateFoldInfo(cm, line, line, callback) with a timeout and then have callback start updateFoldInfo on the next line unless vp.to is reached or a stop is signaled from onChange … I hope that makes sense ?

I think this will make folding more efficient on all modes even if the difference may be small if folding is not expensive.

That would be possible, but it would also complicate the bookkeeping the foldgutter addon does (it needs to know which gutter markers are up to date). I don’t have time to work on that, but if you want to create an implementation, I’d gladly look at a pull request.