# Treesitter Go error folding
I mostly use neovim for writing code. Especially Go code.
Two years ago I was presented with Goland which seemed a little bit overwhelming to me.
But there was a feature that looked quite interesting.
Goland could fold error handling blocks with some sense of context.
I've recently tried treesitter and it turned out that implementing such feature in neovim is trivial:
1-- ftplugin/go.lua
2local q = vim.treesitter.query.parse("go", [[
3(if_statement
4 condition: (binary_expression
5 left: (identifier) @val (#eq? @val "err")
6 operator: ("!=")
7 right: (nil))
8 consequence: (block (return_statement (expression_list [
9 (identifier)
10 (call_expression
11 function: (selector_expression
12 field: (field_identifier))
13 arguments: (_))] @ret .))
14 ) @block)
15]])
16
17local bufnr = vim.api.nvim_get_current_buf()
18local ns = vim.api.nvim_create_namespace("go-err")
19
20vim.api.nvim_create_autocmd("CursorMoved", {
21 group = vim.api.nvim_create_augroup("CollapseErrors", {clear = true}),
22 buffer = bufnr,
23 callback = function()
24 local row, _ = unpack(vim.api.nvim_win_get_cursor(0))
25 local height = vim.fn.getwininfo(vim.api.nvim_get_current_win())[1].height
26 local root = vim.treesitter.get_parser(bufnr, "go"):parse()[1]:root()
27
28 vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1)
29
30 for _, matches in q:iter_matches(root, bufnr) do
31 local captures = {}
32 for id, nodes in pairs(matches) do
33 captures[q.captures[id]] = nodes[1]
34 end
35
36 local start_row, start_col, end_row = captures["block"]:range()
37 if start_row > row + height + height/2 then break end
38 if row-1 >= start_row and row-1 <= end_row then goto continue end
39
40 vim.api.nvim_buf_set_extmark(bufnr, ns, start_row, start_col+1, {
41 virt_text_pos = "inline",
42 virt_text = {{string.format(" -> %s", vim.treesitter.get_node_text(captures["ret"], bufnr)), "Comment"}},
43 })
44
45 vim.api.nvim_buf_set_extmark(bufnr, ns, start_row+1, 0, {
46 end_row = end_row,
47 conceal_lines = "",
48 })
49
50 ::continue::
51 end
52 end,
53})
Don't forget to vim.o.conceallevel >= 2.