Skip to content

Commit b0d5d8f

Browse files
committed
fix!: require tree-sitter-regexp 0.21 and nvim 0.9.5
1 parent 04c8749 commit b0d5d8f

File tree

5 files changed

+76
-107
lines changed

5 files changed

+76
-107
lines changed

lua/regexplainer.lua

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ local au = vim.api.nvim_create_autocmd
3939
local config_command_map = {
4040
show = { 'RegexplainerShow', 'Show Regexplainer' },
4141
hide = { 'RegexplainerHide', 'Hide Regexplainer' },
42-
toggle = { 'RegexplainerToggle', 'Toggle Regexplainer' },
43-
yank = { 'RegexplainerYank', 'Yank Regexplainer' },
42+
toggle = { 'RegexplainerToggle', 'Toggle Regexplainer' }, yank = { 'RegexplainerYank', 'Yank Regexplainer' },
4443
show_split = { 'RegexplainerShowSplit', 'Show Regexplainer in a split Window' },
4544
show_popup = { 'RegexplainerShowPopup', 'Show Regexplainer in a popup' },
4645
}
@@ -79,27 +78,23 @@ local local_config = extend('keep', default_config, {})
7978
---@param options? RegexplainerOptions overrides for this call
8079
---@return nil|number bufnr the bufnr of the regexplaination
8180
--
82-
local function show(options)
81+
local function show_for_real(options)
8382
options = extend('force', local_config, options or {})
84-
local node, error = tree.get_regexp_pattern_at_cursor()
83+
local node, scratchnr, error = tree.get_regexp_pattern_at_cursor()
8584

8685
if error and options.debug then
8786
utils.notify('Rexexplainer: ' .. error, 'debug')
88-
elseif node then
89-
---@type RegexplainerRenderer
90-
local renderer
87+
elseif node and scratchnr then
9188
---@type boolean, RegexplainerRenderer
92-
local can_render, _renderer = pcall(require, 'regexplainer.renderers.' .. options.mode)
89+
local can_render, renderer = pcall(require, 'regexplainer.renderers.' .. options.mode)
9390

94-
if can_render then
95-
renderer = _renderer
96-
else
91+
if not can_render then
9792
utils.notify(options.mode .. ' is not a valid renderer', 'warning')
9893
utils.notify(renderer, 'error')
9994
renderer = require 'regexplainer.renderers.narrative'
10095
end
10196

102-
local components = component.make_components(node, nil, node)
97+
local components = component.make_components(scratchnr, node, nil, node)
10398

10499
local buffer = Buffers.get_buffer(options)
105100

@@ -112,17 +107,17 @@ local function show(options)
112107
components,
113108
options,
114109
{
115-
full_regexp_text = get_node_text(node, 0),
110+
full_regexp_text = get_node_text(node, scratchnr),
116111
})
117-
return buffer.bufnr
112+
return scratchnr
118113
else
119114
Buffers.hide_all()
120115
end
121116
end
122117

123118
local disable_auto = false
124119

125-
local show_debounced_trailing, timer_trailing = defer.debounce_trailing(show, 5)
120+
local show_debounced_trailing, timer_trailing = defer.debounce_trailing(show_for_real, 5)
126121

127122
Buffers.register_timer(timer_trailing)
128123

@@ -132,9 +127,11 @@ local M = {}
132127
---@param options? RegexplainerOptions
133128
function M.show(options)
134129
disable_auto = true
135-
local bufnr = show(options)
130+
local scratchnr = show_for_real(options)
136131
disable_auto = false
137-
return bufnr
132+
if scratchnr then
133+
vim.api.nvim_buf_delete(scratchnr, { force = true })
134+
end
138135
end
139136

140137
--- Yank the explainer for the regexp under the cursor into a given register
@@ -144,11 +141,7 @@ function M.yank(options)
144141
if type(options) == 'string' then
145142
options = { register = options }
146143
end
147-
show(vim.tbl_deep_extend(
148-
'force',
149-
options,
150-
{ display = 'register' }
151-
))
144+
show_for_real(vim.tbl_deep_extend('force', options, { display = 'register' }))
152145
disable_auto = false
153146
end
154147

@@ -219,7 +212,7 @@ end
219212
function M.debug_components()
220213
---@type any
221214
local mode = 'debug'
222-
show({ auto = false, display = 'split', mode = mode })
215+
show_for_real({ auto = false, display = 'split', mode = mode })
223216
end
224217

225218
return M

lua/regexplainer/component/init.lua

Lines changed: 19 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,6 @@ function M.is_lookaround_assertion(component)
117117
return component.type:find('^lookaround_assertion') ~= nil
118118
end
119119

