I’ve been using Neovim full time for the past few months. I set up a nice little config, with everything that I need: LSP, scratch files, Database explorer… but there’s one thing that I couldn’t resolve in a nice way (or could I ? 😏): folds.
Me irl
Yes, folds. The ability to fold a code that you don't want to see to reduce bloat when you’re working on something specific. Like you would see in any IDE
IntelliJ: before folding
IntelliJ: after folding
Neovim (as Vim) has multiple possibilities when it comes to handling folding. You can use different strategies like manual folding, treesitter folding, indent folding, with a wide array of options like depth etc.
Nice, you would say. Yes at first glance, but also this is quite complicated and there’s something that bothers me with every existing strategy: folds are closed by default.
This means that if you enable indent folds, every single buffer you’ll open that has indentation going on will be opened with folds closed. So you can’t read the file before opening them with zR
which I find extremely annoying.
I read some articles proposing some workaround using autocommands. This would have been nice if it worked properly, and maybe I did something wrong, but I couldn’t have it working as intended and kept having some strange behaviors.
No it ain't 🫠
Since I want all folds to be opened by default, I thought I’d be better of creating the folds I need on the go. Although, this is kind of a hassle, you have to select the part your want to fold and then zf
.
I ain’t no Primeagen (for now at least) so I’m not fast enough with my fingers to select the part I want fast enough.
Here is my solution to this issue:
function toggle_fold(char)
local fold_command = ''
if vim.fn.foldlevel('.') > 0 then
fold_command = 'za'
else
fold_command = 'va' .. char .. 'zf'
end
vim.cmd('normal! ' .. fold_command)
end
vim.keymap.set('n', 'z}', ':lua toggle_fold("}")<CR>', { noremap = true, silent = true })
vim.keymap.set('n', 'z{', ':lua toggle_fold("{")<CR>', { noremap = true, silent = true })
vim.keymap.set('n', 'z)', ':lua toggle_fold(")")<CR>', { noremap = true, silent = true })
vim.keymap.set('n', 'z(', ':lua toggle_fold("(")<CR>', { noremap = true, silent = true })
vim.keymap.set('n', 'z]', ':lua toggle_fold("]")<CR>', { noremap = true, silent = true })
vim.keymap.set('n', 'z[', ':lua toggle_fold("[")<CR>', { noremap = true, silent = true })
vim.keymap.set('n', 'zT', ':lua toggle_fold("t")<CR>', { noremap = true, silent = true })
Basically, we check if a fold exists where the cursor is, if it does, it toggles it. If it doesn't, it selects the range between the two characters passed as an argument and creates the fold.
Consequently, the remaps let you easily run this function with any character.
Suppose you have some React Native (Expo) code going on (cursor position is where the orange highlight is):