refactor(sidebar): get rid of winids table, use containers table
Now that we have a table listing all containers and can iterate over it we no longer need a separate table with window IDs that we need to maintain. Remove it.
This commit is contained in:
@@ -35,6 +35,16 @@ local PRIORITY = (vim.hl or vim.highlight).priorities.user
|
|||||||
|
|
||||||
local RESP_SEPARATOR = "-------"
|
local RESP_SEPARATOR = "-------"
|
||||||
|
|
||||||
|
---This is a list of known sidebar containers or sub-windows. They are listed in
|
||||||
|
---the order they appear in the sidebar, from top to bottom.
|
||||||
|
local SIDEBAR_CONTAINERS = {
|
||||||
|
"result",
|
||||||
|
"selected_code",
|
||||||
|
"selected_files",
|
||||||
|
"todos",
|
||||||
|
"input",
|
||||||
|
}
|
||||||
|
|
||||||
---@class avante.Sidebar
|
---@class avante.Sidebar
|
||||||
local Sidebar = {}
|
local Sidebar = {}
|
||||||
Sidebar.__index = Sidebar
|
Sidebar.__index = Sidebar
|
||||||
@@ -49,7 +59,6 @@ Sidebar.__index = Sidebar
|
|||||||
---@field id integer
|
---@field id integer
|
||||||
---@field augroup integer
|
---@field augroup integer
|
||||||
---@field code avante.CodeState
|
---@field code avante.CodeState
|
||||||
---@field winids table<"result_container" | "todos_container" | "selected_code_container" | "selected_files_container" | "input_container", integer>
|
|
||||||
---@field containers { result?: NuiSplit, todos?: NuiSplit, selected_code?: NuiSplit, selected_files?: NuiSplit, input?: NuiSplit }
|
---@field containers { result?: NuiSplit, todos?: NuiSplit, selected_code?: NuiSplit, selected_files?: NuiSplit, input?: NuiSplit }
|
||||||
---@field file_selector FileSelector
|
---@field file_selector FileSelector
|
||||||
---@field chat_history avante.ChatHistory | nil
|
---@field chat_history avante.ChatHistory | nil
|
||||||
@@ -127,8 +136,6 @@ function Sidebar:reset()
|
|||||||
self:delete_containers()
|
self:delete_containers()
|
||||||
|
|
||||||
self.code = { bufnr = 0, winid = 0, selection = nil }
|
self.code = { bufnr = 0, winid = 0, selection = nil }
|
||||||
self.winids =
|
|
||||||
{ result_container = 0, selected_files_container = 0, selected_code_container = 0, input_container = 0 }
|
|
||||||
self.scroll = true
|
self.scroll = true
|
||||||
self.old_result_lines = {}
|
self.old_result_lines = {}
|
||||||
self.token_count = nil
|
self.token_count = nil
|
||||||
@@ -190,8 +197,9 @@ end
|
|||||||
|
|
||||||
function Sidebar:set_code_winhl()
|
function Sidebar:set_code_winhl()
|
||||||
if not self.code.winid or not api.nvim_win_is_valid(self.code.winid) then return end
|
if not self.code.winid or not api.nvim_win_is_valid(self.code.winid) then return end
|
||||||
|
if not self.containers.result or not api.nvim_win_is_valid(self.containers.result.winid) then return end
|
||||||
|
|
||||||
if Utils.should_hidden_border(self.code.winid, self.winids.result_container) then
|
if Utils.should_hidden_border(self.code.winid, self.containers.result.winid) then
|
||||||
Utils.debug("setting winhl")
|
Utils.debug("setting winhl")
|
||||||
local old_winhl = vim.wo[self.code.winid].winhl
|
local old_winhl = vim.wo[self.code.winid].winhl
|
||||||
if self.code.old_winhl == nil then
|
if self.code.old_winhl == nil then
|
||||||
@@ -923,18 +931,14 @@ local base_win_options = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Sidebar:render_header(winid, bufnr, header_text, hl, reverse_hl)
|
function Sidebar:render_header(winid, bufnr, header_text, hl, reverse_hl)
|
||||||
|
if not Config.windows.sidebar_header.enabled then return end
|
||||||
if not bufnr or not api.nvim_buf_is_valid(bufnr) then return end
|
if not bufnr or not api.nvim_buf_is_valid(bufnr) then return end
|
||||||
|
|
||||||
local is_result_win = self.winids.result_container == winid
|
local is_result_win = self.containers.result and self.containers.result.winid == winid
|
||||||
|
|
||||||
local separator_char = is_result_win and " " or "-"
|
local separator_char = is_result_win and " " or "-"
|
||||||
|
|
||||||
if not Config.windows.sidebar_header.enabled then return end
|
|
||||||
|
|
||||||
if not Config.windows.sidebar_header.rounded then header_text = " " .. header_text .. " " end
|
|
||||||
|
|
||||||
local win_width = vim.api.nvim_win_get_width(winid)
|
local win_width = vim.api.nvim_win_get_width(winid)
|
||||||
|
|
||||||
|
if not Config.windows.sidebar_header.rounded then header_text = " " .. header_text .. " " end
|
||||||
local padding = math.floor((win_width - #header_text) / 2)
|
local padding = math.floor((win_width - #header_text) / 2)
|
||||||
if Config.windows.sidebar_header.align ~= "center" then padding = win_width - #header_text end
|
if Config.windows.sidebar_header.align ~= "center" then padding = win_width - #header_text end
|
||||||
|
|
||||||
@@ -1205,7 +1209,7 @@ end
|
|||||||
|
|
||||||
---@param opts AskOptions
|
---@param opts AskOptions
|
||||||
function Sidebar:on_mount(opts)
|
function Sidebar:on_mount(opts)
|
||||||
self:refresh_winids()
|
self:setup_window_navigation(self.containers.result)
|
||||||
|
|
||||||
-- Add keymap to add current buffer while sidebar is open
|
-- Add keymap to add current buffer while sidebar is open
|
||||||
if Config.mappings.files and Config.mappings.files.add_current then
|
if Config.mappings.files and Config.mappings.files.add_current then
|
||||||
@@ -1390,10 +1394,13 @@ function Sidebar:on_mount(opts)
|
|||||||
group = self.augroup,
|
group = self.augroup,
|
||||||
callback = function(args)
|
callback = function(args)
|
||||||
local closed_winid = tonumber(args.match)
|
local closed_winid = tonumber(args.match)
|
||||||
if closed_winid == self.winids.selected_files_container then return end
|
if closed_winid then
|
||||||
if closed_winid == self.winids.todos_container then return end
|
local container = self:get_sidebar_window(closed_winid)
|
||||||
if not self:is_sidebar_winid(closed_winid) then return end
|
-- Ignore closing selected files and todos windows because they can disappear during normal operation
|
||||||
|
if container and container ~= self.containers.selected_files and container ~= self.containers.todos then
|
||||||
self:close()
|
self:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1404,63 +1411,75 @@ function Sidebar:on_mount(opts)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Sidebar:refresh_winids()
|
--- Given a desired container name, returns the window ID of the first valid container
|
||||||
self.winids = {}
|
--- situated above it in the sidebar's order.
|
||||||
for key, container in pairs(self.containers) do
|
--- @param container_name string The name of the container to start searching from.
|
||||||
if container.winid and api.nvim_win_is_valid(container.winid) then
|
--- @return integer|nil The window ID of the previous valid container, or nil.
|
||||||
self.winids[key .. "_container"] = container.winid
|
function Sidebar:get_split_candidate(container_name)
|
||||||
|
local start_index = 0
|
||||||
|
for i, name in ipairs(SIDEBAR_CONTAINERS) do
|
||||||
|
if name == container_name then
|
||||||
|
start_index = i
|
||||||
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local winids = {}
|
if start_index > 1 then
|
||||||
if self.winids.result_container then table.insert(winids, self.winids.result_container) end
|
for i = start_index - 1, 1, -1 do
|
||||||
if self.winids.selected_files_container then table.insert(winids, self.winids.selected_files_container) end
|
local container = self.containers[SIDEBAR_CONTAINERS[i]]
|
||||||
if self.winids.selected_code_container then table.insert(winids, self.winids.selected_code_container) end
|
if Utils.is_valid_container(container, true) then return container.winid end
|
||||||
if self.winids.todos_container then table.insert(winids, self.winids.todos_container) end
|
end
|
||||||
if self.winids.input_container then table.insert(winids, self.winids.input_container) end
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
local function switch_windows()
|
---Cycles focus over sidebar components.
|
||||||
local current_winid = api.nvim_get_current_win()
|
---@param direction "next" | "previous"
|
||||||
winids = vim.iter(winids):filter(function(winid) return api.nvim_win_is_valid(winid) end):totable()
|
function Sidebar:switch_window_focus(direction)
|
||||||
local current_idx = Utils.tbl_indexof(winids, current_winid) or 1
|
local current_winid = vim.api.nvim_get_current_win()
|
||||||
if current_idx == #winids then
|
local current_index = nil
|
||||||
current_idx = 1
|
local ordered_winids = {}
|
||||||
|
|
||||||
|
for _, name in ipairs(SIDEBAR_CONTAINERS) do
|
||||||
|
local container = self.containers[name]
|
||||||
|
if container and container.winid then
|
||||||
|
table.insert(ordered_winids, container.winid)
|
||||||
|
if container.winid == current_winid then current_index = #ordered_winids end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if current_index and #ordered_winids > 1 then
|
||||||
|
local next_index
|
||||||
|
if direction == "next" then
|
||||||
|
next_index = (current_index % #ordered_winids) + 1
|
||||||
|
elseif direction == "previous" then
|
||||||
|
next_index = current_index - 1
|
||||||
|
if next_index < 1 then next_index = #ordered_winids end
|
||||||
else
|
else
|
||||||
current_idx = current_idx + 1
|
error("Invalid 'direction' parameter: " .. direction)
|
||||||
end
|
|
||||||
local winid = winids[current_idx]
|
|
||||||
if winid and api.nvim_win_is_valid(winid) then pcall(api.nvim_set_current_win, winid) end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function reverse_switch_windows()
|
vim.api.nvim_set_current_win(ordered_winids[next_index])
|
||||||
local current_winid = api.nvim_get_current_win()
|
|
||||||
winids = vim.iter(winids):filter(function(winid) return api.nvim_win_is_valid(winid) end):totable()
|
|
||||||
local current_idx = Utils.tbl_indexof(winids, current_winid) or 1
|
|
||||||
if current_idx == 1 then
|
|
||||||
current_idx = #winids
|
|
||||||
else
|
|
||||||
current_idx = current_idx - 1
|
|
||||||
end
|
end
|
||||||
local winid = winids[current_idx]
|
|
||||||
if winid and api.nvim_win_is_valid(winid) then api.nvim_set_current_win(winid) end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, winid in ipairs(winids) do
|
---Sets up focus switching shortcuts for a sidebar component
|
||||||
local buf = api.nvim_win_get_buf(winid)
|
---@param container NuiSplit
|
||||||
|
function Sidebar:setup_window_navigation(container)
|
||||||
|
local buf = api.nvim_win_get_buf(container.winid)
|
||||||
Utils.safe_keymap_set(
|
Utils.safe_keymap_set(
|
||||||
{ "n", "i" },
|
{ "n", "i" },
|
||||||
Config.mappings.sidebar.switch_windows,
|
Config.mappings.sidebar.switch_windows,
|
||||||
function() switch_windows() end,
|
function() self:switch_window_focus("next") end,
|
||||||
{ buffer = buf, noremap = true, silent = true, nowait = true }
|
{ buffer = buf, noremap = true, silent = true, nowait = true }
|
||||||
)
|
)
|
||||||
Utils.safe_keymap_set(
|
Utils.safe_keymap_set(
|
||||||
{ "n", "i" },
|
{ "n", "i" },
|
||||||
Config.mappings.sidebar.reverse_switch_windows,
|
Config.mappings.sidebar.reverse_switch_windows,
|
||||||
function() reverse_switch_windows() end,
|
function() self:switch_window_focus("previous") end,
|
||||||
{ buffer = buf, noremap = true, silent = true, nowait = true }
|
{ buffer = buf, noremap = true, silent = true, nowait = true }
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
function Sidebar:resize()
|
function Sidebar:resize()
|
||||||
for _, container in pairs(self.containers) do
|
for _, container in pairs(self.containers) do
|
||||||
@@ -1506,13 +1525,20 @@ function Sidebar:is_focused_on_result()
|
|||||||
return self:is_open() and self.containers.result and self.containers.result.winid == api.nvim_get_current_win()
|
return self:is_open() and self.containers.result and self.containers.result.winid == api.nvim_get_current_win()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Sidebar:is_sidebar_winid(winid)
|
---Locates container object by its window ID
|
||||||
for _, stored_winid in pairs(self.winids) do
|
---@param winid integer
|
||||||
if stored_winid == winid then return true end
|
---@return NuiSplit|nil
|
||||||
|
function Sidebar:get_sidebar_window(winid)
|
||||||
|
for _, container in pairs(self.containers) do
|
||||||
|
if container and container.winid == winid then return container end
|
||||||
end
|
end
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Checks if a window with given ID belongs to the sidebar
|
||||||
|
---@param winid integer
|
||||||
|
---@return boolean
|
||||||
|
function Sidebar:is_sidebar_winid(winid) return self:get_sidebar_window(winid) ~= nil end
|
||||||
|
|
||||||
---@return boolean
|
---@return boolean
|
||||||
function Sidebar:should_auto_scroll()
|
function Sidebar:should_auto_scroll()
|
||||||
if not self.containers.result or not self.containers.result.winid then return false end
|
if not self.containers.result or not self.containers.result.winid then return false end
|
||||||
@@ -2117,17 +2143,18 @@ function Sidebar:create_selected_code_container()
|
|||||||
enter = false,
|
enter = false,
|
||||||
relative = {
|
relative = {
|
||||||
type = "win",
|
type = "win",
|
||||||
winid = self.containers.input.winid,
|
winid = self:get_split_candidate("selected_code"),
|
||||||
},
|
},
|
||||||
buf_options = buf_options,
|
buf_options = buf_options,
|
||||||
win_options = vim.tbl_deep_extend("force", base_win_options, {}),
|
win_options = vim.tbl_deep_extend("force", base_win_options, {}),
|
||||||
size = {
|
size = {
|
||||||
height = height,
|
height = height,
|
||||||
},
|
},
|
||||||
position = "top",
|
position = "bottom",
|
||||||
})
|
})
|
||||||
self.containers.selected_code:mount()
|
self.containers.selected_code:mount()
|
||||||
self:adjust_layout()
|
self:adjust_layout()
|
||||||
|
self:setup_window_navigation(self.containers.selected_code)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2703,6 +2730,7 @@ function Sidebar:create_input_container()
|
|||||||
vim.cmd("noautocmd stopinsert")
|
vim.cmd("noautocmd stopinsert")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:setup_window_navigation(self.containers.input)
|
||||||
self.containers.input:map("n", Config.mappings.submit.normal, on_submit)
|
self.containers.input:map("n", Config.mappings.submit.normal, on_submit)
|
||||||
self.containers.input:map("i", Config.mappings.submit.insert, on_submit)
|
self.containers.input:map("i", Config.mappings.submit.insert, on_submit)
|
||||||
self.containers.input:map("n", Config.prompt_logger.next_prompt.normal, PromptLogger.on_log_retrieve(-1))
|
self.containers.input:map("n", Config.prompt_logger.next_prompt.normal, PromptLogger.on_log_retrieve(-1))
|
||||||
@@ -2797,8 +2825,6 @@ function Sidebar:create_input_container()
|
|||||||
if ev.data and ev.data.request then handle_submit(ev.data.request) end
|
if ev.data and ev.data.request then handle_submit(ev.data.request) end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
self:refresh_winids()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param value string
|
---@param value string
|
||||||
@@ -2977,7 +3003,7 @@ function Sidebar:create_selected_files_container()
|
|||||||
enter = false,
|
enter = false,
|
||||||
relative = {
|
relative = {
|
||||||
type = "win",
|
type = "win",
|
||||||
winid = self.containers.input.winid,
|
winid = self:get_split_candidate("selected_files"),
|
||||||
},
|
},
|
||||||
buf_options = vim.tbl_deep_extend("force", buf_options, {
|
buf_options = vim.tbl_deep_extend("force", buf_options, {
|
||||||
modifiable = false,
|
modifiable = false,
|
||||||
@@ -2989,28 +3015,22 @@ function Sidebar:create_selected_files_container()
|
|||||||
win_options = vim.tbl_deep_extend("force", base_win_options, {
|
win_options = vim.tbl_deep_extend("force", base_win_options, {
|
||||||
fillchars = Config.windows.fillchars,
|
fillchars = Config.windows.fillchars,
|
||||||
}),
|
}),
|
||||||
position = "top",
|
position = "bottom",
|
||||||
size = {
|
size = {
|
||||||
height = 2,
|
height = 2,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
self.containers.selected_files:mount()
|
self.containers.selected_files:mount()
|
||||||
|
|
||||||
local function render()
|
local function render()
|
||||||
local selected_filepaths_ = self.file_selector:get_selected_filepaths()
|
local selected_filepaths_ = self.file_selector:get_selected_filepaths()
|
||||||
|
|
||||||
if #selected_filepaths_ == 0 then
|
if #selected_filepaths_ == 0 then
|
||||||
if Utils.is_valid_container(self.containers.selected_files) then
|
if Utils.is_valid_container(self.containers.selected_files) then self.containers.selected_files:unmount() end
|
||||||
self.containers.selected_files:unmount()
|
|
||||||
self:refresh_winids()
|
|
||||||
end
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if not Utils.is_valid_container(self.containers.selected_files, true) then
|
if not Utils.is_valid_container(self.containers.selected_files, true) then
|
||||||
self:create_selected_files_container()
|
self:create_selected_files_container()
|
||||||
self:refresh_winids()
|
|
||||||
if not Utils.is_valid_container(self.containers.selected_files, true) then
|
if not Utils.is_valid_container(self.containers.selected_files, true) then
|
||||||
Utils.warn("Failed to create or find selected files container window.")
|
Utils.warn("Failed to create or find selected files container window.")
|
||||||
return
|
return
|
||||||
@@ -3095,6 +3115,8 @@ function Sidebar:create_selected_files_container()
|
|||||||
-- Clear hint when leaving the window
|
-- Clear hint when leaving the window
|
||||||
self.containers.selected_files:on(event.BufLeave, function() self:close_selected_files_hint() end, {})
|
self.containers.selected_files:on(event.BufLeave, function() self:close_selected_files_hint() end, {})
|
||||||
|
|
||||||
|
self:setup_window_navigation(self.containers.selected_files)
|
||||||
|
|
||||||
render()
|
render()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3104,7 +3126,6 @@ function Sidebar:create_todos_container()
|
|||||||
if self.containers.todos then self.containers.todos:unmount() end
|
if self.containers.todos then self.containers.todos:unmount() end
|
||||||
self.containers.todos = nil
|
self.containers.todos = nil
|
||||||
self:adjust_layout()
|
self:adjust_layout()
|
||||||
self:refresh_winids()
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if not Utils.is_valid_container(self.containers.todos, true) then
|
if not Utils.is_valid_container(self.containers.todos, true) then
|
||||||
@@ -3112,7 +3133,7 @@ function Sidebar:create_todos_container()
|
|||||||
enter = false,
|
enter = false,
|
||||||
relative = {
|
relative = {
|
||||||
type = "win",
|
type = "win",
|
||||||
winid = self.containers.input.winid,
|
winid = self:get_split_candidate("todos"),
|
||||||
},
|
},
|
||||||
buf_options = vim.tbl_deep_extend("force", buf_options, {
|
buf_options = vim.tbl_deep_extend("force", buf_options, {
|
||||||
modifiable = false,
|
modifiable = false,
|
||||||
@@ -3124,12 +3145,13 @@ function Sidebar:create_todos_container()
|
|||||||
win_options = vim.tbl_deep_extend("force", base_win_options, {
|
win_options = vim.tbl_deep_extend("force", base_win_options, {
|
||||||
fillchars = Config.windows.fillchars,
|
fillchars = Config.windows.fillchars,
|
||||||
}),
|
}),
|
||||||
position = "top",
|
position = "bottom",
|
||||||
size = {
|
size = {
|
||||||
height = 3,
|
height = 3,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
self.containers.todos:mount()
|
self.containers.todos:mount()
|
||||||
|
self:setup_window_navigation(self.containers.todos)
|
||||||
end
|
end
|
||||||
local done_count = 0
|
local done_count = 0
|
||||||
local total_count = #history.todos
|
local total_count = #history.todos
|
||||||
@@ -3161,7 +3183,6 @@ function Sidebar:create_todos_container()
|
|||||||
Highlights.REVERSED_SUBTITLE
|
Highlights.REVERSED_SUBTITLE
|
||||||
)
|
)
|
||||||
self:adjust_layout()
|
self:adjust_layout()
|
||||||
self:refresh_winids()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Sidebar:adjust_layout()
|
function Sidebar:adjust_layout()
|
||||||
|
|||||||
@@ -190,17 +190,15 @@ function M:open()
|
|||||||
|
|
||||||
vim.keymap.set("n", Config.mappings.confirm.resp, function()
|
vim.keymap.set("n", Config.mappings.confirm.resp, function()
|
||||||
local sidebar = require("avante").get()
|
local sidebar = require("avante").get()
|
||||||
if not sidebar then return end
|
if sidebar and sidebar.containers.result and vim.api.nvim_win_is_valid(sidebar.containers.result.winid) then
|
||||||
if sidebar.winids.result_container and vim.api.nvim_win_is_valid(sidebar.winids.result_container) then
|
vim.api.nvim_set_current_win(sidebar.containers.result.winid)
|
||||||
vim.api.nvim_set_current_win(sidebar.winids.result_container)
|
|
||||||
end
|
end
|
||||||
end, { buffer = popup.bufnr, nowait = true })
|
end, { buffer = popup.bufnr, nowait = true })
|
||||||
|
|
||||||
vim.keymap.set("n", Config.mappings.confirm.input, function()
|
vim.keymap.set("n", Config.mappings.confirm.input, function()
|
||||||
local sidebar = require("avante").get()
|
local sidebar = require("avante").get()
|
||||||
if not sidebar then return end
|
if sidebar and sidebar.containers.input and vim.api.nvim_win_is_valid(sidebar.containers.input.winid) then
|
||||||
if sidebar.winids.input_container and vim.api.nvim_win_is_valid(sidebar.winids.input_container) then
|
vim.api.nvim_set_current_win(sidebar.containers.input.winid)
|
||||||
vim.api.nvim_set_current_win(sidebar.winids.input_container)
|
|
||||||
end
|
end
|
||||||
end, { buffer = popup.bufnr, nowait = true })
|
end, { buffer = popup.bufnr, nowait = true })
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user