11local config = require (' opencode.config' )
22local util = require (' opencode.util' )
3+ local Promise = require (' opencode.promise' )
34
45--- @class PickerAction
56--- @field key ? OpencodeKeymapEntry | string The key binding for this action
67--- @field label string The display label for this action
7- --- @field fn fun ( selected : any , opts : PickerOptions ): any[] ? The action function
8+ --- @field fn fun ( selected : any , opts : PickerOptions ): any[] | Promise<any[]> ? The action function
89--- @field reload ? boolean Whether to reload the picker after action
910
1011--- @class PickerOptions
@@ -24,7 +25,7 @@ local util = require('opencode.util')
2425--- @field fn_fzf_index fun ( line : string ): integer ?
2526
2627--- @class FzfAction
27- --- @field fn fun ( selected : string[] , fzf_opts : FzfLuaOptions ): nil
28+ --- @field fn fun ( selected : string[] , fzf_opts : FzfLuaOptions ): nil | Promise<nil>
2829--- @field header string
2930--- @field reload boolean
3031
@@ -127,10 +128,12 @@ local function telescope_ui(opts)
127128 local selection = action_state .get_selected_entry ()
128129 if selection then
129130 local new_items = action .fn (selection .value , opts )
130- if action .reload and new_items then
131- opts .items = new_items
132- refresh_picker ()
133- end
131+ Promise .wrap (new_items ):and_then (function (resolved_items )
132+ if action .reload and resolved_items then
133+ opts .items = resolved_items
134+ refresh_picker ()
135+ end
136+ end )
134137 end
135138 end
136139
152155local function fzf_ui (opts )
153156 local fzf_lua = require (' fzf-lua' )
154157
158+ local function create_fzf_config ()
159+ return {
160+ winopts = opts .width and {
161+ width = opts .width + 8 , -- extra space for fzf UI
162+ } or nil ,
163+ fzf_opts = { [' --prompt' ] = opts .title .. ' > ' },
164+ _headers = { ' actions' },
165+ fn_fzf_index = function (line )
166+ for i , item in ipairs (opts .items ) do
167+ if opts .format_fn (item ):to_string () == line then
168+ return i
169+ end
170+ end
171+ return nil
172+ end ,
173+ }
174+ end
175+
176+ local function create_finder ()
177+ return function (fzf_cb )
178+ for _ , item in ipairs (opts .items ) do
179+ fzf_cb (opts .format_fn (item ):to_string ())
180+ end
181+ fzf_cb ()
182+ end
183+ end
184+
185+ local function refresh_fzf ()
186+ vim .schedule (function ()
187+ fzf_ui (opts )
188+ end )
189+ end
190+
155191 --- @type FzfLuaActions
156192 local actions_config = {
157193 [' default' ] = function (selected , fzf_opts )
@@ -176,9 +212,13 @@ local function fzf_ui(opts)
176212 local idx = fzf_opts .fn_fzf_index (selected [1 ] --[[ @as string]] )
177213 if idx and opts .items [idx ] then
178214 local new_items = action .fn (opts .items [idx ], opts )
179- if action .reload and new_items then
180- opts .items = new_items
181- end
215+ Promise .wrap (new_items ):and_then (function (resolved_items )
216+ if action .reload and resolved_items then
217+ --- @cast resolved_items any[]
218+ opts .items = resolved_items
219+ refresh_fzf ()
220+ end
221+ end )
182222 end
183223 end ,
184224 header = action .label ,
@@ -187,27 +227,10 @@ local function fzf_ui(opts)
187227 end
188228 end
189229
190- fzf_lua .fzf_exec (function (fzf_cb )
191- for _ , item in ipairs (opts .items ) do
192- fzf_cb (opts .format_fn (item ):to_string ())
193- end
194- fzf_cb ()
195- end , {
196- winopts = opts .width and {
197- width = opts .width + 8 , -- extra space for fzf UI
198- } or nil ,
199- fzf_opts = { [' --prompt' ] = opts .title .. ' > ' },
200- _headers = { ' actions' },
201- actions = actions_config ,
202- fn_fzf_index = function (line )
203- for i , item in ipairs (opts .items ) do
204- if opts .format_fn (item ):to_string () == line then
205- return i
206- end
207- end
208- return nil
209- end ,
210- })
230+ local fzf_config = create_fzf_config ()
231+ fzf_config .actions = actions_config
232+
233+ fzf_lua .fzf_exec (create_finder (), fzf_config )
211234end
212235
213236--- Mini.pick UI implementation
@@ -230,15 +253,14 @@ local function mini_pick_ui(opts)
230253 local selected = mini_pick .get_picker_matches ().current
231254 if selected and selected .item then
232255 local new_items = action .fn (selected .item , opts )
233- if action .reload and new_items then
234- opts .items = new_items
235- --- @type MiniPickItem[]
236- items = vim .tbl_map (function (it )
237- return { text = opts .format_fn (it ):to_string (), item = it }
238- end , opts .items )
239- mini_pick .set_picker_items (items )
240- end
256+ Promise .wrap (new_items ):and_then (function (resolved_items )
257+ if action .reload and resolved_items then
258+ opts .items = resolved_items
259+ mini_pick_ui (opts )
260+ end
261+ end )
241262 end
263+ return true
242264 end ,
243265 }
244266 end
@@ -318,10 +340,12 @@ local function snacks_picker_ui(opts)
318340 if item then
319341 vim .schedule (function ()
320342 local new_items = action .fn (item , opts )
321- if action .reload and new_items then
322- opts .items = new_items
323- _picker :find ()
324- end
343+ Promise .wrap (new_items ):and_then (function (resolved_items )
344+ if action .reload and resolved_items then
345+ opts .items = resolved_items
346+ _picker :find ()
347+ end
348+ end )
325349 end )
326350 end
327351 end
0 commit comments