When I use neovim treesitter incremental selection, it randomly crashes, but I cannot stable reproduce it. And I found some issues and complaints about this issue, but no solution. So I decide to write a blog post to record this issue and the solution.
paste this https://github.com/xiantang/nvim-conf/blob/7c0d6cbf6d9fd7b6a8960de887db1109332419bf/lua/plugins/treesitter.lua#L62-L132 into your neovim configuration file.
sometime when I use v to expand the selection, it crashes, and it’s a Segmentation fault, and I have the report:
But I have no idea how to fix it in neovim source code. After many times I updated the neovim and treesitter, the issue still exists. So I decide to disable the incremental selection feature. And implement a new incremental selection feature by myself.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
local ts_utils = require("nvim-treesitter.ts_utils")
local node_list = {}
local current_index = nil
function start_select()
node_list = {}
current_index = nil
current_index = 1
vim.cmd("normal! v")
end
function find_expand_node(node)
local start_row, start_col, end_row, end_col = node:range()
local parent = node:parent()
if parent == nil then
return nil
end
local parent_start_row, parent_start_col, parent_end_row, parent_end_col = parent:range()
if
start_row == parent_start_row
and start_col == parent_start_col
and end_row == parent_end_row
and end_col == parent_end_col
then
return find_expand_node(parent)
end
return parent
end
function select_parent_node()
if current_index == nil then
return
end
local node = node_list[current_index - 1]
local parent = nil
if node == nil then
parent = ts_utils.get_node_at_cursor()
else
parent = find_expand_node(node)
end
if not parent then
vim.cmd("normal! gv")
return
end
table.insert(node_list, parent)
current_index = current_index + 1
local start_row, start_col, end_row, end_col = parent:range()
vim.fn.setpos(".", { 0, start_row + 1, start_col + 1, 0 })
vim.cmd("normal! v")
vim.fn.setpos(".", { 0, end_row + 1, end_col, 0 })
end
function restore_last_selection()
if not current_index or current_index <= 1 then
return
end
current_index = current_index - 1
local node = node_list[current_index]
local start_row, start_col, end_row, end_col = node:range()
vim.fn.setpos(".", { 0, start_row + 1, start_col + 1, 0 })
vim.cmd("normal! v")
vim.fn.setpos(".", { 0, end_row + 1, end_col, 0 })
end
vim.api.nvim_set_keymap("n", "v", ":lua start_select()<CR>", { noremap = true, silent = true })
vim.api.nvim_set_keymap("v", "v", ":lua select_parent_node()<CR>", { noremap = true, silent = true })
vim.api.nvim_set_keymap("v", "<BS>", ":lua restore_last_selection()<CR>", { noremap = true, silent = true })
|
And it works well, and I can expand the selection by v and select the parent node by v and restore the last selection by <BS>.
if there have many people have the same issue, im willing to create a new tressitter plugin that let you config this altrenative incremental selection in treesitter configuration like as below: