Skip to content

Commit

Permalink
feat: Add preselect option to moonicipal.select
Browse files Browse the repository at this point in the history
  • Loading branch information
idanarye committed Jan 2, 2025
1 parent 468c9ee commit 91b464c
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 34 deletions.
68 changes: 36 additions & 32 deletions doc/moonicipal.txt
Original file line number Diff line number Diff line change
Expand Up @@ -638,38 +638,42 @@ MoonicipalSelectSource *MoonicipalSelectSource*
MoonicipalSelectOptions *MoonicipalSelectOptions*

Fields: ~
{prompt?} (string) A prompt to display to the user when they select the option.
{format?} (MoonicipalOptionTransformer) How to display the options in the selection UI.
{multi?} (boolean) Select multiple items. Setting this to `true` will make |moonicipal.select|
return a list - even if only one item is selected.

This, of course, does not work for backends that don't support multiple
selection (like the builtin |vim.ui.select()|), and they'll still allow to
select only one item, but if `multi` is set to `true` that one item will
still get wrapped in a list.
{preview?} (fun(item:any):string|string[]) Show a preview for the item under the cursor.
{actions?} () Add actions - keymaps that can be used to finalize the selection instead of
Enter. When such a key is used, its string is returned as the second return
value.

The syntax for special keys is always Vim's syntax (e.g. `<C-r>`). Even when
the backend uses a different sytnax (e.g. fzf-lua), one should still use
Vim's sytnax and let the interaction function do the translation. The string
returned in the second return value will still be the exact same string
passed to `actions` - the translation is transparent to the user.

The keycodes can be passed as either list items or dictionary keys - and
both styles can be mixed in the same table:
```
moonicipal.select({ ... }, {
actions = {
'<M-a>',
['<M-a>'] = {},
},
})
```
When using the second style, the value is used to configure the specific
action (see |MoonicipalSelectActionOptions|)
{prompt?} (string) A prompt to display to the user when they select the option.
{format?} (MoonicipalOptionTransformer) How to display the options in the selection UI.
{multi?} (boolean) Select multiple items. Setting this to `true` will make |moonicipal.select|
return a list - even if only one item is selected.

This, of course, does not work for backends that don't support multiple
selection (like the builtin |vim.ui.select()|), and they'll still allow to
select only one item, but if `multi` is set to `true` that one item will
still get wrapped in a list.
{preview?} (fun(item:any):string|string[]) Show a preview for the item under the cursor.
{actions?} (string[]|table<string,MoonicipalSelectActionOptions>) Add actions - keymaps that can be used to finalize the selection instead of
Enter. When such a key is used, its string is returned as the second return
value.

The syntax for special keys is always Vim's syntax (e.g. `<C-r>`). Even when
the backend uses a different sytnax (e.g. fzf-lua), one should still use
Vim's sytnax and let the interaction function do the translation. The string
returned in the second return value will still be the exact same string
passed to `actions` - the translation is transparent to the user.

The keycodes can be passed as either list items or dictionary keys - and
both styles can be mixed in the same table:
```
moonicipal.select({ ... }, {
actions = {
'<M-a>',
['<M-a>'] = {},
},
})
```
When using the second style, the value is used to configure the specific
action (see |MoonicipalSelectActionOptions|)
{preselect?} (number|any) Start the selection UI with the (1-based) item selected.

If the items are provided as a table, preselect is the key of that table
instead of a number.


MoonicipalSelectActionOptions *MoonicipalSelectActionOptions*
Expand Down
13 changes: 13 additions & 0 deletions lua/moonicipal/selection/fzf-lua.lua
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ return function(options, opts)
['--with-nth'] = '2..',
['--delimiter'] = '\t',
},
keymap = {
fzf = {},
}
}
if opts.prompt then
new_opts.prompt = opts.prompt .. '> '
Expand All @@ -100,6 +103,7 @@ return function(options, opts)
local register, fetch = tagged_items_register_and_fetch(format_item)

local new_options
local preselect_index = opts.preselect
if vim.is_callable(options) then
function new_options(cb)
util.defer_to_coroutine(function()
Expand All @@ -115,6 +119,11 @@ return function(options, opts)
else
assert(not opts.format, 'cannot use format when the options are a table')
new_options = vim.tbl_keys(options)
if preselect_index ~= nil then
preselect_index = vim.iter(ipairs(new_options)):find(function(_, key)
return preselect_index == key
end)
end
new_opts.fzf_opts['--with-nth'] = nil
fetch = function(key)
return options[key]
Expand All @@ -128,6 +137,10 @@ return function(options, opts)
end
end

if preselect_index then
new_opts.keymap.fzf['load'] = ('pos(%d)'):format(preselect_index)
end

return util.resume_with(function(resumer)
new_opts.actions = {}

Expand Down
7 changes: 6 additions & 1 deletion lua/moonicipal/selection/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ local M = {}
---```
---When using the second style, the value is used to configure the specific
---action (see |MoonicipalSelectActionOptions|)
---@field actions? (string[] | {[string]: MoonicipalSelectActionOptions})
---@field actions? string[] | table<string,MoonicipalSelectActionOptions>
---Start the selection UI with the (1-based) item selected.
---
---If the items are provided as a table, preselect is the key of that table
---instead of a number.
---@field preselect? number | any
M.MoonicipalSelectOptions = {}

---@class MoonicipalSelectActionOptions
Expand Down
8 changes: 7 additions & 1 deletion lua/moonicipal/selection/telescope.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ return function(options, opts)
end

local finder
local preselect_index = opts.preselect
if vim.is_callable(options) then
-- TODO: make this lazy
local items = {}
Expand All @@ -34,8 +35,12 @@ return function(options, opts)
}
else
assert(not opts.format, 'cannot use format when the options are a table')
local options_keys = vim.tbl_keys(options)
preselect_index = vim.iter(ipairs(options_keys)):find(function(_, key)
return preselect_index == key
end)
finder = require'telescope.finders'.new_table {
results = vim.tbl_keys(options),
results = options_keys,
entry_maker = function(key)
return {
value = options[key],
Expand Down Expand Up @@ -84,6 +89,7 @@ return function(options, opts)
finder = finder,
sorter = require'telescope.config'.values.generic_sorter{},
previewer = previewer,
default_selection_index = preselect_index,
attach_mappings = function(_, map_action)
local function gen_action(return_marker, action_opts)
action_opts = vim.tbl_extend('keep', action_opts, {multi = opts.multi})
Expand Down

0 comments on commit 91b464c

Please sign in to comment.