1
1
local async = require (" blink.cmp.lib.async" )
2
2
local logger = require (" parrot.logger" )
3
- local utils = require (" parrot.utils " )
3
+ local core = require (" parrot.completion.core " )
4
4
local comp_utils = require (" parrot.completion.utils" )
5
5
6
6
local source = {}
@@ -22,80 +22,61 @@ function source:is_available(context)
22
22
return comp_utils .is_completion_available (context .bufnr )
23
23
end
24
24
25
- local function extract_cmd (context )
26
- if not context or not context .line then
27
- return nil
28
- end
29
- local line_before_cursor = context .line :sub (1 , context .cursor [2 ])
30
- return line_before_cursor :match (" ^%s*(@%S*)" )
31
- end
32
-
33
25
function source :get_completions (context , callback )
34
26
callback = vim .schedule_wrap (callback )
35
- local cmd = extract_cmd (context )
27
+ local input = context .line :sub (1 , context .cursor [2 ])
28
+ local cmd = core .extract_cmd (input )
36
29
if not cmd then
37
30
callback ({ is_incomplete_forward = false , is_incomplete_backward = false , items = {} })
38
31
return
39
32
end
40
-
41
33
if cmd == " @" then
42
- local CompletionItemKind = require (" blink.cmp.types" ).CompletionItemKind
43
- local items = {
44
- {
45
- label = " file" ,
46
- kind = CompletionItemKind .Keyword ,
47
- documentation = {
48
- kind = " markdown" ,
49
- value = comp_utils .get_command_documentation (" file" ),
50
- },
51
- },
52
- {
53
- label = " buffer" ,
54
- kind = CompletionItemKind .Keyword ,
55
- documentation = {
56
- kind = " markdown" ,
57
- value = comp_utils .get_command_documentation (" buffer" ),
58
- },
59
- },
60
- {
61
- label = " directory" ,
62
- kind = CompletionItemKind .Keyword ,
63
- documentation = {
64
- kind = " markdown" ,
65
- value = comp_utils .get_command_documentation (" directory" ),
66
- },
67
- },
68
- }
69
- callback ({ is_incomplete_forward = false , is_incomplete_backward = false , items = items })
34
+ local result = core .get_base_completion_items ()
35
+ callback ({ is_incomplete_forward = result .is_incomplete , is_incomplete_backward = false , items = result .items })
70
36
elseif cmd :match (" ^@file:" ) then
71
37
local path = cmd :sub (7 )
72
- self
73
- :get_file_completions (context , path )
74
- :map (function (completion_response )
75
- callback (completion_response )
38
+ async .task
39
+ .new (function (resolve )
40
+ local result = core .get_file_completions_sync (path , false , self .opts .max_items )
41
+ resolve ({
42
+ is_incomplete_forward = result .is_incomplete ,
43
+ is_incomplete_backward = false ,
44
+ items = result .items ,
45
+ })
76
46
end )
47
+ :map (callback )
77
48
:catch (function (err )
78
49
logger .error (" File completion error: " .. tostring (err ))
79
50
callback ({ is_incomplete_forward = false , is_incomplete_backward = false , items = {} })
80
51
end )
81
52
elseif cmd :match (" ^@buffer:" ) then
82
53
local query = cmd :sub (9 ):lower ()
83
- self
84
- :get_buffer_completions (context , query )
85
- :map (function (completion_response )
86
- callback (completion_response )
54
+ async .task
55
+ .new (function (resolve )
56
+ local result = core .get_buffer_completions_sync (query , self .opts .max_items )
57
+ resolve ({
58
+ is_incomplete_forward = result .is_incomplete ,
59
+ is_incomplete_backward = false ,
60
+ items = result .items ,
61
+ })
87
62
end )
63
+ :map (callback )
88
64
:catch (function (err )
89
65
logger .error (" Buffer completion error: " .. tostring (err ))
90
66
callback ({ is_incomplete_forward = false , is_incomplete_backward = false , items = {} })
91
67
end )
92
68
elseif cmd :match (" ^@directory:" ) then
93
69
local path = cmd :sub (12 )
94
- self
95
- :get_directory_completions (context , path )
96
- :map (function (completion_response )
97
- callback (completion_response )
70
+ async .task
71
+ .new (function (resolve )
72
+ local result = core .get_file_completions_sync (path , true , self .opts .max_items )
73
+ resolve ({
74
+ is_incomplete_forward = result .is_incomplete ,
75
+ is_incomplete_backward = false ,
76
+ items = result .items ,
77
+ })
98
78
end )
79
+ :map (callback )
99
80
:catch (function (err )
100
81
logger .error (" Directory completion error: " .. tostring (err ))
101
82
callback ({ is_incomplete_forward = false , is_incomplete_backward = false , items = {} })
@@ -105,179 +86,7 @@ function source:get_completions(context, callback)
105
86
end
106
87
end
107
88
108
- function source :get_file_completions (context , path )
109
- local cwd = vim .fn .getcwd ()
110
- local target_dir = comp_utils .resolve_path (path , cwd )
111
- if not target_dir then
112
- return async .task .new (function (resolve )
113
- resolve ({ is_incomplete_forward = false , is_incomplete_backward = false , items = {} })
114
- end )
115
- end
116
- return comp_utils
117
- .scan_dir_async (target_dir , async )
118
- :map (function (entries )
119
- return comp_utils .fs_stat_all_async (target_dir , entries , async )
120
- end )
121
- :map (function (entries )
122
- local CompletionItemKind = require (" blink.cmp.types" ).CompletionItemKind
123
- local items = {}
124
- for _ , entry in ipairs (entries ) do
125
- if # items >= self .opts .max_items then
126
- break
127
- end
128
- if self .opts .show_hidden_files or entry .name :sub (1 , 1 ) ~= " ." then
129
- local full_path = utils .path_join (target_dir , entry .name )
130
- local is_dir = entry .type == " directory"
131
- local documentation_value
132
- if is_dir then
133
- documentation_value = string.format (" **Directory:** %s" , full_path )
134
- else
135
- local size = entry .stat .size or 0
136
- local mtime = os.date (" %Y-%m-%d %H:%M" , (entry .stat .mtime or {}).sec or os.time ())
137
- documentation_value =
138
- string.format (" **File:** %s\n **Size:** %d bytes\n **Modified:** %s" , full_path , size , mtime )
139
- end
140
- table.insert (items , {
141
- label = is_dir and entry .name .. " /" or entry .name ,
142
- kind = is_dir and CompletionItemKind .Folder or CompletionItemKind .File ,
143
- filterText = entry .name :lower (),
144
- documentation = {
145
- kind = " markdown" ,
146
- value = documentation_value ,
147
- },
148
- data = {
149
- path = entry .name ,
150
- full_path = full_path ,
151
- type = entry .type ,
152
- },
153
- })
154
- end
155
- end
156
- table.sort (items , function (a , b )
157
- local a_is_dir = a .kind == CompletionItemKind .Folder
158
- local b_is_dir = b .kind == CompletionItemKind .Folder
159
- if a_is_dir and not b_is_dir then
160
- return true
161
- elseif not a_is_dir and b_is_dir then
162
- return false
163
- else
164
- return a .label :lower () < b .label :lower ()
165
- end
166
- end )
167
- return {
168
- is_incomplete_forward = (# items >= self .opts .max_items ),
169
- is_incomplete_backward = false ,
170
- items = items ,
171
- }
172
- end )
173
- end
174
-
175
- function source :get_buffer_completions (context , query )
176
- return async .task .new (function (resolve )
177
- local CompletionItemKind = require (" blink.cmp.types" ).CompletionItemKind
178
- local items = {}
179
- local buffers = vim .api .nvim_list_bufs ()
180
- local current_buf = vim .api .nvim_get_current_buf ()
181
- for _ , buf in ipairs (buffers ) do
182
- if # items >= self .opts .max_items then
183
- break
184
- end
185
- if vim .api .nvim_buf_is_loaded (buf ) then
186
- local bufhidden = vim .api .nvim_buf_get_option (buf , " bufhidden" )
187
- local name = vim .api .nvim_buf_get_name (buf )
188
- local filetype = vim .api .nvim_buf_get_option (buf , " filetype" )
189
- local modified = vim .api .nvim_buf_get_option (buf , " modified" )
190
- if name and name ~= " " and not (bufhidden and bufhidden :match (" ^wipe" )) then
191
- local filename = vim .fn .fnamemodify (name , " :t" )
192
- local rel_path = vim .fn .fnamemodify (name , " :~:." )
193
- if
194
- not query
195
- or query == " "
196
- or filename :lower ():find (query , 1 , true )
197
- or rel_path :lower ():find (query , 1 , true )
198
- then
199
- local item = {
200
- label = filename ,
201
- kind = CompletionItemKind .Buffer ,
202
- detail = string.format (" Buffer No.: [%d]\n Relative path: %s\n " , buf , rel_path ),
203
- filterText = filename :lower (),
204
- documentation = {
205
- kind = " markdown" ,
206
- value = string.format (
207
- " Absolute path: %s\n Type: %s\n %s" ,
208
- name ,
209
- filetype ~= " " and filetype or " unknown" ,
210
- modified and " *(modified)*" or " "
211
- ),
212
- },
213
- data = { buffer_id = buf , path = name },
214
- }
215
- if buf == current_buf then
216
- table.insert (items , 1 , item )
217
- else
218
- table.insert (items , item )
219
- end
220
- end
221
- end
222
- end
223
- end
224
- resolve ({
225
- is_incomplete_forward = false ,
226
- is_incomplete_backward = false ,
227
- items = items ,
228
- })
229
- end )
230
- end
231
-
232
- function source :get_directory_completions (context , path )
233
- local cwd = vim .fn .getcwd ()
234
- local target_dir = comp_utils .resolve_path (path , cwd )
235
- if not target_dir then
236
- return async .task .new (function (resolve )
237
- resolve ({ is_incomplete_forward = false , is_incomplete_backward = false , items = {} })
238
- end )
239
- end
240
- return comp_utils
241
- .scan_dir_async (target_dir , async )
242
- :map (function (entries )
243
- return comp_utils .fs_stat_all_async (target_dir , entries , async )
244
- end )
245
- :map (function (entries )
246
- local CompletionItemKind = require (" blink.cmp.types" ).CompletionItemKind
247
- local items = {}
248
- for _ , entry in ipairs (entries ) do
249
- if # items >= self .opts .max_items then
250
- break
251
- end
252
- if entry .type == " directory" and (self .opts .show_hidden_files or entry .name :sub (1 , 1 ) ~= " ." ) then
253
- local full_path = utils .path_join (target_dir , entry .name )
254
- table.insert (items , {
255
- label = entry .name .. " /" ,
256
- kind = CompletionItemKind .Folder ,
257
- filterText = entry .name :lower (),
258
- documentation = {
259
- kind = " markdown" ,
260
- value = string.format (" **Directory:** %s" , full_path ),
261
- },
262
- data = {
263
- path = entry .name ,
264
- full_path = full_path ,
265
- type = entry .type ,
266
- },
267
- })
268
- end
269
- end
270
- table.sort (items , function (a , b )
271
- return a .label :lower () < b .label :lower ()
272
- end )
273
- return {
274
- is_incomplete_forward = (# items >= self .opts .max_items ),
275
- is_incomplete_backward = false ,
276
- items = items ,
277
- }
278
- end )
279
- end
280
-
89
+ -- Keep the resolve function as is, since it’s specific to blink.cmp
281
90
function source :resolve (item , callback )
282
91
callback = vim .schedule_wrap (callback )
283
92
if not item or not item .data or item .data .type ~= " file" or not item .data .full_path then
0 commit comments