@@ -19,6 +19,7 @@ local Promise = require('opencode.promise')
1919--- @field multi_selection ? table<string , boolean> Actions that support multi-selection
2020--- @field preview ? " file" | " none" | false Preview mode : " file" for file preview , " none" or false to disable
2121--- @field layout_opts ? OpencodeUIPickerConfig
22+ --- @field close ? fun () Close the picker programmatically (set by the backend )
2223
2324--- @class TelescopeEntry
2425--- @field value any
@@ -84,6 +85,8 @@ local function telescope_ui(opts)
8485 local entry_display = require (' telescope.pickers.entry_display' )
8586
8687 -- Create displayer dynamically based on number of parts
88+ --- @param picker_item PickerItem
89+ --- @return table
8790 local function create_displayer (picker_item )
8891 local items = {}
8992 for _ in ipairs (picker_item .parts ) do
@@ -128,6 +131,7 @@ local function telescope_ui(opts)
128131 return entry
129132 end
130133
134+ --- @return unknown
131135 local function refresh_picker ()
132136 return current_picker
133137 and current_picker :refresh (
@@ -147,6 +151,11 @@ local function telescope_ui(opts)
147151 width = opts .width + 7 , -- extra space for telescope UI
148152 } or nil ,
149153 attach_mappings = function (prompt_bufnr , map )
154+ opts .close = function ()
155+ selection_made = true
156+ actions .close (prompt_bufnr )
157+ end
158+
150159 actions .select_default :replace (function ()
151160 selection_made = true
152161 local selection = action_state .get_selected_entry ()
@@ -197,8 +206,12 @@ local function telescope_ui(opts)
197206 local new_items = action .fn (items_to_process , opts )
198207 Promise .wrap (new_items ):and_then (function (resolved_items )
199208 if action .reload and resolved_items then
200- opts .items = resolved_items
201- refresh_picker ()
209+ if # resolved_items == 0 and opts .close then
210+ opts .close ()
211+ else
212+ opts .items = resolved_items
213+ refresh_picker ()
214+ end
202215 end
203216 end )
204217 end
222235local function fzf_ui (opts )
223236 local fzf_lua = require (' fzf-lua' )
224237
238+ --- @return table
225239 local function create_fzf_config ()
226240 local has_multi_action = util .some (opts .actions , function (action )
227241 return action .multi_selection
@@ -251,6 +265,7 @@ local function fzf_ui(opts)
251265 }
252266 end
253267
268+ --- @return fun ( fzf_cb : fun ( line ?: string ))
254269 local function create_finder ()
255270 return function (fzf_cb )
256271 for idx , item in ipairs (opts .items ) do
@@ -289,15 +304,40 @@ local function fzf_ui(opts)
289304 end
290305 end
291306
307+ --- Reopen fzf-lua to reflect updated picker items.
292308 local function refresh_fzf ()
293309 vim .schedule (function ()
294310 fzf_ui (opts )
295311 end )
296312 end
297313
314+ local closed = false
315+
316+ opts .close = function ()
317+ if closed then
318+ return
319+ end
320+ closed = true
321+ vim .schedule (function ()
322+ local ok , fzf_win = pcall (require , ' fzf-lua.win' )
323+ if ok and fzf_win .__SELF then
324+ local win = fzf_win .__SELF ()
325+ if win then
326+ win :close ()
327+ end
328+ end
329+ if opts .callback then
330+ opts .callback (nil )
331+ end
332+ end )
333+ end
334+
298335 --- @type FzfLuaActions
299336 local actions_config = {
300337 [' default' ] = function (selected , fzf_opts )
338+ if closed then
339+ return
340+ end
301341 if not selected or # selected == 0 then
302342 if opts .callback then
303343 opts .callback (nil )
@@ -310,6 +350,9 @@ local function fzf_ui(opts)
310350 end
311351 end ,
312352 [' esc' ] = function ()
353+ if closed then
354+ return
355+ end
313356 if opts .callback then
314357 opts .callback (nil )
315358 end
@@ -346,8 +389,12 @@ local function fzf_ui(opts)
346389 Promise .wrap (new_items ):and_then (function (resolved_items )
347390 if action .reload and resolved_items then
348391 --- @cast resolved_items any[]
349- opts .items = resolved_items
350- refresh_fzf ()
392+ if # resolved_items == 0 and opts .close then
393+ opts .close ()
394+ else
395+ opts .items = resolved_items
396+ refresh_fzf ()
397+ end
351398 end
352399 end )
353400 end
@@ -376,6 +423,10 @@ local function mini_pick_ui(opts)
376423
377424 local mappings = {}
378425
426+ opts .close = function ()
427+ mini_pick .stop ()
428+ end
429+
379430 for action_name , action in pairs (opts .actions ) do
380431 if action .key and action .key [1 ] then
381432 mappings [action_name ] = {
@@ -387,8 +438,12 @@ local function mini_pick_ui(opts)
387438 local new_items = action .fn (current .item , opts )
388439 Promise .wrap (new_items ):and_then (function (resolved_items )
389440 if action .reload and resolved_items then
390- opts .items = resolved_items
391- mini_pick_ui (opts )
441+ if # resolved_items == 0 and opts .close then
442+ opts .close ()
443+ else
444+ opts .items = resolved_items
445+ mini_pick_ui (opts )
446+ end
392447 end
393448 end )
394449 end
@@ -522,6 +577,13 @@ local function snacks_picker_ui(opts)
522577 snack_opts .win .input .keys [action .key [1 ]] = { action_name , mode = action .key .mode or ' i' }
523578
524579 snack_opts .actions [action_name ] = function (_picker , item )
580+ if not opts .close then
581+ opts .close = function ()
582+ selection_made = true
583+ _picker :close ()
584+ end
585+ end
586+
525587 if item then
526588 local items_to_process
527589 if action .multi_selection then
@@ -540,9 +602,13 @@ local function snacks_picker_ui(opts)
540602 local new_items = action .fn (items_to_process , opts )
541603 Promise .wrap (new_items ):and_then (function (resolved_items )
542604 if action .reload and resolved_items then
543- opts .items = resolved_items
544- _picker :refresh ()
545- _picker :find ()
605+ if # resolved_items == 0 and opts .close then
606+ opts .close ()
607+ else
608+ opts .items = resolved_items
609+ _picker :refresh ()
610+ _picker :find ()
611+ end
546612 end
547613 end )
548614 end )
@@ -584,6 +650,7 @@ function M.create_picker_item(parts)
584650 parts = parts ,
585651 }
586652
653+ --- @return string
587654 function item :to_string ()
588655 local texts = {}
589656 for _ , part in ipairs (self .parts ) do
@@ -592,6 +659,7 @@ function M.create_picker_item(parts)
592659 return table.concat (texts , ' ' )
593660 end
594661
662+ --- @return table
595663 function item :to_formatted_text ()
596664 local formatted = {}
597665 for _ , part in ipairs (self .parts ) do
0 commit comments