diff --git a/README.md b/README.md index 0803c59..cd04d2a 100644 --- a/README.md +++ b/README.md @@ -262,6 +262,18 @@ _See [config.lua#L9](./lua/avante/config.lua) for the full config_ align = "center", -- left, center, right for title rounded = true, }, + input = { + prefix = "> ", + }, + edit = { + border = "rounded", + start_insert = true, -- Start insert mode when opening the edit window + }, + ask = { + floating = false, -- Open the 'AvanteAsk' prompt in a floating window + start_insert = true, -- Start insert mode when opening the ask window, only effective if floating = true. + border = "rounded", + }, }, highlights = { ---@type AvanteConflictHighlights diff --git a/lua/avante/api.lua b/lua/avante/api.lua index 2be7487..a0691d0 100644 --- a/lua/avante/api.lua +++ b/lua/avante/api.lua @@ -1,5 +1,6 @@ local Config = require("avante.config") local Utils = require("avante.utils") +local PromptInput = require("avante.prompt_input") ---@class avante.ApiToggle ---@operator call(): boolean @@ -88,6 +89,7 @@ end ---@field question? string optional questions ---@field win? table windows options similar to |nvim_open_win()| ---@field ask? boolean +---@field floating? boolean whether to open a floating input to enter the question ---@param opts? AskOptions M.ask = function(opts) @@ -97,10 +99,42 @@ M.ask = function(opts) opts = { question = opts } end - if not require("avante").toggle_sidebar(opts) then return false end - if opts.question == nil or opts.question == "" then return true end - vim.api.nvim_exec_autocmds("User", { pattern = "AvanteInputSubmitted", data = { request = opts.question } }) - return true + local has_question = opts.question ~= nil and opts.question ~= "" + + if Utils.is_sidebar_buffer(0) and not has_question then + require("avante").close_sidebar() + return false + end + + opts = vim.tbl_extend("force", { selection = Utils.get_visual_selection_and_range() }, opts) + + local function ask(input) + if input == nil or input == "" then input = opts.question end + local sidebar = require("avante").get() + if sidebar and sidebar:is_open() and sidebar.code.bufnr ~= vim.api.nvim_get_current_buf() then + sidebar:close({ goto_code_win = false }) + end + require("avante").open_sidebar(opts) + if input == nil or input == "" then return true end + vim.api.nvim_exec_autocmds("User", { pattern = "AvanteInputSubmitted", data = { request = input } }) + return true + end + + if opts.floating == true or (Config.windows.ask.floating == true and not has_question and opts.floating == nil) then + local prompt_input = PromptInput:new({ + submit_callback = function(input) ask(input) end, + close_on_submit = true, + win_opts = { + border = Config.options.windows.ask.border, + title = { { "ask", "FloatTitle" } }, + }, + start_insert = Config.options.windows.ask.start_insert, + }) + prompt_input:open() + return true + end + + return ask() end ---@param question? string diff --git a/lua/avante/config.lua b/lua/avante/config.lua index 501b9fd..2e6a221 100644 --- a/lua/avante/config.lua +++ b/lua/avante/config.lua @@ -172,6 +172,12 @@ Respect and use existing conventions, libraries, etc that are already present in }, edit = { border = "rounded", + start_insert = true, -- Start insert mode when opening the edit window + }, + ask = { + floating = false, -- Open the 'AvanteAsk' prompt in a floating window + border = "rounded", + start_insert = true, -- Start insert mode when opening the ask window }, }, --- @class AvanteConflictConfig diff --git a/lua/avante/init.lua b/lua/avante/init.lua index 0af23ee..b057240 100644 --- a/lua/avante/init.lua +++ b/lua/avante/init.lua @@ -357,6 +357,27 @@ M.toggle_sidebar = function(opts) return sidebar:toggle(opts) end +M.is_sidebar_open = function() + local sidebar = M.get() + if not sidebar then return false end + return sidebar:is_open() +end + +---@param opts? AskOptions +M.open_sidebar = function(opts) + opts = opts or {} + if opts.ask == nil then opts.ask = true end + local sidebar = M.get() + if not sidebar then M._init(api.nvim_get_current_tabpage()) end + M.current.sidebar:open(opts) +end + +M.close_sidebar = function() + local sidebar = M.get() + if not sidebar then return end + sidebar:close() +end + M.toggle.debug = H.api(Utils.toggle_wrap({ name = "debug", get = function() return Config.debug end, diff --git a/lua/avante/prompt_input.lua b/lua/avante/prompt_input.lua new file mode 100644 index 0000000..7fe5ea4 --- /dev/null +++ b/lua/avante/prompt_input.lua @@ -0,0 +1,316 @@ +local api = vim.api +local fn = vim.fn +local Config = require("avante.config") +local Utils = require("avante.utils") + +---@class PromptInput +---@field bufnr integer | nil +---@field winid integer | nil +---@field win_opts table +---@field shortcuts_hints_winid integer | nil +---@field augroup integer | nil +---@field start_insert boolean +---@field submit_callback function | nil +---@field cancel_callback function | nil +---@field close_on_submit boolean +---@field spinner_chars table +---@field spinner_index integer +---@field spinner_timer uv_timer_t | nil +---@field spinner_active boolean +local PromptInput = {} + +---@class PromptInputOptions +---@field start_insert? boolean +---@field submit_callback? fun(input: string):nil +---@field cancel_callback? fun():nil +---@field close_on_submit? boolean +---@field win_opts? table + +---@param opts? PromptInputOptions +function PromptInput:new(opts) + opts = opts or {} + local obj = setmetatable({}, { __index = self }) + obj.bufnr = nil + obj.winid = nil + obj.shortcuts_hints_winid = nil + obj.augroup = api.nvim_create_augroup("PromptInput", { clear = true }) + obj.start_insert = opts.start_insert or false + obj.submit_callback = opts.submit_callback + obj.cancel_callback = opts.cancel_callback + obj.close_on_submit = opts.close_on_submit or false + obj.win_opts = opts.win_opts + obj.spinner_chars = { + "⡀", + "⠄", + "⠂", + "⠁", + "⠈", + "⠐", + "⠠", + "⢀", + "⣀", + "⢄", + "⢂", + "⢁", + "⢈", + "⢐", + "⢠", + "⣠", + "⢤", + "⢢", + "⢡", + "⢨", + "⢰", + "⣰", + "⢴", + "⢲", + "⢱", + "⢸", + "⣸", + "⢼", + "⢺", + "⢹", + "⣹", + "⢽", + "⢻", + "⣻", + "⢿", + "⣿", + "⣶", + "⣤", + "⣀", + } + obj.spinner_index = 1 + obj.spinner_timer = nil + obj.spinner_active = false + return obj +end + +function PromptInput:open() + self:close() + + local bufnr = api.nvim_create_buf(false, true) + self.bufnr = bufnr + vim.bo[bufnr].filetype = "AvanteInput" + Utils.mark_as_sidebar_buffer(bufnr) + + local win_opts = vim.tbl_extend("force", { + relative = "cursor", + width = 40, + height = 2, + row = 1, + col = 0, + style = "minimal", + border = Config.windows.edit.border, + title = { { "Input", "FloatTitle" } }, + title_pos = "center", + }, self.win_opts) + + local winid = api.nvim_open_win(bufnr, true, win_opts) + self.winid = winid + + api.nvim_set_option_value("wrap", false, { win = winid }) + api.nvim_set_option_value("cursorline", true, { win = winid }) + api.nvim_set_option_value("modifiable", true, { buf = bufnr }) + + self:show_shortcuts_hints() + + self:setup_keymaps() + self:setup_autocmds() + + if self.start_insert then vim.cmd([[startinsert]]) end +end + +function PromptInput:close() + if not self.bufnr then return end + self:stop_spinner() + self:close_shortcuts_hints() + if api.nvim_get_mode().mode == "i" then vim.cmd([[stopinsert]]) end + if self.winid and api.nvim_win_is_valid(self.winid) then + api.nvim_win_close(self.winid, true) + self.winid = nil + end + if self.bufnr and api.nvim_buf_is_valid(self.bufnr) then + api.nvim_buf_delete(self.bufnr, { force = true }) + self.bufnr = nil + end + if self.augroup then + api.nvim_del_augroup_by_id(self.augroup) + self.augroup = nil + end +end + +function PromptInput:cancel() + self:close() + if self.cancel_callback then self.cancel_callback() end +end + +function PromptInput:submit(input) + if self.close_on_submit then self:close() end + if self.submit_callback then self.submit_callback(input) end +end + +function PromptInput:show_shortcuts_hints() + self:close_shortcuts_hints() + + if not self.winid or not api.nvim_win_is_valid(self.winid) then return end + + local win_width = api.nvim_win_get_width(self.winid) + local buf_height = api.nvim_buf_line_count(self.bufnr) + + local hint_text = (vim.fn.mode() ~= "i" and Config.mappings.submit.normal or Config.mappings.submit.insert) + .. ": submit" + + local display_text = hint_text + + if self.spinner_active then + local spinner = self.spinner_chars[self.spinner_index] + display_text = spinner .. " " .. hint_text + end + + local buf = api.nvim_create_buf(false, true) + api.nvim_buf_set_lines(buf, 0, -1, false, { display_text }) + vim.api.nvim_buf_add_highlight(buf, 0, "AvantePopupHint", 0, 0, -1) + + local width = fn.strdisplaywidth(display_text) + + local opts = { + relative = "win", + win = self.winid, + width = width, + height = 1, + row = buf_height, + col = math.max(win_width - width, 0), + style = "minimal", + border = "none", + focusable = false, + zindex = 100, + } + + self.shortcuts_hints_winid = api.nvim_open_win(buf, false, opts) +end + +function PromptInput:close_shortcuts_hints() + if self.shortcuts_hints_winid and api.nvim_win_is_valid(self.shortcuts_hints_winid) then + api.nvim_win_close(self.shortcuts_hints_winid, true) + self.shortcuts_hints_winid = nil + end +end + +function PromptInput:start_spinner() + self.spinner_active = true + self.spinner_index = 1 + + if self.spinner_timer then + self.spinner_timer:stop() + self.spinner_timer:close() + self.spinner_timer = nil + end + + self.spinner_timer = vim.loop.new_timer() + local spinner_timer = self.spinner_timer + + if self.spinner_timer then + self.spinner_timer:start(0, 100, function() + vim.schedule(function() + if not self.spinner_active or spinner_timer ~= self.spinner_timer then return end + self.spinner_index = (self.spinner_index % #self.spinner_chars) + 1 + self:show_shortcuts_hints() + end) + end) + end +end + +function PromptInput:stop_spinner() + self.spinner_active = false + if self.spinner_timer then + self.spinner_timer:stop() + self.spinner_timer:close() + self.spinner_timer = nil + end + self:show_shortcuts_hints() +end + +function PromptInput:setup_keymaps() + local bufnr = self.bufnr + + local function get_input() + local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false) + return lines[1] or "" + end + + vim.keymap.set( + "i", + Config.mappings.submit.insert, + function() self:submit(get_input()) end, + { buffer = bufnr, noremap = true, silent = true } + ) + + vim.keymap.set( + "n", + Config.mappings.submit.normal, + function() self:submit(get_input()) end, + { buffer = bufnr, noremap = true, silent = true } + ) + + vim.keymap.set("n", "", function() self:cancel() end, { buffer = bufnr }) + vim.keymap.set("n", "q", function() self:cancel() end, { buffer = bufnr }) +end + +function PromptInput:setup_autocmds() + local bufnr = self.bufnr + local group = self.augroup + + api.nvim_create_autocmd({ "TextChanged", "TextChangedI" }, { + group = group, + buffer = bufnr, + callback = function() self:show_shortcuts_hints() end, + }) + + api.nvim_create_autocmd("ModeChanged", { + group = group, + pattern = "i:*", + callback = function() + local cur_buf = api.nvim_get_current_buf() + if cur_buf == bufnr then self:show_shortcuts_hints() end + end, + }) + + api.nvim_create_autocmd("ModeChanged", { + group = group, + pattern = "*:i", + callback = function() + local cur_buf = api.nvim_get_current_buf() + if cur_buf == bufnr then self:show_shortcuts_hints() end + end, + }) + + local quit_id, close_unfocus + quit_id = api.nvim_create_autocmd("QuitPre", { + group = group, + buffer = bufnr, + once = true, + nested = true, + callback = function() + self:cancel() + if not quit_id then + api.nvim_del_autocmd(quit_id) + quit_id = nil + end + end, + }) + + close_unfocus = api.nvim_create_autocmd("WinLeave", { + group = group, + buffer = bufnr, + callback = function() + self:cancel() + if close_unfocus then + api.nvim_del_autocmd(close_unfocus) + close_unfocus = nil + end + end, + }) +end + +return PromptInput diff --git a/lua/avante/selection.lua b/lua/avante/selection.lua index 109292f..27307eb 100644 --- a/lua/avante/selection.lua +++ b/lua/avante/selection.lua @@ -3,6 +3,7 @@ local Config = require("avante.config") local Llm = require("avante.llm") local Provider = require("avante.providers") local RepoMap = require("avante.repo_map") +local PromptInput = require("avante.prompt_input") local api = vim.api local fn = vim.fn @@ -11,19 +12,14 @@ local NAMESPACE = api.nvim_create_namespace("avante_selection") local SELECTED_CODE_NAMESPACE = api.nvim_create_namespace("avante_selected_code") local PRIORITY = vim.highlight.priorities.user -local EDITING_INPUT_START_SPINNER_PATTERN = "AvanteEditingInputStartSpinner" -local EDITING_INPUT_STOP_SPINNER_PATTERN = "AvanteEditingInputStopSpinner" - ---@class avante.Selection ---@field selection avante.SelectionResult | nil ---@field cursor_pos table | nil ---@field shortcuts_extmark_id integer | nil ---@field selected_code_extmark_id integer | nil ---@field augroup integer | nil ----@field editing_input_bufnr integer | nil ----@field editing_input_winid integer | nil ----@field editing_input_shortcuts_hints_winid integer | nil ---@field code_winid integer | nil +---@field prompt_input PromptInput | nil local Selection = {} Selection.did_setup = false @@ -36,10 +32,8 @@ function Selection:new(id) augroup = api.nvim_create_augroup("avante_selection_" .. id, { clear = true }), selection = nil, cursor_pos = nil, - editing_input_bufnr = nil, - editing_input_winid = nil, - editing_input_shortcuts_hints_winid = nil, code_winid = nil, + prompt_input = nil, }, { __index = self }) end @@ -80,13 +74,11 @@ function Selection:close_shortcuts_hints_popup() end function Selection:close_editing_input() - self:close_editing_input_shortcuts_hints() - Llm.cancel_inflight_request() - if api.nvim_get_mode().mode == "i" then vim.cmd([[stopinsert]]) end - if self.editing_input_winid and api.nvim_win_is_valid(self.editing_input_winid) then - api.nvim_win_close(self.editing_input_winid, true) - self.editing_input_winid = nil + if self.prompt_input then + self.prompt_input:close() + self.prompt_input = nil end + Llm.cancel_inflight_request() if self.code_winid and api.nvim_win_is_valid(self.code_winid) then local code_bufnr = api.nvim_win_get_buf(self.code_winid) api.nvim_buf_clear_namespace(code_bufnr, SELECTED_CODE_NAMESPACE, 0, -1) @@ -105,156 +97,6 @@ function Selection:close_editing_input() api.nvim_win_set_cursor(self.code_winid, { row, col }) end) end - if self.editing_input_bufnr and api.nvim_buf_is_valid(self.editing_input_bufnr) then - api.nvim_buf_delete(self.editing_input_bufnr, { force = true }) - self.editing_input_bufnr = nil - end -end - -function Selection:close_editing_input_shortcuts_hints() - if self.editing_input_shortcuts_hints_winid and api.nvim_win_is_valid(self.editing_input_shortcuts_hints_winid) then - api.nvim_win_close(self.editing_input_shortcuts_hints_winid, true) - self.editing_input_shortcuts_hints_winid = nil - end -end - -function Selection:show_editing_input_shortcuts_hints() - self:close_editing_input_shortcuts_hints() - - if not self.editing_input_winid or not api.nvim_win_is_valid(self.editing_input_winid) then return end - - local win_width = api.nvim_win_get_width(self.editing_input_winid) - local buf_height = api.nvim_buf_line_count(self.editing_input_bufnr) - -- spinner string: "⡀⠄⠂⠁⠈⠐⠠⢀⣀⢄⢂⢁⢈⢐⢠⣠⢤⢢⢡⢨⢰⣰⢴⢲⢱⢸⣸⢼⢺⢹⣹⢽⢻⣻⢿⣿⣶⣤⣀" - local spinner_chars = { - "⡀", - "⠄", - "⠂", - "⠁", - "⠈", - "⠐", - "⠠", - "⢀", - "⣀", - "⢄", - "⢂", - "⢁", - "⢈", - "⢐", - "⢠", - "⣠", - "⢤", - "⢢", - "⢡", - "⢨", - "⢰", - "⣰", - "⢴", - "⢲", - "⢱", - "⢸", - "⣸", - "⢼", - "⢺", - "⢹", - "⣹", - "⢽", - "⢻", - "⣻", - "⢿", - "⣿", - "⣶", - "⣤", - "⣀", - } - local spinner_index = 1 - local timer = nil - - local hint_text = (vim.fn.mode() ~= "i" and Config.mappings.submit.normal or Config.mappings.submit.insert) - .. ": submit" - - local buf = api.nvim_create_buf(false, true) - api.nvim_buf_set_lines(buf, 0, -1, false, { hint_text }) - vim.api.nvim_buf_add_highlight(buf, 0, "AvantePopupHint", 0, 0, -1) - - local function update_spinner() - spinner_index = (spinner_index % #spinner_chars) + 1 - local spinner = spinner_chars[spinner_index] - local new_text = spinner .. " " .. hint_text - - api.nvim_buf_set_lines(buf, 0, -1, false, { new_text }) - - if - not self.editing_input_shortcuts_hints_winid - or not api.nvim_win_is_valid(self.editing_input_shortcuts_hints_winid) - then - return - end - - local win_config = vim.api.nvim_win_get_config(self.editing_input_shortcuts_hints_winid) - - local new_width = fn.strdisplaywidth(new_text) - - if win_config.width ~= new_width then - win_config.width = new_width - win_config.col = math.max(win_width - new_width, 0) - vim.api.nvim_win_set_config(self.editing_input_shortcuts_hints_winid, win_config) - end - end - - local function stop_spinner() - if timer then - timer:stop() - timer:close() - timer = nil - end - api.nvim_buf_set_lines(buf, 0, -1, false, { hint_text }) - - if - not self.editing_input_shortcuts_hints_winid - or not api.nvim_win_is_valid(self.editing_input_shortcuts_hints_winid) - then - return - end - - local win_config = vim.api.nvim_win_get_config(self.editing_input_shortcuts_hints_winid) - - if win_config.width ~= #hint_text then - win_config.width = #hint_text - win_config.col = math.max(win_width - #hint_text, 0) - vim.api.nvim_win_set_config(self.editing_input_shortcuts_hints_winid, win_config) - end - end - - api.nvim_create_autocmd("User", { - pattern = EDITING_INPUT_START_SPINNER_PATTERN, - callback = function() - timer = vim.uv.new_timer() - if timer then timer:start(0, 100, vim.schedule_wrap(function() update_spinner() end)) end - end, - }) - - api.nvim_create_autocmd("User", { - pattern = EDITING_INPUT_STOP_SPINNER_PATTERN, - callback = function() stop_spinner() end, - }) - - local width = fn.strdisplaywidth(hint_text) - - local opts = { - relative = "win", - win = self.editing_input_winid, - width = width, - height = 1, - row = buf_height, - col = math.max(win_width - width, 0), - style = "minimal", - border = "none", - focusable = false, - zindex = 100, - } - - self.editing_input_shortcuts_hints_winid = api.nvim_open_win(buf, false, opts) end function Selection:create_editing_input() @@ -266,9 +108,9 @@ function Selection:create_editing_input() end local code_bufnr = api.nvim_get_current_buf() - local code_wind = api.nvim_get_current_win() - self.cursor_pos = api.nvim_win_get_cursor(code_wind) - self.code_winid = code_wind + local code_winid = api.nvim_get_current_win() + self.cursor_pos = api.nvim_win_get_cursor(code_winid) + self.code_winid = code_winid local code_lines = api.nvim_buf_get_lines(code_bufnr, 0, -1, false) local code_content = table.concat(code_lines, "\n") @@ -303,58 +145,7 @@ function Selection:create_editing_input() priority = PRIORITY, }) - local bufnr = api.nvim_create_buf(false, true) - - self.editing_input_bufnr = bufnr - - local win_opts = { - relative = "cursor", - width = 40, - height = 2, - row = 1, - col = 0, - style = "minimal", - border = Config.windows.edit.border, - title = { { "edit selected block", "FloatTitle" } }, - title_pos = "center", - } - - local winid = api.nvim_open_win(bufnr, true, win_opts) - - self.editing_input_winid = winid - - api.nvim_set_option_value("wrap", false, { win = winid }) - api.nvim_set_option_value("cursorline", true, { win = winid }) - api.nvim_set_option_value("modifiable", true, { buf = bufnr }) - - self:show_editing_input_shortcuts_hints() - - api.nvim_create_autocmd({ "TextChanged", "TextChangedI" }, { - group = self.augroup, - buffer = bufnr, - callback = function() self:show_editing_input_shortcuts_hints() end, - }) - - api.nvim_create_autocmd("ModeChanged", { - group = self.augroup, - pattern = "i:*", - callback = function() - local cur_buf = api.nvim_get_current_buf() - if cur_buf == bufnr then self:show_editing_input_shortcuts_hints() end - end, - }) - - api.nvim_create_autocmd("ModeChanged", { - group = self.augroup, - pattern = "*:i", - callback = function() - local cur_buf = api.nvim_get_current_buf() - if cur_buf == bufnr then self:show_editing_input_shortcuts_hints() end - end, - }) - - ---@param input string - local function submit_input(input) + local submit_input = function(input) local full_response = "" local start_line = self.selection.range.start.line local finish_line = self.selection.range.finish.line @@ -363,7 +154,8 @@ function Selection:create_editing_input() local need_prepend_indentation = false - api.nvim_exec_autocmds("User", { pattern = EDITING_INPUT_START_SPINNER_PATTERN }) + self.prompt_input:start_spinner() + ---@type AvanteChunkParser local on_chunk = function(chunk) full_response = full_response .. chunk @@ -397,7 +189,7 @@ function Selection:create_editing_input() ) return end - api.nvim_exec_autocmds("User", { pattern = EDITING_INPUT_STOP_SPINNER_PATTERN }) + self.prompt_input:stop_spinner() vim.defer_fn(function() self:close_editing_input() end, 0) end @@ -422,63 +214,32 @@ function Selection:create_editing_input() }) end - ---@return string - local get_bufnr_input = function() - local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false) - return lines[1] or "" - end - - vim.keymap.set( - "i", - Config.mappings.submit.insert, - function() submit_input(get_bufnr_input()) end, - { buffer = bufnr, noremap = true, silent = true } - ) - vim.keymap.set( - "n", - Config.mappings.submit.normal, - function() submit_input(get_bufnr_input()) end, - { buffer = bufnr, noremap = true, silent = true } - ) - vim.keymap.set("n", "", function() self:close_editing_input() end, { buffer = bufnr }) - vim.keymap.set("n", "q", function() self:close_editing_input() end, { buffer = bufnr }) - - local quit_id, close_unfocus - quit_id = api.nvim_create_autocmd("QuitPre", { - group = self.augroup, - buffer = bufnr, - once = true, - nested = true, - callback = function() - self:close_editing_input() - if not quit_id then - api.nvim_del_autocmd(quit_id) - quit_id = nil - end - end, + local prompt_input = PromptInput:new({ + submit_callback = submit_input, + cancel_callback = function() self:close_editing_input() end, + win_opts = { + border = Config.windows.edit.border, + title = { { "edit selected block", "FloatTitle" } }, + }, + start_insert = Config.windows.edit.start_insert, }) - close_unfocus = api.nvim_create_autocmd("WinLeave", { - group = self.augroup, - buffer = bufnr, - callback = function() - self:close_editing_input() - if close_unfocus then - api.nvim_del_autocmd(close_unfocus) - close_unfocus = nil - end - end, - }) + self.prompt_input = prompt_input + + prompt_input:open() api.nvim_create_autocmd("InsertEnter", { group = self.augroup, - buffer = bufnr, + buffer = prompt_input.bufnr, once = true, desc = "Setup the completion of helpers in the input buffer", callback = function() local has_cmp, cmp = pcall(require, "cmp") if has_cmp then - cmp.register_source("avante_mentions", require("cmp_avante.mentions").new(Utils.get_mentions(), bufnr)) + cmp.register_source( + "avante_mentions", + require("cmp_avante.mentions").new(Utils.get_mentions(), prompt_input.bufnr) + ) cmp.setup.buffer({ enabled = true, sources = { @@ -488,13 +249,6 @@ function Selection:create_editing_input() end end, }) - - api.nvim_create_autocmd("User", { - pattern = "AvanteEditSubmitted", - callback = function(ev) - if ev.data and ev.data.request then submit_input(ev.data.request) end - end, - }) end function Selection:setup_autocmds() diff --git a/lua/avante/sidebar.lua b/lua/avante/sidebar.lua index b33d3aa..9afbcfc 100644 --- a/lua/avante/sidebar.lua +++ b/lua/avante/sidebar.lua @@ -65,18 +65,24 @@ function Sidebar:reset() self.input = nil end ----@param opts AskOptions +---@class SidebarOpenOptions: AskOptions +---@field selection? avante.SelectionResult + +---@param opts SidebarOpenOptions function Sidebar:open(opts) + opts = opts or {} local in_visual_mode = Utils.in_visual_mode() and self:in_code_win() if not self:is_open() then self:reset() self:initialize() + if opts.selection then self.code.selection = opts.selection end self:render(opts) else - if in_visual_mode then + if in_visual_mode or opts.selection then self:close() self:reset() self:initialize() + if opts.selection then self.code.selection = opts.selection end self:render(opts) return self end @@ -92,12 +98,19 @@ function Sidebar:open(opts) return self end -function Sidebar:close() +---@class SidebarCloseOptions +---@field goto_code_win? boolean + +---@param opts? SidebarCloseOptions +function Sidebar:close(opts) + opts = vim.tbl_extend("force", { goto_code_win = true }, opts or {}) self:delete_autocmds() for _, comp in pairs(self) do if comp and type(comp) == "table" and comp.unmount then comp:unmount() end end - if self.code and self.code.winid and api.nvim_win_is_valid(self.code.winid) then fn.win_gotoid(self.code.winid) end + if opts.goto_code_win and self.code and self.code.winid and api.nvim_win_is_valid(self.code.winid) then + fn.win_gotoid(self.code.winid) + end vim.cmd("wincmd =") end @@ -839,8 +852,6 @@ function Sidebar:on_mount(opts) self:render_input(opts.ask) self:render_selected_code() - self.augroup = api.nvim_create_augroup("avante_sidebar_" .. self.id .. self.result.winid, { clear = true }) - local filetype = api.nvim_get_option_value("filetype", { buf = self.code.bufnr }) if self.selected_code ~= nil then @@ -1570,6 +1581,7 @@ function Sidebar:create_input(opts) }) api.nvim_create_autocmd("User", { + group = self.augroup, pattern = "AvanteInputSubmitted", callback = function(ev) if ev.data and ev.data.request then handle_submit(ev.data.request) end @@ -1635,6 +1647,8 @@ function Sidebar:render(opts) self.result:mount() + self.augroup = api.nvim_create_augroup("avante_sidebar_" .. self.id .. self.result.winid, { clear = true }) + self.result:on(event.BufWinEnter, function() xpcall(function() api.nvim_buf_set_name(self.result.bufnr, RESULT_BUF_NAME) end, function(_) end) end)