From 001e969e05b68350988ab4c989d95e9b6a5ed671 Mon Sep 17 00:00:00 2001 From: David Herman Date: Mon, 30 Mar 2026 23:26:06 +0200 Subject: [PATCH] fix(ui): close picker when last item is deleted --- lua/opencode/ui/base_picker.lua | 78 +++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/lua/opencode/ui/base_picker.lua b/lua/opencode/ui/base_picker.lua index 2149e830..9a289898 100644 --- a/lua/opencode/ui/base_picker.lua +++ b/lua/opencode/ui/base_picker.lua @@ -19,6 +19,7 @@ local Promise = require('opencode.promise') ---@field multi_selection? table Actions that support multi-selection ---@field preview? "file"|"none"|false Preview mode: "file" for file preview, "none" or false to disable ---@field layout_opts? OpencodeUIPickerConfig +---@field close? fun() Close the picker programmatically (set by the backend) ---@class TelescopeEntry ---@field value any @@ -147,6 +148,11 @@ local function telescope_ui(opts) width = opts.width + 7, -- extra space for telescope UI } or nil, attach_mappings = function(prompt_bufnr, map) + opts.close = function() + selection_made = true + actions.close(prompt_bufnr) + end + actions.select_default:replace(function() selection_made = true local selection = action_state.get_selected_entry() @@ -197,8 +203,12 @@ local function telescope_ui(opts) local new_items = action.fn(items_to_process, opts) Promise.wrap(new_items):and_then(function(resolved_items) if action.reload and resolved_items then - opts.items = resolved_items - refresh_picker() + if #resolved_items == 0 and opts.close then + opts.close() + else + opts.items = resolved_items + refresh_picker() + end end end) end @@ -295,9 +305,33 @@ local function fzf_ui(opts) end) end + local closed = false + + opts.close = function() + if closed then + return + end + closed = true + vim.schedule(function() + local ok, fzf_win = pcall(require, 'fzf-lua.win') + if ok and fzf_win.__SELF then + local win = fzf_win.__SELF() + if win then + win:close() + end + end + if opts.callback then + opts.callback(nil) + end + end) + end + ---@type FzfLuaActions local actions_config = { ['default'] = function(selected, fzf_opts) + if closed then + return + end if not selected or #selected == 0 then if opts.callback then opts.callback(nil) @@ -310,6 +344,9 @@ local function fzf_ui(opts) end end, ['esc'] = function() + if closed then + return + end if opts.callback then opts.callback(nil) end @@ -346,8 +383,12 @@ local function fzf_ui(opts) Promise.wrap(new_items):and_then(function(resolved_items) if action.reload and resolved_items then ---@cast resolved_items any[] - opts.items = resolved_items - refresh_fzf() + if #resolved_items == 0 and opts.close then + opts.close() + else + opts.items = resolved_items + refresh_fzf() + end end end) end @@ -376,6 +417,10 @@ local function mini_pick_ui(opts) local mappings = {} + opts.close = function() + mini_pick.stop() + end + for action_name, action in pairs(opts.actions) do if action.key and action.key[1] then mappings[action_name] = { @@ -387,8 +432,12 @@ local function mini_pick_ui(opts) local new_items = action.fn(current.item, opts) Promise.wrap(new_items):and_then(function(resolved_items) if action.reload and resolved_items then - opts.items = resolved_items - mini_pick_ui(opts) + if #resolved_items == 0 and opts.close then + opts.close() + else + opts.items = resolved_items + mini_pick_ui(opts) + end end end) end @@ -522,6 +571,13 @@ local function snacks_picker_ui(opts) snack_opts.win.input.keys[action.key[1]] = { action_name, mode = action.key.mode or 'i' } snack_opts.actions[action_name] = function(_picker, item) + if not opts.close then + opts.close = function() + selection_made = true + _picker:close() + end + end + if item then local items_to_process if action.multi_selection then @@ -540,9 +596,13 @@ local function snacks_picker_ui(opts) local new_items = action.fn(items_to_process, opts) Promise.wrap(new_items):and_then(function(resolved_items) if action.reload and resolved_items then - opts.items = resolved_items - _picker:refresh() - _picker:find() + if #resolved_items == 0 and opts.close then + opts.close() + else + opts.items = resolved_items + _picker:refresh() + _picker:find() + end end end) end)