From 91b464c2cd5e33e572a9fe0a825fd0f2151c0877 Mon Sep 17 00:00:00 2001 From: Idan Arye Date: Thu, 2 Jan 2025 21:13:45 +0200 Subject: [PATCH] feat: Add `preselect` option to `moonicipal.select` --- doc/moonicipal.txt | 68 ++++++++++++++------------ lua/moonicipal/selection/fzf-lua.lua | 13 +++++ lua/moonicipal/selection/init.lua | 7 ++- lua/moonicipal/selection/telescope.lua | 8 ++- 4 files changed, 62 insertions(+), 34 deletions(-) diff --git a/doc/moonicipal.txt b/doc/moonicipal.txt index 246a669..f010865 100644 --- a/doc/moonicipal.txt +++ b/doc/moonicipal.txt @@ -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. ``). 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 = { - '', - [''] = {}, - }, - }) - ``` - 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) 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. ``). 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 = { + '', + [''] = {}, + }, + }) + ``` + 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* diff --git a/lua/moonicipal/selection/fzf-lua.lua b/lua/moonicipal/selection/fzf-lua.lua index 7c429f5..596dfbd 100644 --- a/lua/moonicipal/selection/fzf-lua.lua +++ b/lua/moonicipal/selection/fzf-lua.lua @@ -91,6 +91,9 @@ return function(options, opts) ['--with-nth'] = '2..', ['--delimiter'] = '\t', }, + keymap = { + fzf = {}, + } } if opts.prompt then new_opts.prompt = opts.prompt .. '> ' @@ -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() @@ -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] @@ -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 = {} diff --git a/lua/moonicipal/selection/init.lua b/lua/moonicipal/selection/init.lua index 1fbfa20..3ca2600 100644 --- a/lua/moonicipal/selection/init.lua +++ b/lua/moonicipal/selection/init.lua @@ -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 +---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 diff --git a/lua/moonicipal/selection/telescope.lua b/lua/moonicipal/selection/telescope.lua index 3f009c2..1a6100f 100644 --- a/lua/moonicipal/selection/telescope.lua +++ b/lua/moonicipal/selection/telescope.lua @@ -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 = {} @@ -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], @@ -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})