1
- local ts_utils = require ' nvim-treesitter.ts_utils'
2
-
3
1
local M = {}
4
2
5
3
local GUARD_MAX = 1000
@@ -31,28 +29,112 @@ local node_types = {
31
29
}
32
30
33
31
for _ , type in ipairs (node_types ) do
32
+ --- @type fun ( node : TSNode ): boolean
34
33
M [' is_' .. type ] = function (node )
35
- if not node then return false end
34
+ if not node then
35
+ return false
36
+ end
36
37
return node and node :type () == type
37
38
end
38
39
end
39
40
41
+ -- Get previous node with same parent
42
+ --- @param node TSNode
43
+ --- @param allow_switch_parents ? boolean allow switching parents if first node
44
+ --- @param allow_previous_parent ? boolean allow previous parent if first node and previous parent without children
45
+ --- @return TSNode ?
46
+ local function get_previous_node (node , allow_switch_parents , allow_previous_parent )
47
+ local destination_node --- @type TSNode ?
48
+ local parent = node :parent ()
49
+ if not parent then
50
+ return
51
+ end
52
+
53
+ local found_pos = 0
54
+ for i = 0 , parent :named_child_count () - 1 , 1 do
55
+ if parent :named_child (i ) == node then
56
+ found_pos = i
57
+ break
58
+ end
59
+ end
60
+ if 0 < found_pos then
61
+ destination_node = parent :named_child (found_pos - 1 )
62
+ elseif allow_switch_parents then
63
+ local previous_node = get_previous_node (node :parent ())
64
+ if previous_node and previous_node :named_child_count () > 0 then
65
+ destination_node = previous_node :named_child (previous_node :named_child_count () - 1 )
66
+ elseif previous_node and allow_previous_parent then
67
+ destination_node = previous_node
68
+ end
69
+ end
70
+ return destination_node
71
+ end
72
+
73
+ --- @param node TSNode
74
+ --- @return TSNode ?
75
+ local function get_root_for_node (node )
76
+ --- @type TSNode ?
77
+ local parent = node
78
+ local result = node
79
+
80
+ while parent ~= nil do
81
+ result = parent
82
+ parent = result :parent ()
83
+ end
84
+
85
+ return result
86
+ end
87
+
88
+ --- @param row number
89
+ --- @param col number
90
+ --- @param root_lang_tree LanguageTree
91
+ --- @return TSNode ?
92
+ local function get_root_for_position (row , col , root_lang_tree )
93
+ local lang_tree = root_lang_tree :language_for_range { row , col , row , col }
94
+
95
+ for _ , tree in pairs (lang_tree :trees ()) do
96
+ local root = tree :root ()
97
+
98
+ if root and vim .treesitter .is_in_node_range (root , row , col ) then
99
+ return root
100
+ end
101
+ end
102
+
103
+ return nil
104
+ end
105
+
106
+ --- @param root_lang_tree LanguageTree
107
+ --- @return TSNode ?
108
+ local function get_node_at_cursor (root_lang_tree )
109
+ local cursor = vim .api .nvim_win_get_cursor (0 )
110
+ local cursor_range = { cursor [1 ] - 1 , cursor [2 ] }
111
+
112
+ --- @type TSNode ?
113
+ local root = get_root_for_position (cursor_range [1 ], cursor_range [2 ], root_lang_tree )
114
+
115
+ if not root then
116
+ return
117
+ end
118
+
119
+ return root :named_descendant_for_range (cursor_range [1 ], cursor_range [2 ], cursor_range [1 ], cursor_range [2 ])
120
+ end
121
+
40
122
--- Enter a parent-language's regexp node which contains the embedded
41
123
--- regexp grammar
42
- --- @param node TreesitterNode
43
- local function enter_js_re_node (node )
124
+ --- @param root_lang_tree LanguageTree
125
+ --- @param node TSNode
126
+ --- @return TSNode ?
127
+ local function enter_js_re_node (root_lang_tree , node )
44
128
-- cribbed from get_node_at_cursor impl
45
- local parsers = require ' nvim-treesitter.parsers'
46
- local root_lang_tree = parsers .get_parser (0 )
47
129
local row , col = vim .treesitter .get_node_range (node )
48
130
49
- local root = ts_utils . get_root_for_position (row , col + 1 --[[ hack that works for js]] , root_lang_tree )
131
+ local root = get_root_for_position (row , col + 1 --[[ hack that works for js]] , root_lang_tree )
50
132
51
133
if not root then
52
- root = ts_utils . get_root_for_node (node )
134
+ root = get_root_for_node (node )
53
135
54
136
if not root then
55
- return nil , ' no node immediately to the right of the regexp node '
137
+ return nil
56
138
end
57
139
end
58
140
62
144
--- Containers are regexp treesitter nodes which may contain leaf nodes like pattern_character.
63
145
--- An example container is anonymous_capturing_group.
64
146
--
65
- --- @param node TreesitterNode regexp treesitter node
147
+ --- @param node TSNode regexp treesitter node
66
148
--- @return boolean
67
- --
68
149
function M .is_container (node )
69
150
if node :child_count () == 0 then
70
151
return false
@@ -102,7 +183,8 @@ function M.is_punctuation(type)
102
183
end
103
184
104
185
-- Is this the document root (or close enough for our purposes)?
105
- --
186
+ --- @param node TSNode
187
+ --- @return boolean
106
188
function M .is_document (node )
107
189
if node == nil then return true else
108
190
local type = node :type ()
@@ -120,6 +202,8 @@ function M.is_document(node)
120
202
end
121
203
end
122
204
205
+ --- @param node TSNode
206
+ --- @return unknown
123
207
function M .is_control_escape (node )
124
208
return require ' regexplainer.component' .is_control_escape {
125
209
type = node :type (),
150
234
--- @return any , string | nil
151
235
--
152
236
function M .get_regexp_pattern_at_cursor ()
153
- local cursor_node = ts_utils .get_node_at_cursor ()
237
+ local root_lang_tree = vim .treesitter .get_parser (0 , vim .treesitter .language .get_lang (vim .bo [0 ].ft ))
238
+ local cursor_node = get_node_at_cursor (root_lang_tree )
154
239
local cursor_node_type = cursor_node and cursor_node :type ()
155
240
if not cursor_node or cursor_node_type == ' program' then
156
241
return
@@ -180,7 +265,10 @@ function M.get_regexp_pattern_at_cursor()
180
265
if type == ' pattern' then
181
266
node = next
182
267
elseif type == ' regex_pattern' or type == ' regex' then
183
- node = enter_js_re_node (next )
268
+ node = enter_js_re_node (root_lang_tree , next )
269
+ if not node then
270
+ return nil , ' no node immediately to the right of the regexp node'
271
+ end
184
272
end
185
273
end
186
274
end
@@ -196,9 +284,9 @@ function M.get_regexp_pattern_at_cursor()
196
284
end
197
285
198
286
local _node = node
199
- node = ts_utils . get_previous_node (node , true , true )
287
+ node = get_previous_node (node , true , true )
200
288
if not node then
201
- node = ts_utils . get_root_for_node (_node )
289
+ node = get_root_for_node (_node )
202
290
if not node then
203
291
return nil , ' no upwards node'
204
292
end
0 commit comments