mirror of
https://github.com/neovim/neovim.git
synced 2026-07-16 22:21:30 +00:00
feat(ui): use vim.ui.select for :tselect, z= #39478
Problem: `:tselect` and `z=` (spell suggest) have their own bespoke select menus. Solution: - Delegate to `vim.ui.select` instead. - Bonus: - `:tselect` gains mouse support. `print_tag_list` didn't suport mouseclick. This causes some minor regressions, which are not blockers: - `z=` no longer draws the list right-left if 'rightleft' is set. - TODO: can/should `vim.ui.select` / `vim.fn.inputlist()` handle that? - `:tselect` - No "column" headings (`# pri kind tag file`). - No highlighting: (HLF_T: tag name, HLF_D: file, HLF_CM: extra fields). - TODO: can `vim.ui.select()` support highlighted chunks (`[[text, hl_id], ...]`) ? fix https://github.com/neovim/neovim/issues/25814 fix https://github.com/neovim/neovim/issues/31987
This commit is contained in:
36
runtime/lua/vim/_core/spell.lua
Normal file
36
runtime/lua/vim/_core/spell.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
local select_blocking = require('vim._core.ui').select_blocking
|
||||
local N_ = vim.fn.gettext
|
||||
|
||||
local M = {}
|
||||
|
||||
--- @class vim._core.spell.Suggestion
|
||||
--- @field word string The suggested replacement.
|
||||
--- @field extra? string Text replaced when wider than the bad span.
|
||||
--- @field score integer Primary score.
|
||||
--- @field altscore? integer Secondary score (only set when 'spellsuggest' contains "double" or "best").
|
||||
--- @field salscore? boolean True if the score came from sound-alike comparison (only set alongside `altscore`).
|
||||
|
||||
--- Called from `spell_suggest()` (`z=`) to let the user pick from `items` via
|
||||
--- |vim.ui.select()|.
|
||||
---
|
||||
--- @param items vim._core.spell.Suggestion[]
|
||||
--- @param bad string The misspelled word being replaced.
|
||||
--- @return integer? # 1-based index of the chosen suggestion, or nil if cancelled.
|
||||
function M.suggest_select(items, bad)
|
||||
return select_blocking(items, {
|
||||
prompt = N_('Change "%s" to:'):format(bad),
|
||||
kind = 'spell',
|
||||
format_item = function(s)
|
||||
local extra = s.extra and (' < "' .. s.extra .. '"') or ''
|
||||
local score = ''
|
||||
if vim.o.verbose > 0 then
|
||||
score = s.altscore
|
||||
and (' (%s%d - %d)'):format(s.salscore and 's ' or '', s.score, s.altscore)
|
||||
or (' (%d)'):format(s.score)
|
||||
end
|
||||
return ('"%s"%s%s'):format(s.word, extra, score)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
44
runtime/lua/vim/_core/tag.lua
Normal file
44
runtime/lua/vim/_core/tag.lua
Normal file
@@ -0,0 +1,44 @@
|
||||
local select_blocking = require('vim._core.ui').select_blocking
|
||||
local N_ = vim.fn.gettext
|
||||
|
||||
local M = {}
|
||||
|
||||
--- @class vim._core.tag.Match
|
||||
--- @field tag string
|
||||
--- @field kind? string
|
||||
--- @field pri string Priority code, e.g. "FSC" — see `:h tag-priority`.
|
||||
--- @field file string
|
||||
--- @field extra? string
|
||||
--- @field cur boolean True if this is the currently-active tagstack match.
|
||||
|
||||
--- Called from `do_tag()` (`:tselect`, ambiguous `:tag`, etc.) to let the user
|
||||
--- pick from `matches` via |vim.ui.select()|.
|
||||
---
|
||||
--- @param items vim._core.tag.Match[] One per matching tag.
|
||||
--- @return integer? # 1-based index of the chosen tag, or nil if cancelled.
|
||||
function M.select(items)
|
||||
local taglen = 18
|
||||
for _, m in ipairs(items) do
|
||||
taglen = math.max(taglen, vim.fn.strdisplaywidth(m.tag) + 2)
|
||||
end
|
||||
|
||||
return select_blocking(items, {
|
||||
prompt = N_('Type number and <Enter> (q or empty cancels):'),
|
||||
kind = 'tag',
|
||||
format_item = function(m)
|
||||
local marker = m.cur and '>' or ' '
|
||||
local kind = m.kind or ''
|
||||
local extra = m.extra and (' ' .. m.extra) or ''
|
||||
return ('%s %s %-4s %-' .. taglen .. 's %s%s'):format(
|
||||
marker,
|
||||
m.pri,
|
||||
kind,
|
||||
m.tag,
|
||||
m.file,
|
||||
extra
|
||||
)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
23
runtime/lua/vim/_core/ui.lua
Normal file
23
runtime/lua/vim/_core/ui.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
local M = {}
|
||||
|
||||
--- Wait for |vim.ui.select()| and return the selected index. The default vim.ui.select impl
|
||||
--- (inputlist()) is synchronous, but this also handles async pickers (fzf-lua, telescope, …).
|
||||
---
|
||||
--- @param items table Items to choose from.
|
||||
--- @param opts table Forwarded to |vim.ui.select()|.
|
||||
--- @return integer? # 1-based index of the chosen item, or nil if cancelled/interrupted.
|
||||
function M.select_blocking(items, opts)
|
||||
local choice ---@type integer?
|
||||
local done = false
|
||||
vim.ui.select(items, opts or {}, function(_, idx)
|
||||
choice = idx
|
||||
done = true
|
||||
end)
|
||||
-- vim.wait returns false on timeout (math.huge means never) or interrupt (-2).
|
||||
vim.wait(math.huge, function()
|
||||
return done
|
||||
end)
|
||||
return choice
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -26,11 +26,11 @@ local M = vim._defer_require('vim.ui', {
|
||||
---@field kind? string
|
||||
|
||||
--- Prompts the user to pick from a list of items, allowing arbitrary (potentially asynchronous)
|
||||
--- work until `on_choice`.
|
||||
--- work until `on_choice`. This is the standard "picker" interface, used by |z=|, |:tselect|, etc.
|
||||
---
|
||||
--- Plugins may override `vim.ui.select` to provide a custom "picker" interface; they are expected
|
||||
--- to call the `format_item` and `preview_item` handlers (if any) provided by the caller. They may
|
||||
--- also use the `kind` hint (if provided by the caller) to decide how to handle some items.
|
||||
--- Plugins may override `vim.ui.select` to provide a custom picker; they are expected to call the
|
||||
--- `format_item` and `preview_item` handlers (if any) provided by the caller. They may also use the
|
||||
--- `kind` hint (if provided by the caller) to decide how to handle some items.
|
||||
---
|
||||
--- Note: the default `vim.ui.select` currently doesn't support preview.
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user