Search code examples
neovimcode-foldingtreesitter

Neovim: fold code with `foldmethod=syntax` or `foldmethod=expr` depending on Tree-sitter


I've just fresh-installed LazyVim and I'm having troubles configuring code folding to my liking.

  • For the languages for which I have no nvim-treesitter parser installed I would like to use :set foldmethod=syntax (presumably Neovim already knows how to parse these languages at a basic level).

  • On the other hand, for the languages for which I have a nvim-treesitter parser installed and configured I would like to use :set foldmethod=expr foldexpr=nvim_treesitter#foldexpr().

The reason for this is that in both circumstances if I use the opposite configuration then code folding will not work at all.

My idea is to default to :set foldmethod=syntax and have an autocommand switch it to expr when opening a buffer with nvim-treesitter support, however I have no idea how to achieve that (I don't know what event to listen to and how to detect whether a nvim-treesitter parser gets loaded for the current buffer). Maybe there is some other way to achieve this, by directly configuring nvim-treesitter to do the switching; I don't know.

Does anybody have a solution?


Solution

  • In your LazyVim config, under lua/config/autocmds.lua, you can add:

    vim.api.nvim_create_autocmd({ "FileType" }, {
      callback = function()
        if require("nvim-treesitter.parsers").has_parser() then
          vim.opt.foldmethod = "expr"
          vim.opt.foldexpr = "nvim_treesitter#foldexpr()"
        else
          vim.opt.foldmethod = "syntax"
        end
      end,
    })
    

    This follows the general format recommended in LazyVim's tips section.

    Note that, as recommended in the nvim-treesitter README, you may also want to set this elsewhere:

    set nofoldenable   " Disable folding at startup.
    

    ... though I found it unnecessary, as files open without folds anyway in my LazyVim config.

    Note that this won't trigger for new, unnamed buffers. If you wanted to handle that explicitly you could trying handling the BufEnter event instead of FileType, or have a look at other event types via :help events inside Neovim.