120-
---@param component RegexplainerComponent
121-
---@return boolean
122-
--
123-
function M.is_lookbehind_assertion(component)
124-
return component.type:find('^lookaround_assertion') ~= nil
125-
end
126-
127-
128120
-- Does a container component contain nothing by pattern_characters?
129121
---@param component RegexplainerComponent
130122
---@return boolean
@@ -201,13 +193,14 @@ end
201193
---@alias TreesitterNode any
202194

203195
--- Transform a treesitter node to a table of components which are easily rendered
196+
---@param bufnr number
204197
---@param node TSNode
205-
---@param parent? TSNode
198+
---@param parent? RegexplainerComponent
206199
---@param root_regex_node TSNode
207200
---@return RegexplainerComponent[]
208201
--
209-
function M.make_components(node, parent, root_regex_node)
210-
local text = get_node_text(node, 0)
202+
function M.make_components(bufnr, node, parent, root_regex_node)
203+
local text = get_node_text(node, bufnr)
211204
local cached = lookuptables[text]
212205
if cached then return cached end
213206

@@ -226,7 +219,7 @@ function M.make_components(node, parent, root_regex_node)
226219
for child in node:iter_children() do
227220
local type = child:type()
228221

229-
local child_text = get_node_text(child, 0)
222+
local child_text = get_node_text(child, bufnr)
230223

