feat(buffer): preserve category fold state across re-renders

Problem: pressing :w, toggling priority, or any other operation that
calls buffer.render() reset foldlevel = 99, causing all manually
collapsed category sections to snap back open.

Solution: snapshot which categories are folded (per window) before
nvim_buf_set_lines destroys the fold tree, then restore them after
fold options are re-applied by calling normal! zc on each previously
closed header line. State persists across all render call sites
within a session.
This commit is contained in:
Barrett Ruth 2026-02-24 22:01:57 -05:00 committed by Barrett Ruth
parent fe15721c6f
commit 2482df0f0b

View file

@ -12,6 +12,8 @@ local task_ns = vim.api.nvim_create_namespace('pending')
local current_view = nil
---@type pending.LineMeta[]
local _meta = {}
---@type table<integer, table<string, boolean>>
local _fold_state = {}
---@return pending.LineMeta[]
function M.meta()
@ -148,6 +150,50 @@ local function setup_highlights()
vim.api.nvim_set_hl(0, 'PendingPriority', { link = 'DiagnosticWarn', default = true })
end
local function snapshot_folds(bufnr)
if current_view ~= 'category' then
return
end
for _, winid in ipairs(vim.fn.win_findbuf(bufnr)) do
local state = {}
vim.api.nvim_win_call(winid, function()
for lnum, m in ipairs(_meta) do
if m.type == 'header' and m.category then
if vim.fn.foldclosed(lnum) ~= -1 then
state[m.category] = true
end
end
end
end)
_fold_state[winid] = state
end
end
local function restore_folds(bufnr)
if current_view ~= 'category' then
return
end
for _, winid in ipairs(vim.fn.win_findbuf(bufnr)) do
local state = _fold_state[winid]
if not state or next(state) == nil then
goto continue
end
vim.api.nvim_win_call(winid, function()
vim.cmd('normal! zx')
local saved = vim.api.nvim_win_get_cursor(0)
for lnum, m in ipairs(_meta) do
if m.type == 'header' and m.category and state[m.category] then
vim.api.nvim_win_set_cursor(0, { lnum, 0 })
vim.cmd('normal! zc')
end
end
vim.api.nvim_win_set_cursor(0, saved)
end)
_fold_state[winid] = nil
::continue::
end
end
---@param bufnr? integer
function M.render(bufnr)
bufnr = bufnr or task_bufnr
@ -167,6 +213,7 @@ function M.render(bufnr)
_meta = line_meta
snapshot_folds(bufnr)
vim.bo[bufnr].modifiable = true
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
vim.bo[bufnr].modified = false
@ -185,6 +232,7 @@ function M.render(bufnr)
vim.wo[winid].foldenable = false
end
end
restore_folds(bufnr)
end
function M.toggle_view()