mirror of
https://github.com/harivansh-afk/forge.nvim.git
synced 2026-04-17 10:02:25 +00:00
feat(picker): add multi-backend picker abstraction
Problem: all pickers were tightly coupled to fzf-lua via ANSI strings and fzf-specific action tables, making it impossible to use telescope or snacks.nvim. Solution: introduce `forge.picker` dispatcher with `fzf`, `telescope`, and `snacks` backends. Format functions now return `forge.Segment[]` instead of ANSI strings. `pickers.lua` builds backend-agnostic `forge.PickerEntry[]` and delegates to `forge.picker.pick()`. Backend auto-detection tries fzf-lua, snacks, telescope in order. Commits, branches, and worktree pickers remain fzf-only with graceful fallback.
This commit is contained in:
parent
354c5000c0
commit
fa7cab89af
6 changed files with 826 additions and 599 deletions
80
lua/forge/picker/init.lua
Normal file
80
lua/forge/picker/init.lua
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
local M = {}
|
||||
|
||||
---@alias forge.Segment {[1]: string, [2]: string?}
|
||||
|
||||
---@class forge.PickerEntry
|
||||
---@field display forge.Segment[]
|
||||
---@field value any
|
||||
---@field ordinal string?
|
||||
|
||||
---@class forge.PickerActionDef
|
||||
---@field name string
|
||||
---@field fn fun(entry: forge.PickerEntry?)
|
||||
|
||||
---@class forge.PickerOpts
|
||||
---@field prompt string?
|
||||
---@field entries forge.PickerEntry[]
|
||||
---@field actions forge.PickerActionDef[]
|
||||
---@field picker_name string
|
||||
|
||||
---@type table<string, string>
|
||||
local backends = {
|
||||
['fzf-lua'] = 'forge.picker.fzf',
|
||||
telescope = 'forge.picker.telescope',
|
||||
snacks = 'forge.picker.snacks',
|
||||
}
|
||||
|
||||
---@return string
|
||||
local function detect()
|
||||
local cfg = require('forge').config()
|
||||
local name = cfg.picker or 'auto'
|
||||
if name ~= 'auto' then
|
||||
return name
|
||||
end
|
||||
if pcall(require, 'fzf-lua') then
|
||||
return 'fzf-lua'
|
||||
end
|
||||
if pcall(require, 'snacks') then
|
||||
return 'snacks'
|
||||
end
|
||||
if pcall(require, 'telescope') then
|
||||
return 'telescope'
|
||||
end
|
||||
return 'fzf-lua'
|
||||
end
|
||||
|
||||
---@param entry forge.PickerEntry
|
||||
---@return string
|
||||
function M.ordinal(entry)
|
||||
if entry.ordinal then
|
||||
return entry.ordinal
|
||||
end
|
||||
local parts = {}
|
||||
for _, seg in ipairs(entry.display) do
|
||||
table.insert(parts, seg[1])
|
||||
end
|
||||
return table.concat(parts)
|
||||
end
|
||||
|
||||
---@return string
|
||||
function M.backend()
|
||||
return detect()
|
||||
end
|
||||
|
||||
---@param opts forge.PickerOpts
|
||||
function M.pick(opts)
|
||||
local name = detect()
|
||||
local mod_path = backends[name]
|
||||
if not mod_path then
|
||||
vim.notify('[forge]: unknown picker backend: ' .. name, vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
local ok, backend = pcall(require, mod_path)
|
||||
if not ok then
|
||||
vim.notify('[forge]: picker backend ' .. name .. ' not available', vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
backend.pick(opts)
|
||||
end
|
||||
|
||||
return M
|
||||
Loading…
Add table
Add a link
Reference in a new issue