feat(mapping): plug and expose API (#346)

Signed-off-by: Aaron Pham <contact@aarnphm.xyz>
This commit is contained in:
Aaron Pham 2024-08-28 23:56:00 -04:00 committed by GitHub
parent 8a683b053b
commit 2e6a26240e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 201 additions and 57 deletions

View File

@ -26,6 +26,11 @@ Install `avante.nvim` using [lazy.nvim](https://github.com/folke/lazy.nvim):
opts = { opts = {
-- add any opts here -- add any opts here
}, },
keys = { -- See https://github.com/yetone/avante.nvim/wiki#keymaps for more info
{ "<leader>aa", function() require("avante.api").ask() end, desc = "avante: ask", mode = { "n", "v" } },
{ "<leader>ar", function() require("avante.api").refresh() end, desc = "avante: refresh", mode = "v" },
{ "<leader>ae", function() require("avante.api").edit() end, desc = "avante: edit", mode = { "n", "v" } },
},
dependencies = { dependencies = {
"stevearc/dressing.nvim", "stevearc/dressing.nvim",
"nvim-lua/plenary.nvim", "nvim-lua/plenary.nvim",
@ -94,9 +99,6 @@ _See [config.lua#L9](./lua/avante/config.lua) for the full config_
max_tokens = 4096, max_tokens = 4096,
}, },
mappings = { mappings = {
ask = "<leader>aa",
edit = "<leader>ae",
refresh = "<leader>ar",
--- @class AvanteConflictMappings --- @class AvanteConflictMappings
diff = { diff = {
ours = "co", ours = "co",
@ -113,10 +115,6 @@ _See [config.lua#L9](./lua/avante/config.lua) for the full config_
normal = "<CR>", normal = "<CR>",
insert = "<C-s>", insert = "<C-s>",
}, },
toggle = {
debug = "<leader>ad",
hint = "<leader>ah",
},
}, },
hints = { enabled = true }, hints = { enabled = true },
windows = { windows = {
@ -208,6 +206,11 @@ The following key bindings are available for use with `avante.nvim`:
| <kbd>[</kbd><kbd>[</kbd> | jump to previous codeblocks (results window) | | <kbd>[</kbd><kbd>[</kbd> | jump to previous codeblocks (results window) |
| <kbd>]</kbd><kbd>]</kbd> | jump to next codeblocks (results windows) | | <kbd>]</kbd><kbd>]</kbd> | jump to next codeblocks (results windows) |
> [!NOTE]
>
> If you are using `lazy.nvim`, then all keymap here will be safely set, meaning if `<leader>aa` is already binded, then avante.nvim won't bind this mapping.
> In this case, user will be responsible for setting up their own. See [notes on keymaps](https://github.com/yetone/avante.nvim/wiki#keymaps) for more details.
## Highlight Groups ## Highlight Groups

27
lua/avante/api.lua Normal file
View File

@ -0,0 +1,27 @@
local Utils = require("avante.utils")
---@class avante.ApiToggle
---@operator call(): boolean
---@field debug ToggleBind.wrap
---@field hint ToggleBind.wrap
---
---@class avante.Api
---@field ask fun(): boolean
---@field edit fun(): nil
---@field refresh fun(): nil
---@field toggle avante.ApiToggle
return setmetatable({}, {
__index = function(t, k)
local module = require("avante")
---@class AvailableApi: ApiCaller
---@field api? boolean
local has = module[k]
if type(has) ~= "table" or not has.api then
Utils.warn(k .. " is not a valid avante's API method", { once = true })
return
end
t[k] = has
return t[k]
end,
}) --[[@as avante.Api]]

View File

@ -88,9 +88,6 @@ M.defaults = {
}, },
}, },
mappings = { mappings = {
ask = "<leader>aa",
edit = "<leader>ae",
refresh = "<leader>ar",
---@class AvanteConflictMappings ---@class AvanteConflictMappings
diff = { diff = {
ours = "co", ours = "co",
@ -108,6 +105,10 @@ M.defaults = {
normal = "<CR>", normal = "<CR>",
insert = "<C-s>", insert = "<C-s>",
}, },
-- NOTE: The following will be safely set by avante.nvim
ask = "<leader>aa",
edit = "<leader>ae",
refresh = "<leader>ar",
toggle = { toggle = {
debug = "<leader>ad", debug = "<leader>ad",
hint = "<leader>ah", hint = "<leader>ah",

View File

@ -26,7 +26,7 @@ H.commands = function()
end end
cmd("Ask", function() cmd("Ask", function()
M.toggle() M.ask()
end, { desc = "avante: ask AI for code suggestions" }) end, { desc = "avante: ask AI for code suggestions" })
cmd("Close", function() cmd("Close", function()
local sidebar, _ = M._get() local sidebar, _ = M._get()
@ -35,34 +35,53 @@ H.commands = function()
end end
sidebar:close() sidebar:close()
end, { desc = "avante: close chat window" }) end, { desc = "avante: close chat window" })
cmd("Edit", function()
M.edit()
end, { desc = "avante: edit selected block" })
cmd("Refresh", function() cmd("Refresh", function()
M.refresh() M.refresh()
end, { desc = "avante: refresh windows" }) end, { desc = "avante: refresh windows" })
end end
H.keymaps = function() H.keymaps = function()
vim.keymap.set({ "n", "v" }, Config.mappings.ask, M.toggle, { noremap = true, desc = "avante: Ask" }) vim.keymap.set({ "n", "v" }, "<Plug>(AvanteAsk)", function()
vim.keymap.set("v", Config.mappings.edit, M.edit, { noremap = true, desc = "avante: Edit" }) M.ask()
vim.keymap.set("n", Config.mappings.refresh, M.refresh, { noremap = true, desc = "avante: Refresh" }) end, { noremap = true })
vim.keymap.set("v", "<Plug>(AvanteEdit)", function()
M.edit()
end, { noremap = true })
vim.keymap.set("n", "<Plug>(AvanteRefresh)", function()
M.refresh()
end, { noremap = true })
--- the following is kinda considered as internal mappings.
vim.keymap.set("n", "<Plug>(AvanteToggleDebug)", function()
M.toggle.debug()
end)
vim.keymap.set("n", "<Plug>(AvanteToggleHint)", function()
M.toggle.hint()
end)
Utils.toggle_map("n", Config.mappings.toggle.debug, { Utils.safe_keymap_set({ "n", "v" }, Config.mappings.ask, "<Plug>(AvanteAsk)", { desc = "avante: ask" })
name = "debug", Utils.safe_keymap_set("v", Config.mappings.edit, "<Plug>(AvanteEdit)", { desc = "avante: edit" })
get = function() Utils.safe_keymap_set("n", Config.mappings.refresh, "<Plug>(AvanteRefresh)", { desc = "avante: refresh" })
return Config.debug Utils.safe_keymap_set(
"n",
Config.mappings.toggle.debug,
"<Plug>(AvanteToggleDebug)",
{ desc = "avante: toggle debug" }
)
Utils.safe_keymap_set("n", Config.mappings.toggle.hint, "<Plug>(AvanteToggleHint)", { desc = "avante: toggle hint" })
end
---@class ApiCaller
---@operator call(...): any
H.api = function(fun)
return setmetatable({ api = true }, {
__call = function(...)
return fun(...)
end, end,
set = function(state) }) --[[@as ApiCaller]]
Config.override({ debug = state })
end,
})
Utils.toggle_map("n", Config.mappings.toggle.hint, {
name = "hint",
get = function()
return Config.hints.enabled
end,
set = function(state)
Config.override({ hints = { enabled = state } })
end,
})
end end
H.signs = function() H.signs = function()
@ -166,7 +185,31 @@ function M._init(id)
return M return M
end end
M.toggle = function() M.toggle = { api = true }
M.toggle.debug = H.api(Utils.toggle_wrap({
name = "debug",
get = function()
return Config.debug
end,
set = function(state)
Config.override({ debug = state })
end,
}))
M.toggle.hint = H.api(Utils.toggle_wrap({
name = "hint",
get = function()
return Config.hints.enabled
end,
set = function(state)
Config.override({ hints = { enabled = state } })
end,
}))
setmetatable(M.toggle, {
__index = M.toggle,
__call = function()
local sidebar, _ = M._get() local sidebar, _ = M._get()
if not sidebar then if not sidebar then
M._init(api.nvim_get_current_tabpage()) M._init(api.nvim_get_current_tabpage())
@ -175,17 +218,22 @@ M.toggle = function()
end end
return sidebar:toggle() return sidebar:toggle()
end end,
})
M.edit = function() M.ask = H.api(function()
M.toggle()
end)
M.edit = H.api(function()
local _, selection = M._get() local _, selection = M._get()
if not selection then if not selection then
return return
end end
selection:create_editing_input() selection:create_editing_input()
end end)
M.refresh = function() M.refresh = H.api(function()
local sidebar, _ = M._get() local sidebar, _ = M._get()
if not sidebar then if not sidebar then
return return
@ -213,7 +261,7 @@ M.refresh = function()
sidebar.code.winid = curwin sidebar.code.winid = curwin
sidebar.code.bufnr = curbuf sidebar.code.bufnr = curbuf
sidebar:render() sidebar:render()
end end)
---@param opts? avante.Config ---@param opts? avante.Config
function M.setup(opts) function M.setup(opts)

View File

@ -69,23 +69,88 @@ M.shell_run = function(input_cmd)
return { stdout = output, code = code } return { stdout = output, code = code }
end end
---@see https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/util/toggle.lua
---
---@alias _ToggleSet fun(state: boolean): nil ---@alias _ToggleSet fun(state: boolean): nil
---@alias _ToggleGet fun(): boolean ---@alias _ToggleGet fun(): boolean
--- ---
---@param lhs string ---@class ToggleBind
---@param toggle {name: string, set: _ToggleSet, get: _ToggleGet} ---@field name string
---@param mode? string | string[] ---@field set _ToggleSet
M.toggle_map = function(mode, lhs, toggle) ---@field get _ToggleGet
vim.keymap.set(mode or { "n" }, lhs, function() ---
---@class ToggleBind.wrap: ToggleBind
---@operator call:boolean
---@param toggle ToggleBind
M.toggle_wrap = function(toggle)
return setmetatable(toggle, {
__call = function()
toggle.set(not toggle.get()) toggle.set(not toggle.get())
local state = toggle.get() local state = toggle.get()
if state then if state then
M.info("enabled: " .. toggle.name, { title = "Avante" }) M.info("enabled: " .. toggle.name)
else else
M.warn("disabled: " .. toggle.name, { title = "Avante" }) M.warn("disabled: " .. toggle.name)
end end
return state return state
end, { desc = "toggle(avante): " .. toggle.name }) end,
}) --[[@as ToggleBind.wrap]]
end
---@param lhs string
---@param toggle ToggleBind
M.toggle_map = function(lhs, toggle)
M.safe_keymap_set("n", lhs, M.toggle_wrap(toggle), { desc = "toggle(avante): " .. toggle.name })
end
-- Wrapper around vim.keymap.set that will
-- not create a keymap if a lazy key handler exists.
-- It will also set `silent` to true by default.
--
---@param mode string|string[] Mode short-name, see |nvim_set_keymap()|.
--- Can also be list of modes to create mapping on multiple modes.
---@param lhs string Left-hand side |{lhs}| of the mapping.
---@param rhs string|function Right-hand side |{rhs}| of the mapping, can be a Lua function.
---
---@param opts? vim.keymap.set.Opts
---@see |nvim_set_keymap()|
---@see |maparg()|
---@see |mapcheck()|
---@see |mapset()|
M.safe_keymap_set = function(mode, lhs, rhs, opts)
---@type boolean
local ok
---@module "lazy.core.handler"
local H
ok, H = pcall(require, "lazy.core.handler")
if not ok then
M.warn("lazy.nvim is not available. Avante will use vim.keymap.set", { once = true })
vim.keymap.set(mode, lhs, rhs, opts)
return
end
local Keys = H.handlers.keys
---@cast Keys LazyKeysHandler
local modes = type(mode) == "string" and { mode } or mode
---@cast modes -string
---@param m string
modes = vim.tbl_filter(function(m)
return not (Keys.have and Keys:have(lhs, m))
end, modes)
-- don't create keymap if a lazy keys handler exists
if #modes > 0 then
opts = opts or {}
opts.silent = opts.silent ~= false
if opts.remap and not vim.g.vscode then
---@diagnostic disable-next-line: no-unknown
opts.remap = nil
end
vim.keymap.set(mode, lhs, rhs, opts)
end
end end
---@param str string ---@param str string