1
1
local component = require ' regexplainer.component'
2
2
local tree = require ' regexplainer.utils.treesitter'
3
3
local utils = require ' regexplainer.utils'
4
- local buffers = require ' regexplainer.buffers'
5
- local defer = require ' regexplainer.utils.defer'
4
+ local Buffers = require ' regexplainer.buffers'
5
+
6
+ local get_node_text = vim .treesitter .get_node_text
7
+ local deep_extend = vim .tbl_deep_extend
8
+ local map = vim .tbl_map
9
+ local buf_delete = vim .api .nvim_buf_delete
10
+ local ag = vim .api .nvim_create_augroup
11
+ local au = vim .api .nvim_create_autocmd
6
12
7
13
--- @class RegexplainerOptions
8
- --- @field mode ? ' narrative' # TODO: 'ascii', 'graphical'
14
+ --- @field mode ? ' narrative' | ' debug ' # TODO: 'ascii', 'graphical'
9
15
--- @field auto ? boolean # Automatically display when cursor enters a regexp
10
16
--- @field filetypes ? string[] # Filetypes (extensions) to automatically show regexplainer.
11
17
--- @field debug ? boolean # Notify debug logs
@@ -15,10 +21,10 @@ local defer = require 'regexplainer.utils.defer'
15
21
--- @field popup ? NuiPopupBufferOptions # options for the popup buffer
16
22
--- @field split ? NuiSplitBufferOptions # options for the split buffer
17
23
18
- --- @class RegexplainerRenderOptions : RegexplainerOptions
24
+ --- @class RegexplainerRenderOptions : RegexplainerOptions
19
25
--- @field register " *" | " +" | ' "' | " :" | " ." | " %" | " /" | " #" | " 0" | " 1" | " 2" | " 3" | " 4" | " 5" | " 6" | " 7" | " 8" | " 9"
20
26
21
- --- @class RegexplainerYankOptions : RegexplainerOptions
27
+ --- @class RegexplainerYankOptions : RegexplainerOptions
22
28
--- @field register " *" | " +" | ' "' | " :" | " ." | " %" | " /" | " #" | " 0" | " 1" | " 2" | " 3" | " 4" | " 5" | " 6" | " 7" | " 8" | " 9"
23
29
24
30
--- @class RegexplainerMappings
@@ -29,15 +35,12 @@ local defer = require 'regexplainer.utils.defer'
29
35
--- @field show_split ? string # shows regexplainer in a split window
30
36
--- @field show_popup ? string # shows regexplainer in a popup window
31
37
32
- local get_node_text = vim .treesitter .get_node_text or vim .treesitter .query .get_node_text
33
-
34
38
--- Maps config.mappings keys to vim command names and descriptions
35
39
--
36
40
local config_command_map = {
37
41
show = { ' RegexplainerShow' , ' Show Regexplainer' },
38
42
hide = { ' RegexplainerHide' , ' Hide Regexplainer' },
39
- toggle = { ' RegexplainerToggle' , ' Toggle Regexplainer' },
40
- yank = { ' RegexplainerYank' , ' Yank Regexplainer' },
43
+ toggle = { ' RegexplainerToggle' , ' Toggle Regexplainer' }, yank = { ' RegexplainerYank' , ' Yank Regexplainer' },
41
44
show_split = { ' RegexplainerShowSplit' , ' Show Regexplainer in a split Window' },
42
45
show_popup = { ' RegexplainerShowPopup' , ' Show Regexplainer in a popup' },
43
46
}
@@ -51,90 +54,73 @@ local default_config = {
51
54
auto = false ,
52
55
filetypes = {
53
56
' html' ,
54
- ' js' ,
55
- ' cjs' ,
56
- ' mjs' ,
57
- ' ts' ,
58
- ' jsx' ,
59
- ' tsx' ,
60
- ' cjsx' ,
61
- ' mjsx' ,
57
+ ' js' , ' javascript' , ' cjs' , ' mjs' ,
58
+ ' ts' , ' typescript' , ' cts' , ' mts' ,
59
+ ' tsx' , ' typescriptreact' , ' ctsx' , ' mtsx' ,
60
+ ' jsx' , ' javascriptreact' , ' cjsx' , ' mjsx' ,
62
61
},
63
62
debug = false ,
64
63
display = ' popup' ,
65
64
mappings = {
66
65
toggle = ' gR' ,
67
66
},
68
67
narrative = {
69
- separator = ' \n ' ,
68
+ indentation_string = ' ' ,
70
69
},
71
70
}
72
71
73
72
--- A deep copy of the default config.
74
73
--- During setup(), any user-provided config will be folded in
75
74
--- @type RegexplainerOptions
76
75
--
77
- local local_config = vim . tbl_deep_extend (' keep' , default_config , {})
76
+ local local_config = deep_extend (' keep' , default_config , {})
78
77
79
78
--- Show the explainer for the regexp under the cursor
80
79
--- @param options ? RegexplainerOptions overrides for this call
81
- --- @return nil
80
+ --- @return nil | number bufnr the bufnr of the regexplaination
82
81
--
83
- local function show (options )
84
- options = vim . tbl_deep_extend (' force' , local_config , options or {})
85
- local node , error = tree .get_regexp_pattern_at_cursor (options )
82
+ local function show_for_real (options )
83
+ options = deep_extend (' force' , local_config , options or {})
84
+ local node , scratchnr , error = tree .get_regexp_pattern_at_cursor ()
86
85
87
86
if error and options .debug then
88
87
utils .notify (' Rexexplainer: ' .. error , ' debug' )
89
- elseif node then
90
- -- in the case of a pattern node, we need to get the first child 🤷
91
- if node :type () == ' pattern' and node :child_count () == 1 then
92
- node = node :child (0 )
93
- end
94
-
95
- --- @type RegexplainerRenderer
96
- local renderer
88
+ elseif node and scratchnr then
97
89
--- @type boolean , RegexplainerRenderer
98
- local can_render , _renderer = pcall (require , ' regexplainer.renderers.' .. options .mode )
90
+ local can_render , renderer = pcall (require , ' regexplainer.renderers.' .. options .mode )
99
91
100
- if can_render then
101
- renderer = _renderer
102
- else
92
+ if not can_render then
103
93
utils .notify (options .mode .. ' is not a valid renderer' , ' warning' )
104
94
utils .notify (renderer , ' error' )
105
95
renderer = require ' regexplainer.renderers.narrative'
106
96
end
107
97
108
- local components = component .make_components (node , nil , node )
98
+ local components = component .make_components (scratchnr , node , nil , node )
109
99
110
- local buffer = buffers .get_buffer (options )
100
+ local buffer = Buffers .get_buffer (options )
111
101
112
102
if not buffer and options .debug then
113
- local Debug = require ' regexplainer.renderers.debug'
114
- return Debug .render (options , components )
103
+ renderer = require ' regexplainer.renderers.debug'
115
104
end
116
105
117
- buffers .render (buffer , renderer , components , options , {
118
- full_regexp_text = get_node_text (node , 0 ),
119
- })
106
+ local state = { full_regexp_text = get_node_text (node , scratchnr ) }
107
+
108
+ Buffers .render (buffer , renderer , components , options , state )
109
+ buf_delete (scratchnr , { force = true })
120
110
else
121
- buffers .hide_all ()
111
+ Buffers .hide_all ()
122
112
end
123
113
end
124
114
125
115
local disable_auto = false
126
116
127
- local show_debounced_trailing , timer_trailing = defer .debounce_trailing (show , 5 )
128
-
129
- buffers .register_timer (timer_trailing )
130
-
131
117
local M = {}
132
118
133
119
--- Show the explainer for the regexp under the cursor
134
120
--- @param options ? RegexplainerOptions
135
121
function M .show (options )
136
122
disable_auto = true
137
- show (options )
123
+ show_for_real (options )
138
124
disable_auto = false
139
125
end
140
126
@@ -145,11 +131,7 @@ function M.yank(options)
145
131
if type (options ) == ' string' then
146
132
options = { register = options }
147
133
end
148
- show (vim .tbl_deep_extend (
149
- ' force' ,
150
- options ,
151
- { display = ' register' }
152
- ))
134
+ show_for_real (deep_extend (' force' , options , { display = ' register' }))
153
135
disable_auto = false
154
136
end
155
137
@@ -158,16 +140,16 @@ end
158
140
--- @return nil
159
141
--
160
142
function M .setup (config )
161
- local_config = vim . tbl_deep_extend (' keep' , config or {}, default_config )
143
+ local_config = deep_extend (' keep' , config or {}, default_config )
162
144
163
145
-- bind keys from config
164
146
local has_which_key = pcall (require , ' which-key' )
165
- for cmd , binding in pairs (local_config .mappings ) do
166
- local command = ' :' .. config_command_map [cmd ][1 ] .. ' <CR>'
147
+ for cmdmap , binding in pairs (local_config .mappings ) do
148
+ local cmd , description = unpack (config_command_map [cmdmap ])
149
+ local command = ' :' .. cmd .. ' <CR>'
167
150
168
151
if has_which_key then
169
152
local wk = require ' which-key'
170
- local description = config_command_map [cmd ][2 ]
171
153
wk .register ({ [binding ] = { command , description } }, { mode = ' n' })
172
154
else
173
155
utils .map (' n' , binding , command )
@@ -176,13 +158,13 @@ function M.setup(config)
176
158
177
159
-- setup autocommand
178
160
if local_config .auto then
179
- vim . api . nvim_create_augroup (augroup_name , { clear = true })
180
- vim . api . nvim_create_autocmd (' CursorMoved' , {
161
+ ag (augroup_name , { clear = true })
162
+ au (' CursorMoved' , {
181
163
group = ' Regexplainer' ,
182
- pattern = vim . tbl_map (function (x ) return ' *.' .. x end , local_config .filetypes ),
164
+ pattern = map (function (x ) return ' *.' .. x end , local_config .filetypes ),
183
165
callback = function ()
184
- if not disable_auto then
185
- show_debounced_trailing ()
166
+ if tree . has_regexp_at_cursor () and not disable_auto then
167
+ show_for_real ()
186
168
end
187
169
end ,
188
170
})
@@ -194,13 +176,13 @@ end
194
176
--- Hide any displayed regexplainer buffers
195
177
--
196
178
function M .hide ()
197
- buffers .hide_all ()
179
+ Buffers .hide_all ()
198
180
end
199
181
200
182
--- Toggle Regexplainer
201
183
--
202
184
function M .toggle ()
203
- if buffers .is_open () then
185
+ if Buffers .is_open () then
204
186
M .hide ()
205
187
else
206
188
M .show ()
211
193
--
212
194
function M .teardown ()
213
195
local_config = vim .tbl_deep_extend (' keep' , {}, default_config )
214
- buffers .clear_timers ()
196
+ Buffers .clear_timers ()
215
197
pcall (vim .api .nvim_del_augroup_by_name , augroup_name )
216
198
end
217
199
220
202
function M .debug_components ()
221
203
--- @type any
222
204
local mode = ' debug'
223
- show ({ auto = false , display = ' split' , mode = mode })
205
+ show_for_real ({ auto = false , display = ' split' , mode = mode })
224
206
end
225
207
226
208
return M
0 commit comments