diff --git a/README.md b/README.md index 0d593360..d24d1545 100644 --- a/README.md +++ b/README.md @@ -387,6 +387,15 @@ vim.keymap.set( to `true` (defaults to `false`), it will fall back to `vim.ui.select` if there are no grouped code actions. + The default keymaps are `` to confirm a code action and `q` or `` to cancel + a selection. + You can modify these by defining `rustaceanvim.code_action.confirm` or + `rustaceanvim.code_action.quit` mappings, for example: + + ```lua + vim.keymap.set('n', '', 'rustaceanvim.code_action.confirm') + ``` + ![](https://github.com/mrcjkb/rustaceanvim/assets/12857160/866d3cb1-8e56-4380-8c03-812386441f47) @@ -408,9 +417,6 @@ vim.keymap.set( vim.cmd.RustLsp { 'hover', 'actions' } ``` - By default, this plugin replaces Neovim's built-in hover handler with hover - actions, so you can also use `vim.lsp.buf.hover()`. - You can invoke a hover action by switching to the hover window and entering `` on the respective line, or with a keymap for the `RustHoverAction` mapping, which accepts a `` prefix as the (1-based) index of the hover action to invoke. diff --git a/doc/rustaceanvim.txt b/doc/rustaceanvim.txt index facba973..fa72c44d 100644 --- a/doc/rustaceanvim.txt +++ b/doc/rustaceanvim.txt @@ -45,7 +45,24 @@ It accepts the following subcommands: `args[]` allows you to override the executable's arguments. 'expandMacro' - Expand macros recursively. 'moveItem {up|down}' - Move items up or down. + 'codeAction' - Sometimes, rust-analyzer groups code actions by category, + which is not supported by Neovim's built-in |vim.lsp.buf.codeAction|. + This command provides a command with a UI that does. + If you set the option `vim.g.rustaceanvim.tools.code_actions.ui_select_fallback` + to `true` (defaults to `false`), it will fall back to |vim.ui.select| + if there are no grouped code actions. + + The default keymaps are `` to confirm a code action and `q` or `` to cancel + a selection. + You can modify these by defining `rustaceanvim.code_action.confirm` or + `rustaceanvim.code_action.quit` mappings. 'hover {actions|range}' - Hover actions, or hover over visually selected range. + You can invoke a hover action by switching to the hover window and entering `` + on the respective line, or with a keymap for the `RustHoverAction` mapping, + which accepts a `` prefix as the (1-based) index of the hover action to invoke. + + For example, if you set the keymap: `vim.keymap.set('n', 'a', 'RustHoverAction')`, + you can invoke the third hover action with `3a`. 'explainError {cycle?|current?}' - Display a hover window with explanations form the Rust error index. - If called with |cycle| or no args: Like |vim.diagnostic.goto_next|, diff --git a/lua/rustaceanvim/commands/code_action_group.lua b/lua/rustaceanvim/commands/code_action_group.lua index 6603958c..aefb3bbc 100644 --- a/lua/rustaceanvim/commands/code_action_group.lua +++ b/lua/rustaceanvim/commands/code_action_group.lua @@ -33,6 +33,39 @@ function M.apply_action(action, client, ctx) end end +---@class rustaceanvim.code_action_group.set_user_keymaps +---@field confirm boolean +---@field quit boolean + +---@class rustaceanvim.api.keyset.keymap: vim.api.keyset.keymap +---@field rhs string + +---@return rustaceanvim.code_action_group.set_user_keymaps +local function search_for_user_keymaps() + return vim + .iter(vim.api.nvim_get_keymap('n')) + :map(function(keymap) + return keymap.rhs + end) + :filter(function(rhs) + return type(rhs) == 'string' and vim.startswith(rhs, '') + end) + :fold( + {}, + ---@param acc rustaceanvim.code_action_group.set_user_keymaps + ---@param rhs string + function(acc, rhs) + if type(rhs) ~= 'string' then + return acc + end + return { + confirm = acc.confirm or rhs:find('rustaceanvim%.code_action%.confirm') ~= nil, + quit = acc.quit or rhs:find('rustaceanvim%.code_action%.quit') ~= nil, + } + end + ) +end + ---@alias action_tuple { [1]: number, [2]: rustaceanvim.RACodeAction|rustaceanvim.RACommand } ---@param action_tuple action_tuple | nil @@ -86,7 +119,7 @@ local function compute_width(action_tuples, is_group) return { width = width + 5 } end -local function on_primary_enter_press() +local function on_primary_confirm() if M.state.secondary.winnr then vim.api.nvim_set_current_win(M.state.secondary.winnr) return @@ -194,10 +227,30 @@ local function on_code_action_results(results, ctx) vim.api.nvim_buf_set_lines(M.state.primary.bufnr, 0, 1, false, {}) - vim.keymap.set('n', '', on_primary_enter_press, { buffer = M.state.primary.bufnr, noremap = true, silent = true }) + local user_keymaps = search_for_user_keymaps() - vim.keymap.set('n', 'q', on_primary_quit, { buffer = M.state.primary.bufnr, noremap = true, silent = true }) - vim.keymap.set('n', '', on_primary_quit, { buffer = M.state.primary.bufnr, noremap = true, silent = true }) + if user_keymaps.confirm then + vim.keymap.set( + 'n', + 'rustaceanvim.code_action.confirm', + on_primary_confirm, + { buffer = M.state.primary.bufnr, noremap = true, silent = true } + ) + else + vim.keymap.set('n', '', on_primary_confirm, { buffer = M.state.primary.bufnr, noremap = true, silent = true }) + end + + if user_keymaps.quit then + vim.keymap.set( + 'n', + 'rustaceanvim.code_action.quit', + on_primary_quit, + { buffer = M.state.primary.bufnr, noremap = true, silent = true } + ) + else + vim.keymap.set('n', 'q', on_primary_quit, { buffer = M.state.primary.bufnr, noremap = true, silent = true }) + vim.keymap.set('n', '', on_primary_quit, { buffer = M.state.primary.bufnr, noremap = true, silent = true }) + end M.codeactionify_window_buffer(M.state.primary.winnr, M.state.primary.bufnr) @@ -230,7 +283,7 @@ function M.codeactionify_window_buffer(winnr, bufnr) vim.wo[winnr].cul = true end -local function on_secondary_enter_press() +local function on_secondary_confirm() local line = vim.api.nvim_win_get_cursor(M.state.secondary.winnr)[1] local active_group = nil @@ -319,10 +372,40 @@ function M.on_cursor_move() M.codeactionify_window_buffer(M.state.secondary.winnr, M.state.secondary.bufnr) - vim.keymap.set('n', '', on_secondary_enter_press, { buffer = M.state.secondary.bufnr }) - - vim.keymap.set('n', 'q', on_secondary_quit, { buffer = M.state.secondary.bufnr }) + local user_keymaps = search_for_user_keymaps() + + if user_keymaps.confirm then + vim.keymap.set( + 'n', + 'rustaceanvim.code_action.confirm', + on_secondary_confirm, + { buffer = M.state.secondary.bufnr, noremap = true, silent = true } + ) + else + vim.keymap.set( + 'n', + '', + on_secondary_confirm, + { buffer = M.state.secondary.bufnr, noremap = true, silent = true } + ) + end + if user_keymaps.quit then + vim.keymap.set( + 'n', + 'rustaceanvim.code_action.quit', + on_secondary_quit, + { buffer = M.state.secondary.bufnr, noremap = true, silent = true } + ) + else + vim.keymap.set('n', 'q', on_secondary_quit, { buffer = M.state.secondary.bufnr, noremap = true, silent = true }) + vim.keymap.set( + 'n', + '', + on_secondary_quit, + { buffer = M.state.secondary.bufnr, noremap = true, silent = true } + ) + end return end diff --git a/lua/rustaceanvim/init.lua b/lua/rustaceanvim/init.lua index 351c6a16..6ebb5cc6 100644 --- a/lua/rustaceanvim/init.lua +++ b/lua/rustaceanvim/init.lua @@ -38,7 +38,24 @@ --- `args[]` allows you to override the executable's arguments. --- 'expandMacro' - Expand macros recursively. --- 'moveItem {up|down}' - Move items up or down. +--- 'codeAction' - Sometimes, rust-analyzer groups code actions by category, +--- which is not supported by Neovim's built-in |vim.lsp.buf.codeAction|. +--- This command provides a command with a UI that does. +--- If you set the option `vim.g.rustaceanvim.tools.code_actions.ui_select_fallback` +--- to `true` (defaults to `false`), it will fall back to |vim.ui.select| +--- if there are no grouped code actions. +--- +--- The default keymaps are `` to confirm a code action and `q` or `` to cancel +--- a selection. +--- You can modify these by defining `rustaceanvim.code_action.confirm` or +--- `rustaceanvim.code_action.quit` mappings. --- 'hover {actions|range}' - Hover actions, or hover over visually selected range. +--- You can invoke a hover action by switching to the hover window and entering `` +--- on the respective line, or with a keymap for the `RustHoverAction` mapping, +--- which accepts a `` prefix as the (1-based) index of the hover action to invoke. +--- +--- For example, if you set the keymap: `vim.keymap.set('n', 'a', 'RustHoverAction')`, +--- you can invoke the third hover action with `3a`. --- 'explainError {cycle?|current?}' - Display a hover window with explanations form the Rust error index. --- - If called with |cycle| or no args: --- Like |vim.diagnostic.goto_next|,