Skip to content

fix(finder): handle abort in mini.pick integration#1983

Merged
CKolkey merged 1 commit into
NeogitOrg:masterfrom
DefectingCat:fix/mini-pick-abort
Jul 9, 2026
Merged

fix(finder): handle abort in mini.pick integration#1983
CKolkey merged 1 commit into
NeogitOrg:masterfrom
DefectingCat:fix/mini-pick-abort

Conversation

@DefectingCat

Copy link
Copy Markdown
Contributor

Problem

When mini_pick is enabled as the finder integration, aborting a selection (e.g. pressing <Esc> in the branch picker opened via bb) leaves the find_async coroutine suspended forever. The picker then appears dead — subsequent bb invocations show nothing until Neovim is restarted.

Root cause

Finder:find documents its contract as (finder.lua:307-308):

---Engages finder and invokes `on_select` with the item or items, or nil if aborted

Every integration branch honors this — on_select(nil) is called on abort — except mini_pick:

elseif config.check_integration("mini_pick") then
  local mini_pick = require("mini.pick")
  mini_pick.start { source = { items = self.entries, choose = on_select } }  -- ← no abort path
end

mini.pick's source.choose only fires on explicit confirm (<CR>). Aborting via <Esc> goes through picker_stop, which never calls choose. As a result on_select is never invoked on abort.

Since Finder.find_async = a.wrap(Finder.find, 2), callers using open_async (e.g. checkout_branch_revision via bb) `coroutine.yield` waiting for on_select to resume them. With on_select never firing, the coroutine is permanently suspended.

Compare with how the other integrations handle abort:

Integration abort → on_select(nil)
vim.ui.select calls on_select(...) with a nil item
fzf_lua ["esc"] / ["ctrl-c"] / ["ctrl-q"]close_actionon_select(nil)
telescope close → on_select(nil)
snacks on_closecomplete(nil)on_select(nil)
mini_pick ❌ none

Fix

Wire a one-shot MiniPickStop autocmd (mini.pick has no source.on_close field) so an abort still completes the finder via on_select(nil). The new mini_pick_choose helper mirrors the existing snacks_confirm, including the completed guard that ensures on_select runs exactly once.

elseif config.check_integration("mini_pick") then
  local mini_pick = require("mini.pick")
  local choose, on_stop = mini_pick_choose(on_select, self.opts.refocus_status)
  local group = vim.api.nvim_create_augroup("NeogitMiniPickStop", { clear = true })
  vim.api.nvim_create_autocmd("User", {
    pattern = "MiniPickStop", once = true, group = group,
    callback = function()
      vim.api.nvim_clear_autocmds { group = group }
      on_stop()
    end,
  })
  mini_pick.start { source = { items = self.entries, choose = choose } }
end

Reproduce

  1. setup({ integrations = { mini_pick = true } })
  2. Open neogit status, press bb (branch/revision checkout)
  3. Press <Esc> instead of <CR>
  4. Press bb again — picker no longer opens; requires restarting Neovim to recover

`Finder:find` documents that `on_select` is invoked with the selected item
or `nil` if aborted. Every integration honors this except `mini_pick`:
`source.choose` only fires on explicit confirm (<CR>), and aborting via
<Esc> goes through `picker_stop`, which never calls `choose`.

Through `find_async = a.wrap(Finder.find, 2)`, callers using `open_async`
(e.g. `bb` -> `checkout_branch_revision`) `coroutine.yield` waiting for
`on_select` to resume them. When `on_select` never runs, the coroutine is
suspended forever and the picker appears dead until Neovim is restarted.

Wire a one-shot `MiniPickStop` autocmd (mini.pick has no `source.on_close`
field) so an abort still completes the finder via `on_select(nil)`. The new
`mini_pick_choose` helper mirrors `snacks_confirm`, including the `completed`
guard that ensures `on_select` runs exactly once.
@CKolkey
CKolkey merged commit ef5b449 into NeogitOrg:master Jul 9, 2026
3 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants