feat: follow the ACP agent edit and open files automatically (#2780)
This commit is contained in:
@@ -507,6 +507,9 @@ _See [config.lua#L9](./lua/avante/config.lua) for the full config_
|
||||
-- auto_approve_tool_permissions = {"bash", "replace_in_file"}, -- Auto-approve specific tools only
|
||||
---@type "popup" | "inline_buttons"
|
||||
confirmation_ui_style = "inline_buttons",
|
||||
--- Whether to automatically open files and navigate to lines when ACP agent makes edits
|
||||
---@type boolean
|
||||
acp_follow_agent_locations = true,
|
||||
},
|
||||
prompt_logger = { -- logs prompts to disk (timestamped, for replay/debugging)
|
||||
enabled = true, -- toggle logging entirely
|
||||
|
||||
@@ -529,6 +529,9 @@ M._defaults = {
|
||||
--- inline_buttons is the new inline buttons in the sidebar
|
||||
---@type "popup" | "inline_buttons"
|
||||
confirmation_ui_style = "inline_buttons",
|
||||
--- Whether to automatically open files and navigate to lines when ACP agent makes edits
|
||||
---@type boolean
|
||||
acp_follow_agent_locations = true,
|
||||
},
|
||||
prompt_logger = { -- logs prompts to disk (timestamped, for replay/debugging)
|
||||
enabled = true, -- toggle logging entirely
|
||||
|
||||
@@ -1005,6 +1005,7 @@ function M._stream_acp(opts)
|
||||
end)
|
||||
return
|
||||
end
|
||||
|
||||
if update.sessionUpdate == "agent_message_chunk" then
|
||||
if update.content.type == "text" then
|
||||
if opts.get_history_messages then
|
||||
@@ -1038,6 +1039,7 @@ function M._stream_acp(opts)
|
||||
on_messages_add({ message })
|
||||
end
|
||||
end
|
||||
|
||||
if update.sessionUpdate == "agent_thought_chunk" then
|
||||
if update.content.type == "text" then
|
||||
local messages = opts.get_history_messages()
|
||||
@@ -1065,7 +1067,75 @@ function M._stream_acp(opts)
|
||||
on_messages_add({ message })
|
||||
end
|
||||
end
|
||||
if update.sessionUpdate == "tool_call" then add_tool_call_message(update) end
|
||||
|
||||
if update.sessionUpdate == "tool_call" then
|
||||
add_tool_call_message(update)
|
||||
|
||||
local sidebar = require("avante").get()
|
||||
|
||||
if
|
||||
Config.behaviour.acp_follow_agent_locations
|
||||
and sidebar
|
||||
and not sidebar.is_in_full_view -- don't follow when in Zen mode
|
||||
and update.kind == "edit" -- to avoid entering more than once
|
||||
and update.locations
|
||||
and #update.locations > 0
|
||||
then
|
||||
vim.schedule(function()
|
||||
if not sidebar:is_open() then return end
|
||||
|
||||
-- Find a valid code window (non-sidebar window)
|
||||
local code_winid = nil
|
||||
if sidebar.code.winid and sidebar.code.winid ~= 0 and api.nvim_win_is_valid(sidebar.code.winid) then
|
||||
code_winid = sidebar.code.winid
|
||||
else
|
||||
-- Find first non-sidebar window in the current tab
|
||||
local all_wins = api.nvim_tabpage_list_wins(0)
|
||||
for _, winid in ipairs(all_wins) do
|
||||
if api.nvim_win_is_valid(winid) and not sidebar:is_sidebar_winid(winid) then
|
||||
code_winid = winid
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not code_winid then return end
|
||||
|
||||
local now = uv.now()
|
||||
local last_auto_nav = vim.g.avante_last_auto_nav or 0
|
||||
local grace_period = 2000
|
||||
|
||||
-- Check if user navigated manually recently
|
||||
if now - last_auto_nav < grace_period then return end
|
||||
|
||||
-- Only follow first location to avoid rapid jumping
|
||||
local location = update.locations[1]
|
||||
if not location or not location.path then return end
|
||||
|
||||
local abs_path = Utils.join_paths(Utils.get_project_root(), location.path)
|
||||
local bufnr = vim.fn.bufnr(abs_path, true)
|
||||
|
||||
if not bufnr or bufnr == -1 then return end
|
||||
|
||||
if not api.nvim_buf_is_loaded(bufnr) then pcall(vim.fn.bufload, bufnr) end
|
||||
|
||||
local ok = pcall(api.nvim_win_set_buf, code_winid, bufnr)
|
||||
if not ok then return end
|
||||
|
||||
local line = location.line or 1
|
||||
local line_count = api.nvim_buf_line_count(bufnr)
|
||||
local target_line = math.min(line, line_count)
|
||||
|
||||
pcall(api.nvim_win_set_cursor, code_winid, { target_line, 0 })
|
||||
pcall(api.nvim_win_call, code_winid, function()
|
||||
vim.cmd("normal! zz") -- Center line in viewport
|
||||
end)
|
||||
|
||||
vim.g.avante_last_auto_nav = now
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
if update.sessionUpdate == "tool_call_update" then
|
||||
local tool_call_message = tool_call_messages[update.toolCallId]
|
||||
if not tool_call_message then
|
||||
@@ -1102,6 +1172,7 @@ function M._stream_acp(opts)
|
||||
if tool_result_message then table.insert(messages, tool_result_message) end
|
||||
on_messages_add(messages)
|
||||
end
|
||||
|
||||
if update.sessionUpdate == "available_commands_update" then
|
||||
local commands = update.availableCommands
|
||||
local has_cmp, cmp = pcall(require, "cmp")
|
||||
@@ -1129,6 +1200,7 @@ function M._stream_acp(opts)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
on_request_permission = function(tool_call, options, callback)
|
||||
local sidebar = require("avante").get()
|
||||
if not sidebar then
|
||||
|
||||
@@ -85,7 +85,7 @@ Sidebar.__index = Sidebar
|
||||
---@field skip_line_count integer | nil
|
||||
---@field current_tool_use_extmark_id integer | nil
|
||||
---@field private win_size_store table<integer, {width: integer, height: integer}>
|
||||
---@field private is_in_full_view boolean
|
||||
---@field is_in_full_view boolean
|
||||
|
||||
---@param id integer the tabpage id retrieved from api.nvim_get_current_tabpage()
|
||||
function Sidebar:new(id)
|
||||
|
||||
Reference in New Issue
Block a user