# Folding functions

**URL:** <https://discuss.codemirror.net/t/folding-functions/4189>\
**Category:** v6\
**Created:** [March 28, 2022, 4:21pm UTC](https://discuss.codemirror.net/t/folding-functions/4189 "2022-03-28T16:21:36Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 28, 2022, 4:21pm UTC](https://discuss.codemirror.net/t/folding-functions/4189/1 "2022-03-28T16:21:36Z")

</div>

For CM6, I had code like this to automatically fold all functions that started with `exports`:

\_dataLoadedConfig (v, op) {  
if (op !== ‘autoload’) return

```
/*
const cms = this.shadowRoot.querySelectorAll('co-codemirror')
cms.forEach(cm => {
  cm = cm._cm
  cm.operation(() => {
    for (let l = cm.firstLine(); l <= cm.lastLine(); ++l) {
      if (cm.getLine(l).startsWith('exports.')) cm.foldCode({ line: l, ch: 0 }, null, 'fold')
    }
  })
})
*/

```

}

Is there an equivalent way with CodeMirror 6?

---

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 29, 2022, 3:31am UTC](https://discuss.codemirror.net/t/folding-functions/4189/2 "2022-03-29T03:31:28Z")

</div>

Please ignore. I somehow managed to miss completely the `fold` module – apologies

---

<div class="post-metadata">

**Author:** ![marijn](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/marijn/32/136_2.png) [@marijn](https://discuss.codemirror.net/u/marijn)\
**Post date:** [March 29, 2022, 7:42am UTC](https://discuss.codemirror.net/t/folding-functions/4189/3 "2022-03-29T07:42:27Z")

</div>

Right, you can fold with [`foldEffect`](https://codemirror.net/6/docs/ref/#fold.foldEffect), and find foldable ranges with [`foldable`](https://codemirror.net/6/docs/ref/#language.foldable) from the language package.

---

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 29, 2022, 7:45am UTC](https://discuss.codemirror.net/t/folding-functions/4189/4 "2022-03-29T07:45:55Z")

</div>

Yeah. Sorry for my total ineptitude. I am very new to CodeMirror 6 and I am clumsy at best.

I am actually trying to use foldAll which is part of the API. But… I am having a timing problem.

I need to set the value for my editor. Once the code is viewed, I want it to be _totally_ folded.  
So, I am doing this:

```auto
  set value (v) {
    const state = this.view.state

    this.view.dispatch({
      changes: { from: 0, to: state.doc.length, insert: v || '' }
    })

   foldAll(this.view)
  }

```

However, this only folds the first portion of the document (which is quite long).  
In order to get it all folded, I have to do this:

```auto
  set value (v) {
    const state = this.view.state

    this.view.dispatch({
      changes: { from: 0, to: state.doc.length, insert: v || '' }
    })

    setTimeout(() => {
      foldAll(this.view)
    }, 5000)
  }

```

Which is obviously NOT a solution – it’s only to show that it’s a timing issue.  
I assumed that the changes dispatched would be executed in order, in a somewhat sync fashion. So:

1. 

Is this a problem with CodeMirror? OR

1. 

How do I apply the folding to the whole document without a timeout?

Thank you!

---

<div class="post-metadata">

**Author:** ![marijn](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/marijn/32/136_2.png) [@marijn](https://discuss.codemirror.net/u/marijn)\
**Post date:** [March 29, 2022, 8:01am UTC](https://discuss.codemirror.net/t/folding-functions/4189/5 "2022-03-29T08:01:20Z")

</div>

What you’re seeing is the parsing happening in a background process, which hasn’t finished yet. Folding is based on the parse tree. You could either synchronously force a full parse with [`ensureSyntaxTree`](https://codemirror.net/6/docs/ref/#language.ensureSyntaxTree), or wait for updates until [`syntaxParserRunning`](https://codemirror.net/6/docs/ref/#language.syntaxParserRunning) returns false.

---

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 29, 2022, 8:03am UTC](https://discuss.codemirror.net/t/folding-functions/4189/6 "2022-03-29T08:03:17Z")

</div>

Thank you Marijn. You must be the most helpful developer on the planet!

---

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 29, 2022, 8:09am UTC](https://discuss.codemirror.net/t/folding-functions/4189/7 "2022-03-29T08:09:10Z")

</div>

> [@marijn](#):
>
> ensureSyntaxTree

I am sorry, I don’t mean to be the guy who wants to be spoon-fed code, and I realise you are busy. But…  
How do I use ensureSyntaxTree?

---

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 29, 2022, 9:20am UTC](https://discuss.codemirror.net/t/folding-functions/4189/8 "2022-03-29T09:20:36Z")

</div>

I mean, my aim would be to set the value and then run `foldAll()` once the tree is fully parsed: From `ensureSyntaxTree()`, I can’t figure out how to run something once the tree is done: the call doesn’t take a callback and doesn’t seem to return a promise?

---

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 29, 2022, 9:51am UTC](https://discuss.codemirror.net/t/folding-functions/4189/9 "2022-03-29T09:51:00Z")

</div>

Wait you wrote _synchronously_! Sorry again.  
So I tried this:

```auto
import { ensureSyntaxTree } from '@codemirror/language'

  set value (v) {
    const state = this.view.state

    this.view.dispatch({
      changes: { from: 0, to: state.doc.length, insert: v || '' }
    })

    ensureSyntaxTree(this.view.state, state.doc.length, 5000)
    foldAll(this.view)
  }

```

but no luck.

I am not sure listening to updates will work for me, since I need to trigger the folding only when I set the editor to a new value (for example when you navigate onto that particular page in an SPA).

(I tried to figure out how to go this route, and I realise that [UpdateListener](https://codemirror.net/6/docs/ref/#view.EditorView%5EupdateListener) is the key, but I haven’t managed to figure out how to actually use it).

---

<div class="post-metadata">

**Author:** ![marijn](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/marijn/32/136_2.png) [@marijn](https://discuss.codemirror.net/u/marijn)\
**Post date:** [March 29, 2022, 11:21am UTC](https://discuss.codemirror.net/t/folding-functions/4189/10 "2022-03-29T11:21:05Z")

</div>

Oh, right, `ensureSyntaxTree` won’t actually change the editor state until the next editor update (since it’s immutable), so that doesn’t work straightforwardly.

Yeah, the idea would be to have an update listener that somehow recognizes the ‘right after load, didn’t fold yet, but syntax parser no longer running’ situation, and does the folding (and then sets the ‘after load’ flag to false).

---

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 29, 2022, 10:51pm UTC](https://discuss.codemirror.net/t/folding-functions/4189/11 "2022-03-29T22:51:42Z")

</div>

I am afraid that didn’t work either.  
My code is very straightforward:

```auto

  set value (v) {
    const state = this.view.state

    this.view.dispatch({
      changes: { from: 0, to: state.doc.length, insert: v || '' }
    })

    // This will tell us if the value was just set
    this._valueJustSet = true
  }
...
        this.view = new EditorView({
          state: EditorState.create({
            extensions: [
              ...
              EditorView.updateListener.of(update => this._maybeFoldAll(update))
...
  _maybeFoldAll (update) {
    console.log(`_maybeFoldAll: docChanged: ${update.docChanged}, flags: ${update.flags}, _valueJustSet: ${!!this._valueJustSet}, syntaxTreeAvailable: ${!!syntaxTreeAvailable(this.view.state)}, syntaxParserRunning: ${!!syntaxParserRunning(this.view)}`)
    if (!this._valueJustSet) return
    if (syntaxParserRunning(this.view)) return
    // if (!syntaxTreeAvailable(this.view.state) || ) return
    console.log('Folding!')
    this._valueJustSet = false
    foldAll(this.view)
  }

```

The result is not what was hoped:

```auto
Value just set!
co-codemirror.js:150 _maybeFoldAll: docChanged: false, flags: 14, _valueJustSet: true, syntaxTreeAvailable: false, syntaxParserRunning: true
co-codemirror.js:150 _maybeFoldAll: docChanged: false, flags: 0, _valueJustSet: true, syntaxTreeAvailable: false, syntaxParserRunning: true
co-codemirror.js:150 _maybeFoldAll: docChanged: false, flags: 0, _valueJustSet: true, syntaxTreeAvailable: false, syntaxParserRunning: false
co-codemirror.js:154 Folding!
co-codemirror.js:150 _maybeFoldAll: docChanged: false, flags: 6, _valueJustSet: false, syntaxTreeAvailable: false, syntaxParserRunning: false
4co-codemirror.js:150 _maybeFoldAll: docChanged: false, flags: 4, _valueJustSet: false, syntaxTreeAvailable: false, syntaxParserRunning: false
co-codemirror.js:150 _maybeFoldAll: docChanged: false, flags: 4, _valueJustSet: false, syntaxTreeAvailable: false, syntaxParserRunning: true
co-codemirror.js:150 _maybeFoldAll: docChanged: false, flags: 0, _valueJustSet: false, syntaxTreeAvailable: false, syntaxParserRunning: false
co-codemirror.js:150 _maybeFoldAll: docChanged: false, flags: 0, _valueJustSet: false, syntaxTreeAvailable: true, syntaxParserRunning: false
3co-codemirror.js:150 _maybeFoldAll: docChanged: false, flags: 4, _valueJustSet: false, syntaxTreeAvailable: true, syntaxParserRunning: false

```

Interestingly, only about three quarters of the file was folded. As you can see, the parser stopped running for a while, and then it restarted. I read in the documentation that the parser can, and _will_, do that if it’s taking too much time.

I looked everywhere for hints – I even checked if the flags might mean something (although they were just Focus, Height, Viewport, Geometry).

Is there anything, at all, that will say “parsing is done”?

---

<div class="post-metadata">

**Author:** ![marijn](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/marijn/32/136_2.png) [@marijn](https://discuss.codemirror.net/u/marijn)\
**Post date:** [March 30, 2022, 7:13am UTC](https://discuss.codemirror.net/t/folding-functions/4189/12 "2022-03-30T07:13:59Z")

</div>

Right, if the document is big enough the parser will just stop doing work below the viewport. Lazy parsing may make `foldAll` fundamentally unreliable.

@codemirror/language 0.19.9 fixes an issue so that can do `view.dispatch({})` after `ensureSyntaxTree` to flush the new parsing work to the view, making `foldAll` work, which might address your use case here, though it’s still all somewhat dodgy.

---

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 30, 2022, 2:26pm UTC](https://discuss.codemirror.net/t/folding-functions/4189/13 "2022-03-30T14:26:02Z")

</div>

Ah, so this should work now?

```auto
set value (v) {
    const state = this.view.state

    this.view.dispatch({
      changes: { from: 0, to: state.doc.length, insert: v || '' }
    })

    ensureSyntaxTree(this.view.state, state.doc.length, 5000)
    foldAll(this.view)
  }

```

…?

---

<div class="post-metadata">

**Author:** ![marijn](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/marijn/32/136_2.png) [@marijn](https://discuss.codemirror.net/u/marijn)\
**Post date:** [March 30, 2022, 2:50pm UTC](https://discuss.codemirror.net/t/folding-functions/4189/14 "2022-03-30T14:50:30Z")

</div>

No. Try reading my response a bit more closely.

---

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 31, 2022, 10:29am UTC](https://discuss.codemirror.net/t/folding-functions/4189/15 "2022-03-31T10:29:17Z")

</div>

> [@marijn](#):
>
> view.dispatch({})

Oh, you mean _actually_ `view.dispatch({})` with the empty object as the argument?

---

<div class="post-metadata">

**Author:** ![marijn](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/marijn/32/136_2.png) [@marijn](https://discuss.codemirror.net/u/marijn)\
**Post date:** [March 31, 2022, 11:06am UTC](https://discuss.codemirror.net/t/folding-functions/4189/16 "2022-03-31T11:06:00Z")

</div>

Yes, that’ll create an empty transaction, allowing the state to move forward to the new parse tree.

---

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 31, 2022, 12:32pm UTC](https://discuss.codemirror.net/t/folding-functions/4189/17 "2022-03-31T12:32:32Z")

</div>

Thanks for that. I read your answer a little _too_ closely I think! I thought that empty object meant “put the transaction here” – but I was obviously reading too much into it.

_(Unrelated, but I will avoid opening a new ticket about it) Did you know that [https://replit.com/](https://replit.com/) uses CodeMirror now? CodeMirror 6 is INCREDIBLE – and if you open two tabs, they will update in real time. Impressive stuff._

---

<div class="post-metadata">

**Author:** ![marijn](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/marijn/32/136_2.png) [@marijn](https://discuss.codemirror.net/u/marijn)\
**Post date:** [March 31, 2022, 12:48pm UTC](https://discuss.codemirror.net/t/folding-functions/4189/18 "2022-03-31T12:48:47Z")

</div>

> [@mercmobily](#):
>
> Did you know that [https://replit.com/](https://replit.com/) uses CodeMirror now?

Yes! They did some [blog posts](https://blog.replit.com/codemirror) about it.

---

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 31, 2022, 12:49pm UTC](https://discuss.codemirror.net/t/folding-functions/4189/19 "2022-03-31T12:49:25Z")

</div>

I think this is absolutely huge. It’s a really big project, and they are using the cooperative editing – and it _works_. It feels like Google Docs. It’s insane.

---

<div class="post-metadata">

**Author:** ![mercmobily](https://discuss.codemirror.net/user_avatar/discuss.codemirror.net/mercmobily/32/1038_2.png) [@mercmobily](https://discuss.codemirror.net/u/mercmobily)\
**Post date:** [March 31, 2022, 12:57pm UTC](https://discuss.codemirror.net/t/folding-functions/4189/20 "2022-03-31T12:57:30Z")

</div>

> [@marijn](#):
>
> @codemirror/language 0.19.9 fixes an issue so that can do `view.dispatch({})` after `ensureSyntaxTree` to flush the new parsing work to the view, making `foldAll` work, which might address your use case here, though it’s still all somewhat dodgy.

Just letting you know that I can finally _reliably_ open the file with everything folded for the first time.  
Thanks for your help.  
I think you will see interest in Codemirror _exploding_ in the coming weeks. I followed your blog as you were writing it, I read about your “tearing my hair out” moments (yes, I can relate), and I am just so impressed it’s come along so immensely nicely.

[Next page](https://discuss.codemirror.net/t/folding-functions/4189.md?page=2)
