@@ -7,58 +7,17 @@ local range = require "refactoring.range"
77
88local M = {}
99
10- -- TODO: using `inline_var` in something like `local f = vim.bo.filetype` will
11- -- block the editor (because it tried to parse the buffer with each reference
12- -- to `vim.bo.filetype`? Look into it)
13-
1410--- @param definition refactor.QfItem
15- --- @param query vim.treesitter.Query
16- --- @return nil | refactor.VariableInfo
17- local function get_definition_info (definition , query )
11+ --- @param variables_info refactor.VariableInfo[]
12+ --- @return nil | refactor.ProcessedVariableInfo
13+ local function get_definition_info (definition , variables_info )
1814 local definition_buf = vim .fn .bufadd (definition .filename )
19- if not api .nvim_buf_is_loaded (definition_buf ) then vim .fn .bufload (definition_buf ) end
20- local definition_lang_tree , err2 = ts .get_parser (definition_buf , nil , { error = false })
21- if not definition_lang_tree then
22- vim .notify (err2 , vim .log .levels .ERROR )
23- return
24- end
25- -- TODO: use async parsing
26- definition_lang_tree :parse (true )
27- local definition_nested_lang_tree = definition_lang_tree :language_for_range {
28- definition .lnum - 1 ,
29- definition .col - 1 ,
30- definition .end_lnum - 1 ,
31- definition .end_col - 1 ,
32- }
33-
34- local definition_matches_info = {} --- @type refactor.VariableMatchInfo[]
35- for _ , tree in ipairs (definition_nested_lang_tree :trees ()) do
36- for _ , match in query :iter_matches (tree :root (), definition_buf ) do
37- local match_info = {} --- @type refactor.VariableMatchInfo |{}
38- for capture_id , nodes in pairs (match ) do
39- local name = query .captures [capture_id ]
40-
41- if name == " variable.identifier" then
42- match_info .identifier = nodes
43- elseif name == " variable.identifier_separator" then
44- match_info .identifier_separator = nodes
45- elseif name == " variable.value_separator" then
46- match_info .value_separator = nodes
47- elseif name == " variable.value" then
48- match_info .value = nodes
49- elseif name == " variable.declaration" then
50- match_info .declaration = nodes
51- end
52- end
53- if not vim .tbl_isempty (match_info ) then table.insert (definition_matches_info , match_info ) end
54- end
55- end
5615
5716 local definition_start = pos .vimscript (definition_buf , definition .lnum , definition .col )
58- --- @type refactor.VariableInfo
59- local variable_info = iter (definition_matches_info )
17+ --- @type refactor.ProcessedVariableInfo
18+ local variable_info = iter (variables_info )
6019 :map (
61- --- @param match_info refactor.VariableMatchInfo
20+ --- @param match_info refactor.VariableInfo
6221 function (match_info )
6322 local variable_info = iter (ipairs (match_info .identifier ))
6423 :filter (
@@ -72,7 +31,7 @@ local function get_definition_info(definition, query)
7231 :map (
7332 --- @param i integer
7433 --- @param identifier TSNode
75- --- @return refactor.VariableInfo
34+ --- @return refactor.ProcessedVariableInfo
7635 function (i , identifier )
7736 return {
7837 identifier = identifier ,
@@ -91,7 +50,7 @@ local function get_definition_info(definition, query)
9150 end
9251 )
9352 :filter (
94- --- @param variable_info refactor.VariableInfo
53+ --- @param variable_info refactor.ProcessedVariableInfo
9554 function (variable_info )
9655 return variable_info ~= nil
9756 end
@@ -101,14 +60,96 @@ local function get_definition_info(definition, query)
10160 return variable_info
10261end
10362
104- --- @class refactor.VariableMatchInfo
63+ --- @class refactor.inline_var.MatchInfo
64+ --- @field variables refactor.VariableInfo[]
65+
66+ -- As a side effect, loads all the buffers for all of the definitions and references
67+ --- @param definitions refactor.QfItem[]
68+ --- @param references refactor.QfItem[]
69+ --- @param lang string
70+ --- @return nil |{ [integer] : refactor.inline_var.MatchInfo }
71+ local function get_match_info (definitions , references , lang )
72+ local is_unique = require (" refactoring.utils" ).is_unique
73+
74+ local query = ts .query .get (lang , " refactor" )
75+ if not query then
76+ vim .notify ((" There is no `refactor` query file for language %s" ):format (lang ), vim .log .levels .ERROR )
77+ return
78+ end
79+
80+ --- @type { [integer] : refactor.inline_var.MatchInfo }
81+ local ts_info = iter ({ definitions , references })
82+ :flatten (1 )
83+ :map (
84+ --- @param item refactor.QfItem
85+ function (item )
86+ local buf = vim .fn .bufadd (item .filename )
87+ if not api .nvim_buf_is_loaded (buf ) then vim .fn .bufload (buf ) end
88+ return buf
89+ end
90+ )
91+ :filter (is_unique ())
92+ :map (
93+ --- @param buf integer
94+ function (buf )
95+ local lang_tree , err2 = ts .get_parser (buf , lang , { error = false })
96+ if not lang_tree then
97+ vim .notify (err2 , vim .log .levels .ERROR )
98+ return
99+ end
100+
101+ local variables_info = {} --- @type refactor.VariableInfo[]
102+ for _ , tree in ipairs (lang_tree :trees ()) do
103+ for _ , match in query :iter_matches (tree :root (), buf ) do
104+ local variable_info --- @type refactor.VariableInfo | nil
105+ for capture_id , nodes in pairs (match ) do
106+ local name = query .captures [capture_id ]
107+
108+ if name == " variable.identifier" then
109+ variable_info = variable_info or {}
110+ variable_info .identifier = nodes
111+ elseif name == " variable.identifier_separator" then
112+ variable_info = variable_info or {}
113+ variable_info .identifier_separator = nodes
114+ elseif name == " variable.value_separator" then
115+ variable_info = variable_info or {}
116+ variable_info .value_separator = nodes
117+ elseif name == " variable.value" then
118+ variable_info = variable_info or {}
119+ variable_info .value = nodes
120+ elseif name == " variable.declaration" then
121+ variable_info = variable_info or {}
122+ variable_info .declaration = nodes
123+ end
124+ end
125+ if variable_info then table.insert (variables_info , variable_info ) end
126+ end
127+ end
128+
129+ return buf , { variables = variables_info }
130+ end
131+ )
132+ :fold (
133+ {},
134+ --- @param acc { [integer] : refactor.inline_var.MatchInfo }
135+ --- @param k integer
136+ --- @param v nil | refactor.inline_var.MatchInfo
137+ function (acc , k , v )
138+ acc [k ] = v
139+ return acc
140+ end
141+ )
142+ return ts_info
143+ end
144+
145+ --- @class refactor.VariableInfo
105146--- @field identifier TSNode[]
106147--- @field identifier_separator TSNode[] | nil
107148--- @field value TSNode[]
108149--- @field value_separator TSNode[] | nil
109150--- @field declaration TSNode[]
110151
111- --- @class refactor.VariableInfo
152+ --- @class refactor.ProcessedVariableInfo
112153--- @field identifier TSNode
113154--- @field identifier_separator TSNode | nil
114155--- @field value TSNode
@@ -150,24 +191,22 @@ function M.inline_var(_, config)
150191 local definitions = unpack (results [1 ]) --- @type refactor.QfItem[]
151192 local references = unpack (results [2 ]) --- @type refactor.QfItem[]
152193
153- local query = ts .query .get (lang , " refactor" )
154- if not query then
155- vim .notify ((" There is no `refactor` query file for language %s" ):format (lang ), vim .log .levels .ERROR )
156- return
157- end
194+ local ts_info = get_match_info (definitions , references , lang )
195+ if not ts_info then return end
158196
159- --- @type { definition : refactor.QfItem , match : refactor.VariableInfo } []
197+ --- @type { definition : refactor.QfItem , match : refactor.ProcessedVariableInfo } []
160198 local definitions_with_match = iter (definitions )
161199 :map (
162200 --- @param d refactor.QfItem
163201 function (d )
164- -- TODO: parse once and reuse parsed info by buffer (like `inline_func`)
165- local definition_match = get_definition_info (d , query )
202+ local definition_buf = vim .fn .bufadd (d .filename )
203+ local variables_info = ts_info [definition_buf ].variables
204+ local definition_match = get_definition_info (d , variables_info )
166205 return { definition = d , match = definition_match }
167206 end
168207 )
169208 :filter (
170- --- @param dwm { definition : refactor.QfItem , match : refactor.VariableInfo }
209+ --- @param dwm { definition : refactor.QfItem , match : refactor.ProcessedVariableInfo }
171210 function (dwm )
172211 return dwm .match ~= nil
173212 end
@@ -182,7 +221,7 @@ function M.inline_var(_, config)
182221 or select (definitions_with_match , {
183222 prompt = " Mutliple definitions found, select one" ,
184223 format_item =
185- --- @param item { definition : refactor.QfItem , match : refactor.VariableInfo }
224+ --- @param item { definition : refactor.QfItem , match : refactor.ProcessedVariableInfo }
186225 function (item )
187226 local buf = vim .fn .bufadd (item .definition .filename )
188227 return ts .get_node_text (item .match .declaration , buf )
0 commit comments