How can I automatically fold all functions in a file with vim?
Asked Answered
A

7

77

At first, I use the set foldmethod=marker, and move the cursor to the { of one function, use the zf% to fold current function. But there are a lot of functions in this file. How can I fold all functions in this file? And I don't want to fold {} in the functions.

Abrogate answered 30/12, 2010 at 2:33 Comment(2)
FYI vim distributions usually come with embedded help. If you type :help fold you can see all the fold related stuff.Alchemize
You'll have to add what language you're interested in (not all languages have {} for a start!); folding in Vim is a topic of its own.Wellman
A
150

If you :set foldmethod=syntax the folds will be specified from the syntax definitions. If you prefer you can :set foldmethod=indent to have the indentation define the folds.

You can close all folds with zM. If you have nested folds and you want to fold level by level, use zm. To open folds use zR (all) and zr (level by level).

Alchemize answered 30/12, 2010 at 2:41 Comment(8)
I think you misunderstand my meaning. At first, I need set up fold for each function. I just want to know how to set up fold for all functions in the first one time.Abrogate
@Yongwei: ok, I think I get it now. Is this what you wanted?Alchemize
It says "No fold found"Galligan
For those who wonder how to remember zm and zr, the official documentation says it is "More" and "Reduce". (Still not quite intuitive, but as most things in vim world, it is what it is.)Medrano
Just for info, in their documentation, they have mentioned that all the folding commands starts with 'z' . It looks like folded paper if looked from sides.Irrawaddy
When I try zR I get put in replace mode, and zM says no fold found (even though I can fold individually with just z). The only line in my rc modifying z is nnoremap z za Any clues?Elizaelizabet
As a mnemonic, I actually prefer referring to M as Mask and R as Reveal as I find it more intuitive than more/reduce.Airy
How to make it working for all files? I added set foldmethod=indent into .vimrc but it works in files where I manually set command :set foldmethod=indentPat
S
11

If each function has its opening brace on the first column you could do:

:%g/^{/normal! zf%

Maybe it is more clear this way:

:%g /^{/ normal! zf%

the g command selects lines according to the following pattern, and executes an ex command (here normal! to play normal mode keystrokes).

See :help :g and :help :normal

Sastruga answered 30/12, 2010 at 10:16 Comment(1)
I use this - thanks however how can you avoid it from folding across functions? it seems it is not only functionsLass
D
10

I came across this when I was searching for a similar thing. You would have obviously figured this out by now, but for the benefit of other people i'll answer it anyway.

You need to put in the following lines in your .vimrc:

set foldmethod=syntax
set foldnestmax=1
Deckhouse answered 5/2, 2012 at 0:30 Comment(0)
F
10

I was trying to do the same and ended up simply doing:

setlocal foldmethod=marker
setlocal foldmarker={,}

It uses the marker fold method and changes the marker to a single curly brace (by default the marker is {{{).

Follow answered 13/9, 2016 at 20:49 Comment(1)
I loved that, quite handy! But I should split lines which closes one brace and opens another (like "} else {")Inbeing
W
8
set foldlevel=0

will fold everything from the start, what is ment to be folded. Depending on the language, and your fold function, the contents of fold will vary.

Wellman answered 5/2, 2012 at 3:11 Comment(1)
zM do the same thing.Bonin
A
4

Try :%g/\(function\_.\{-}\)\@<={/ normal! f{zf%

Explain bit by bit:

:%g - search globaly in a whole file

/\(function\_.\{-}\)\@<={/ - pattern to find first '{' after any 'function' and put cursor on begin of string with that '{'

normal! f{zf% - execute forward to '{' f{ and make fold with move '%' zf% on that string

Alcmene answered 18/11, 2014 at 11:14 Comment(2)
could not get your comand to work - perhaps show example functionsLass
How can I include the next (empty) line after the function?Sibie
G
0

DISCLAIMER: I'm fairly new to vim/nvim and still exploring the whole functionality and plugin scene of the nvim ecosystem and I'm therefore far from an expert. As this thread here is also almost ancient and the given answers here didn't really solve my needs and maybe others might have similar needs, I post my approaches I have come up with.


In order to achieve an automatic method level folding of C-like slangs like Java, JavaScript, C# and so forth with nvim-lsp configured I had to use this in my nvim.lua file:

vim.o.foldmethod = 'indent'
vim.o.foldlevel = 2
vim.o.foldlevelstart = 1
vim.o.foldnestmax = 2

This setting will automatically fold the body of all method or functions of standard classes, but not of sub-blocks within those functions/methods exactly as I prefer it. These settings though may fail on inner and/or nested classes.

While I am not a big fan of automatic folding, I am currently experimenting with a manual way to get the job done so that I have control over when folding occurs.

In order to achieve this, I first added further keybindings for the move context to the treesitter configuration:

-- added custom keybindings to treesitter
vim.defer_fn(function()
  require('nvim-treesitter.configs').setup {
    ...
    textobjects = {
      ...
      move = {
        ...
        goto_next_start = {
          ...
          [']b'] = '@function.inner',
        },
        goto_next_end = {
          ...
          [']B'] = '@function.inner',
        },
        goto_previous_start = {
          ...
          ['[b'] = '@function.inner',
        },
        goto_previous_end = {
          ...
          ['[B'] = '@function.inner',
        },
      }
    }
  }
}

This basically allows me to jump to the inside of methods with ]b or upwards to the previous method via [b.

Next, I created a keybinding for creating a folding from the inside, basically folding everything between [ and ] or { and }. This keybind is not limited to the functions or methods but can also fold blocks within those, depending on where the cursor is located at:

-- add a custom menu option to WhichKey 
require('which-key').register {
  ...
  ['<leader>f'] = { name = '[F]old', _ = 'which_key_ignore' },
}

vim.o.foldmethod = 'manual'
vim.keymap.set('n', '<leader>fb', 'zfiB', { desc = 'Fold [b]lock' })
vim.keymap.set('n', '<leader>fB', 'zo', { desc = 'Unfold [B]lock' })

In combination with the above treesitter keybind it is now just a matter of calling ]b to jump inside the next function/method and folding the method via <leader>fb (or whatever keybind is preferred here).

As I haven't figured out how to write a lua function that iterates through all function/method treesitter/LSP objects and applies the required steps on a custom keybind, I currently created a macro that looks like that when viewed via :reg:

:reg @f
Type Name Content
  c  "f   ]b fbj

where the same keybinds as described above were used and a final move down after the folding as otherwise the macro would attempt to fold the same function all over again.

When calling the macro now with @f and then with 1000@@ for a file with plenty of methods and 2.6k lines the script takes a bit of time to fold all methods but it gets the job done. The macro will only execute as long as it finds further methods to jump to so overshooting the macro repetition isn't a big deal here IMO. The macro also only operates downwards. So it allows you basically to fold all methods from the current cursor location on and leaves the method above untouched.

Adding the following keybinds therefore to the init.lua file allows me to fold all of the methods at and below the cursor position and unfold them again:

vim.keymap.set('n', '<leader>fa', "@f1000@@", { desc = 'Fold all' })
vim.keymap.set('n', '<leader>fA', "zR", { desc = 'Unfold [A]ll' })

This method should also work for nested classes as it basically uses the LSP tree to navigate through the file.

A word of warning though, if you have plugins like Tagbar or Vista installed, folding functions may drive these plugins nuts and block your nvim from operating smoothly (for some time). I therefore configured Vista in the lazy plugin manager to load lazily. Even with disabled Tagbar/Vista nvim takes a noticeable amount of time before it can be used as usual. Not sure what's making it almost freeze for like 15-20 seconds at worst time before it suddenly catches up and behaves normal again.

While this setup for sure isn't perfect, at last it gets the job done while giving me the control to fold stuff on my terms.

Giorgio answered 29/1 at 5:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.