Folding dart/flutter code with treesitter in neovim
Using :InspectTree
I see that the nodes I want folded are selector
, named_argument
and list_literal
.
In the code below, I bind the function that folds to <C-f>
or Ctrl + f.
local fold_named_arg_func = function()
local allowed_types = {
["selector"] = true,
["named_argument"] = true,
["list_literal"] = true
}
local ts_utils = require('nvim-treesitter.ts_utils')
local winid = vim.fn.bufwinid(1)
local nuc = ts_utils.get_node_at_cursor(winid)
local cn = nuc
while cn ~= nil and allowed_types[cn:type()] == nil
do
cn = cn:parent()
end
local start_row
local end_row
if cn ~=nil then
start_row, _, end_row, _ = cn:range()
vim.cmd(start_row + 1 .. "," .. end_row + 1 .. "fold")
end
end
vim.keymap.set('n', '<C-f>', function()
local fold_level = vim.fn.foldlevel('.')
local fold_closed = vim.fn.foldclosed('.')
if fold_level > 0 then
if fold_closed == -1 then
fold_named_arg_func()
else
vim.cmd("foldopen")
end
else
fold_named_arg_func()
end
end)
In conjunction to the above, I also modded how folds appear in neovim because the default implementation didn't preserve code indendation.
vim.opt.fillchars = { eob = "-", fold = " " }
vim.opt.foldtext = 'v:lua.MyFoldText()'
function MyFoldText()
local start_line = vim.fn.getline(vim.v.foldstart)
local end_line = vim.fn.getline(vim.v.foldend)
end_line = end_line:gsub("^%s+", "")
return start_line .. " ... " .. end_line
end
vim.keymap.set("v", "<C-f>", ":fold<CR>", { desc = "fold" })
Alternatively (what I do now), is to fold all nodes. If the node isn't multiline, fold its parent instead.
local fold_node = function ()
local ts_utils = require('nvim-treesitter.ts_utils')
local cn = ts_utils.get_node_at_cursor(0)
while cn ~= nil
do
local node_start_row, _, node_end_row, _ = cn:range()
if node_end_row == node_start_row then
cn = cn:parent()
else
vim.cmd(node_start_row + 1 .. "," .. node_end_row + 1 .. "fold")
break
end
end
end
vim.keymap.set('n', '<C-f>', function()
local fold_level = vim.fn.foldlevel('.')
local fold_closed = vim.fn.foldclosed('.')
if fold_level > 0 then
if fold_closed == -1 then
-- fold_named_arg_func()
fold_node()
else
vim.cmd("foldopen")
end
else
-- fold_named_arg_func()
fold_node()
end
end)