Search code examples
neovimfoldingtreesitter

Treesitter and syntax folding


not sure if this is well known, but I spent a few hours searching documentation, stack overflow and reddit and never found a clear explanation. So I am posting this here, in case some one else faces the same issue.

Situation: I use both vim and neovim and the configuration is largely the same except that I use tree sitter in neovim for highlighting. I program mainly in C.

Problem: I was playing around with code folding and noticed that syntax folding worked in vim, but not in neovim. I could not find a clear description anywhere. Maybe I did not use the right search terms. But every question about syntax folding was answered with adding some lines in ftplugin or some other file. None of the solutions worked for me.

I document my solution below as an answer and hope that someone else has a more elegant solution.


Solution

  • Analysis: Turns out, the problem is hidden in these sentences in the tree sitter neovim documentation

    -- Setting this to true will run `:h syntax` and tree-sitter at the same time. 
    -- Set this to `true` if you depend on 'syntax' being enabled (like for indentation). 
    -- Using this option may slow down your editor, and you may see some duplicate highlights. 
    -- Instead of true it can also be a list of languages     
    additional_vim_regex_highlighting = false,
    

    This means, even if you have configured syntax code folding correctly, that is,

    filetype plugin indent on 
    syntax on
    

    and do all the weird other stuff suggested by various stack overflow answers that come up when you google "syntax folding for c not working vim" or similar, once you enable treesitter, turn on highlighting and set additional_vim_regex_highlighting = false, the syntax on part is turned off. Now code folding doesn't work.

    What bothers me here, is that it is not readily clear from the name of the option (which only implies disabling regex highlighting) that it affects folding as well!

    Tricky solution number 1: Okay, maybe the simple solution is to set the additional regex highlighting true. But this is inefficient, and pretty sure slows everything down. So what to do?

    Tricky solution number 2: We can just use treesitter folding instead. Here we go, from the documentation

    set foldmethod=expr
    set foldexpr=nvim_treesitter#foldexpr()
    set nofoldenable                     " Disable folding at startup.
    

    problem solved, right? Wrong!

    This will only enable folding for languages supported by treesitter. What does supported mean for treesitter? Again from the documentation:

    For nvim-treesitter to support a specific feature for a specific language requires both a parser for that language and an appropriate language-specific query file for that feature.

    This means, you will have to install every possible parser and enable it in tree sitter settings to enable syntax folding for every language that vim supports by default.

    Acceptable solution number 3: So what we want is, use treesitter folding for those languages for whom treesitter is enabled and use vims syntax folding for every other language. This can be achieved by

    autocmd Filetype c,cpp,rust,python setlocal foldmethod=expr
    autocmd Filetype c,cpp,rust,python setlocal foldexpr=nvim_treesitter#foldexpr()
    
    filetype plugin indent on 
    syntax on
    
    lua <<EOF
    require'nvim-treesitter.configs'.setup {
      highlight = {
        enable = true,
        additional_vim_regex_highlighting = false,
      },
    }
    

    and installing parsers for c, cpp, rust and python. This solution is working for me and is acceptable i guess. If anyone has a more elegant solution, feel free to post it as another answer.