231224
local previous = components[#components]
232225

@@ -298,40 +291,18 @@ function M.make_components(node, parent, root_regex_node)
298291
-- see https://github.com/tree-sitter/tree-sitter-javascript/issues/214
299292
--
300293
elseif type == 'ERROR' then
301-
local error_text = get_node_text(child, 0)
294+
local error_text = get_node_text(child, bufnr)
302295
local row, e_start, _, e_end = child:range()
303296
local _, re_start = node:range()
304-
305-
-- TODO: until treesitter supports lookbehind, we can parse it ourselves
306-
-- This code, however, is not ready to use
307-
308-
local from_re_start_to_err_start = e_start - re_start + 1
309-
310-
local error_term_text = text:sub(from_re_start_to_err_start)
311-
312-
local lookbehind = error_term_text:match [[(%(%?<!?(.*)%))]]
313-
314-
local is_lookbehind = lookbehind ~= nil
315-
316-
if is_lookbehind then
317-
table.insert(components, {
318-
type = 'lookbehind_assertion',
319-
text = lookbehind,
320-
negative = lookbehind:match [[^%(%?<!]] ~= nil,
321-
depth = (parent and parent.depth or 0) + 1,
322-
children = M.make_components(child, nil, root_regex_node)
323-
})
324-
else
325-
table.insert(components, {
326-
type = type,
327-
text = get_node_text(child, 0),
328-
error = {
329-
text = error_text,
330-
position = { row, { e_start, e_end } },
331-
start_offset = re_start,
332-
},
333-
})
334-
end
297+
table.insert(components, {
298+
type = type,
299+
text = get_node_text(child, bufnr),
300+
error = {
301+
text = error_text,
302+
position = { row, { e_start, e_end } },
303+
start_offset = re_start,
304+
},
305+
})
335306
-- all other node types should be added to the tree
336307
else
337308

@@ -349,12 +320,12 @@ function M.make_components(node, parent, root_regex_node)
349320
-- negated character class
350321
if type == 'character_class' and component.text:find [[^%[%^]] then
351322
component.negative = true
352-
component.children = M.make_components(child, nil, root_regex_node)
323+
component.children = M.make_components(bufnr, child, nil, root_regex_node)
353324
table.insert(components, component)
354325

355326
-- alternations are containers which do not increase depth
356327
elseif type == 'alternation' then
357-
component.children = M.make_components(child, nil, root_regex_node)
328+
component.children = M.make_components(bufnr, child, nil, root_regex_node)
358329
table.insert(components, component)
359330

360331
-- skip group_name and punctuation nodes
@@ -372,7 +343,7 @@ function M.make_components(node, parent, root_regex_node)
372343
-- find the group_name and apply it to the component
373344
for grandchild in child:iter_children() do
374345
if node_pred.is_group_name(grandchild) then
375-
component.group_name = get_node_text(grandchild, 0)
346+
component.group_name = get_node_text(grandchild, bufnr)
376347
break
377348
end
378349
end
@@ -387,7 +358,7 @@ function M.make_components(node, parent, root_regex_node)
387358
end
388359

389360
-- once state has been set above, process the children
390-
component.children = M.make_components(child, component, root_regex_node)
361+
component.children = M.make_components(bufnr, child, component, root_regex_node)
391362

392363
-- FIXME: find the root cause of this weird case
393364
if #component.children == 1

lua/regexplainer/renderers/narrative/init.lua

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,11 @@ local buffers = require 'regexplainer.buffers'
55
--
66
local M = {}
77

8-
local function check_for_lookbehind(components)
9-
for _, component in ipairs(components) do
10-
if component.type == 'lookbehind_assertion' or check_for_lookbehind(component.children or {}) then
11-
return true
12-
end
13-
end
14-
return false
15-
end
16-
178
---@param components RegexplainerComponent[]
189
---@param options RegexplainerOptions
1910
---@param state RegexplainerRendererState
2011
function M.get_lines(components, options, state)
21-
local lines = narrative.recurse(components, options, state)
22-
local found = check_for_lookbehind(components)
23-
if found then
24-
table.insert(lines, 1, '⚠️ **Lookbehinds are poorly supported**')
25-
table.insert(lines, 2, '⚠️ results may not be accurate')
26-
table.insert(lines, 3, '⚠️ See https://github.com/tree-sitter/tree-sitter-regex/issues/13')
27-
table.insert(lines, 4, '')
28-
end
29-
return lines
12+
return narrative.recurse(components, options, state)
3013
end
3114

3215
---@param buffer RegexplainerBuffer

lua/regexplainer/utils/treesitter.lua

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
local M = {}
22

3+
local get_cursor = vim.api.nvim_win_get_cursor
34
local get_query = vim.treesitter.query.get
45
local get_parser = vim.treesitter.get_parser
5-
local get_node_text = vim.treesitter.get_node_text or vim.treesitter.query.get_node_text
6-
local get_node = vim.treesitter.get_node
6+
local get_node_text = vim.treesitter.get_node_text or vim.treesitter.query.get_node_text local get_node = vim.treesitter.get_node
77
local get_captures_at_cursor = vim.treesitter.get_captures_at_cursor
8+
local is_in_node_range = vim.treesitter.is_in_node_range
89

910
local node_types = {
1011
'alternation',
@@ -40,6 +41,24 @@ for _, type in ipairs(node_types) do
4041
end
4142
end
4243

44+
---@param original_node TSNode regex_pattern node
45+
---@return TSNode|nil, integer|nil, string|nil
46+
local function get_pattern(original_node)
47+
local buf = vim.api.nvim_create_buf(false, false)
48+
vim.api.nvim_buf_set_lines(buf, 0, 1,true, { get_node_text(original_node, 0) })
49+
local node
50+
for _, tree in ipairs(get_parser(buf, 'regex'):parse()) do
51+
node = tree:root()
52+
while node and node:type() ~= 'pattern' do
53+
node = node:child(0)
54+
end
55+
end
56+
if node and node:type() == 'pattern' then
57+
return node, buf, nil
58+
end
59+
return nil, buf, 'could not find pattern node'
60+
end
61+
4362
function M.has_regexp_at_cursor()
4463
for _, cap in ipairs(get_captures_at_cursor(0)) do
4564
if cap == 'string.regexp' then
@@ -113,25 +132,27 @@ end
113132

114133
--- Using treesitter, find the current node at cursor, and traverse up to the
115134
--- document root to determine if we're on a regexp
116-
---@return any, string|nil
135+
---@return TSNode|nil, integer|nil, string|nil
117136
--
118137
function M.get_regexp_pattern_at_cursor()
119-
local lang_tree = vim.treesitter.get_parser(0, 'regex')
120-
local query = vim.treesitter.query.get('regex', 'regexplainer')
121-
if query then
122-
local cursor_range = vim.api.nvim_win_get_cursor(0)
123-
local cursor_row, cursor_col = unpack(cursor_range)
124-
local cursor_node = get_node_at_cursor(lang_tree)
125-
if cursor_node then
126-
for id, node in query:iter_captures(cursor_node:tree():root(), 0) do
127-
local name = query.captures[id] -- name of the capture in the query
128-
if name == 'regexplainer.pattern' and is_in_node_range(node, cursor_row - 1, cursor_col) then
129-
return node, nil
130-
end
131-
end
138+
local parser = get_parser(0)
139+
parser:parse()
140+
local query = get_query(parser:lang(), 'regexplainer')
141+
if not query then
142+
return nil, nil, 'could not load regexplainer query for ' .. parser:lang()
143+
end
144+
local cursor_node = get_node()
145+
if not cursor_node then
146+
return nil, nil, 'could not get node at cursor'
147+
end
148+
local row, col = cursor_node:range()
149+
for id, node in query:iter_captures(cursor_node:tree():root(), 0, row, row + 1) do
150+
local name = query.captures[id] -- name of the capture in the query
151+
if name == 'regexplainer.pattern' and is_in_node_range(node, row, col) then
152+
return get_pattern(node)
132153
end
133154
end
134-
return nil, 'no node'
155+
return nil, nil, 'no node'
135156
end
136157

137158
return M

queries/javascript/regexplainer.scm

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
(regex) @regexplainer.regex
1+
(regex
2+
(regex_pattern) @regexplainer.pattern) @regexplainer.regex

0 commit comments

Comments
 (0)