Maintaining secondary table of window IDs is cumbersome and is prone to getting out of sync with the true state of the sidebar. In preparation for removal of winids table move all containers (sub-windows of the sidebar) into "containers" table. The change is mostly mechanical rename with following exceptions: - Sidebar:reifresh_winids() and other places where the code scanned entire Sidebar object looking for tables with specific fields, such as "winid", or "mount" needed to be adjusted for the new structure - Sidebar:new() and Sidebar:reset() have been adjusted to make better use of the new sub-table.
171 lines
5.6 KiB
Lua
171 lines
5.6 KiB
Lua
local Utils = require("avante.utils")
|
|
local Path = require("plenary.path")
|
|
|
|
local M = {}
|
|
|
|
M.CANCEL_TOKEN = "__CANCELLED__"
|
|
|
|
-- Track cancellation state
|
|
M.is_cancelled = false
|
|
---@type avante.ui.Confirm
|
|
M.confirm_popup = nil
|
|
|
|
---@param rel_path string
|
|
---@return string
|
|
function M.get_abs_path(rel_path)
|
|
local project_root = Utils.get_project_root()
|
|
local p = Utils.join_paths(project_root, rel_path)
|
|
if p:sub(-2) == "/." then p = p:sub(1, -3) end
|
|
return p
|
|
end
|
|
|
|
---@param message string
|
|
---@param callback fun(yes: boolean, reason?: string)
|
|
---@param confirm_opts? { focus?: boolean }
|
|
---@param session_ctx? table
|
|
---@param tool_name? string -- Optional tool name to check against tool_permissions config
|
|
---@return avante.ui.Confirm | nil
|
|
function M.confirm(message, callback, confirm_opts, session_ctx, tool_name)
|
|
if session_ctx and session_ctx.always_yes then
|
|
callback(true)
|
|
return
|
|
end
|
|
|
|
-- Check behaviour.auto_approve_tool_permissions config for auto-approval
|
|
local Config = require("avante.config")
|
|
local auto_approve = Config.behaviour.auto_approve_tool_permissions
|
|
|
|
-- If auto_approve is true, auto-approve all tools
|
|
if auto_approve == true then
|
|
callback(true)
|
|
return
|
|
end
|
|
|
|
-- If auto_approve is a table (array of tool names), check if this tool is in the list
|
|
if type(auto_approve) == "table" and vim.tbl_contains(auto_approve, tool_name) then
|
|
callback(true)
|
|
return
|
|
end
|
|
local Confirm = require("avante.ui.confirm")
|
|
local sidebar = require("avante").get()
|
|
if not sidebar or not sidebar.containers.input or not sidebar.containers.input.winid then
|
|
Utils.error("Avante sidebar not found", { title = "Avante" })
|
|
callback(false)
|
|
return
|
|
end
|
|
confirm_opts = vim.tbl_deep_extend("force", { container_winid = sidebar.containers.input.winid }, confirm_opts or {})
|
|
if M.confirm_popup then M.confirm_popup:close() end
|
|
M.confirm_popup = Confirm:new(message, function(type, reason)
|
|
if type == "yes" then
|
|
callback(true)
|
|
elseif type == "all" then
|
|
if session_ctx then session_ctx.always_yes = true end
|
|
callback(true)
|
|
elseif type == "no" then
|
|
callback(false, reason)
|
|
end
|
|
M.confirm_popup = nil
|
|
end, confirm_opts)
|
|
M.confirm_popup:open()
|
|
return M.confirm_popup
|
|
end
|
|
|
|
---@param abs_path string
|
|
---@return boolean
|
|
local function old_is_ignored(abs_path)
|
|
local project_root = Utils.get_project_root()
|
|
local gitignore_path = project_root .. "/.gitignore"
|
|
local gitignore_patterns, gitignore_negate_patterns = Utils.parse_gitignore(gitignore_path)
|
|
-- The checker should only take care of the path inside the project root
|
|
-- Specifically, it should not check the project root itself
|
|
-- Otherwise if the binary is named the same as the project root (such as Go binary), any paths
|
|
-- insde the project root will be ignored
|
|
local rel_path = Utils.make_relative_path(abs_path, project_root)
|
|
return Utils.is_ignored(rel_path, gitignore_patterns, gitignore_negate_patterns)
|
|
end
|
|
|
|
---@param abs_path string
|
|
---@return boolean
|
|
function M.is_ignored(abs_path)
|
|
local project_root = Utils.get_project_root()
|
|
local cmd =
|
|
string.format("git -C %s check-ignore %s", vim.fn.shellescape(project_root), vim.fn.shellescape(abs_path))
|
|
|
|
local result = vim.fn.system(cmd)
|
|
local exit_code = vim.v.shell_error
|
|
|
|
-- If command failed or git is not available, fall back to old method
|
|
if exit_code ~= 0 and exit_code ~= 1 then return old_is_ignored(abs_path) end
|
|
|
|
-- Check if result indicates this is not a git repository
|
|
if result:sub(1, 26) == "fatal: not a git repository" then return old_is_ignored(abs_path) end
|
|
|
|
-- git check-ignore returns:
|
|
-- - exit code 0 and outputs the path if the file is ignored
|
|
-- - exit code 1 and no output if the file is not ignored
|
|
return exit_code == 0
|
|
end
|
|
|
|
---@param abs_path string
|
|
---@return boolean
|
|
function M.has_permission_to_access(abs_path)
|
|
if not Path:new(abs_path):is_absolute() then return false end
|
|
local project_root = Utils.get_project_root()
|
|
if abs_path:sub(1, #project_root) ~= project_root then return false end
|
|
return not M.is_ignored(abs_path)
|
|
end
|
|
|
|
---@param path string
|
|
---@return boolean
|
|
function M.already_in_context(path)
|
|
local sidebar = require("avante").get()
|
|
if sidebar and sidebar.file_selector then
|
|
local rel_path = Utils.uniform_path(path)
|
|
return vim.tbl_contains(sidebar.file_selector.selected_filepaths, rel_path)
|
|
end
|
|
return false
|
|
end
|
|
|
|
---@param path string
|
|
---@param session_ctx table
|
|
---@return boolean
|
|
function M.already_viewed(path, session_ctx)
|
|
local view_history = session_ctx.view_history or {}
|
|
local uniform_path = Utils.uniform_path(path)
|
|
if view_history[uniform_path] then return true end
|
|
return false
|
|
end
|
|
|
|
---@param path string
|
|
---@param session_ctx table
|
|
function M.mark_as_viewed(path, session_ctx)
|
|
local view_history = session_ctx.view_history or {}
|
|
local uniform_path = Utils.uniform_path(path)
|
|
view_history[uniform_path] = true
|
|
session_ctx.view_history = view_history
|
|
end
|
|
|
|
function M.mark_as_not_viewed(path, session_ctx)
|
|
local view_history = session_ctx.view_history or {}
|
|
local uniform_path = Utils.uniform_path(path)
|
|
view_history[uniform_path] = nil
|
|
session_ctx.view_history = view_history
|
|
end
|
|
|
|
---@param abs_path string
|
|
---@return integer bufnr
|
|
---@return string | nil error
|
|
function M.get_bufnr(abs_path)
|
|
local sidebar = require("avante").get()
|
|
if not sidebar then return 0, "Avante sidebar not found" end
|
|
local bufnr ---@type integer
|
|
vim.api.nvim_win_call(sidebar.code.winid, function()
|
|
---@diagnostic disable-next-line: param-type-mismatch
|
|
pcall(vim.cmd, "edit " .. abs_path)
|
|
bufnr = vim.api.nvim_get_current_buf()
|
|
end)
|
|
return bufnr, nil
|
|
end
|
|
|
|
return M
|