fix(buffer): fix stale extmarks, duplicate window, and fold state loss
Problem: Deleting lines (`dd`, `dat`, `d3j`) left extmarks stranded on adjacent rows since `render()` only clears and reapplies marks on `:w`. Quickfix `<CR>` opened the pending buffer in a second window because `BufEnter` did not redirect to `task_winid`. Category fold state was lost across `<Tab>/<Tab>` view toggles because `render()` overwrote the saved state with an empty snapshot taken while folds were disabled. Solution: Add a `TextChanged`/`TextChangedI` autocmd that clears the extmark namespace immediately on any edit. Fix `BufEnter` to close duplicate windows and redirect focus to `task_winid`, updating it when stale. Fix `snapshot_folds` to skip if a state is already saved, and `restore_folds` to always clear the saved state; snapshot in `toggle_view` before the view flips so the state survives the round-trip.
This commit is contained in:
parent
c392874311
commit
b41fab79a3
2 changed files with 43 additions and 1 deletions
|
|
@ -77,6 +77,18 @@ function M.clear_winid()
|
||||||
task_winid = nil
|
task_winid = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param winid integer
|
||||||
|
---@return nil
|
||||||
|
function M.update_winid(winid)
|
||||||
|
task_winid = winid
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param b? integer
|
||||||
|
---@return nil
|
||||||
|
function M.clear_marks(b)
|
||||||
|
vim.api.nvim_buf_clear_namespace(b or task_bufnr, task_ns, 0, -1)
|
||||||
|
end
|
||||||
|
|
||||||
---@return nil
|
---@return nil
|
||||||
function M.close()
|
function M.close()
|
||||||
if not task_winid or not vim.api.nvim_win_is_valid(task_winid) then
|
if not task_winid or not vim.api.nvim_win_is_valid(task_winid) then
|
||||||
|
|
@ -263,6 +275,9 @@ local function snapshot_folds(bufnr)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
for _, winid in ipairs(vim.fn.win_findbuf(bufnr)) do
|
for _, winid in ipairs(vim.fn.win_findbuf(bufnr)) do
|
||||||
|
if _fold_state[winid] ~= nil then
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
local state = {}
|
local state = {}
|
||||||
vim.api.nvim_win_call(winid, function()
|
vim.api.nvim_win_call(winid, function()
|
||||||
for lnum, m in ipairs(_meta) do
|
for lnum, m in ipairs(_meta) do
|
||||||
|
|
@ -274,6 +289,7 @@ local function snapshot_folds(bufnr)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
_fold_state[winid] = state
|
_fold_state[winid] = state
|
||||||
|
::continue::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -283,6 +299,7 @@ local function restore_folds(bufnr)
|
||||||
end
|
end
|
||||||
for _, winid in ipairs(vim.fn.win_findbuf(bufnr)) do
|
for _, winid in ipairs(vim.fn.win_findbuf(bufnr)) do
|
||||||
local state = _fold_state[winid]
|
local state = _fold_state[winid]
|
||||||
|
_fold_state[winid] = nil
|
||||||
if state and next(state) ~= nil then
|
if state and next(state) ~= nil then
|
||||||
vim.api.nvim_win_call(winid, function()
|
vim.api.nvim_win_call(winid, function()
|
||||||
vim.cmd('normal! zx')
|
vim.cmd('normal! zx')
|
||||||
|
|
@ -295,7 +312,6 @@ local function restore_folds(bufnr)
|
||||||
end
|
end
|
||||||
vim.api.nvim_win_set_cursor(0, saved)
|
vim.api.nvim_win_set_cursor(0, saved)
|
||||||
end)
|
end)
|
||||||
_fold_state[winid] = nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -372,6 +388,7 @@ end
|
||||||
|
|
||||||
---@return nil
|
---@return nil
|
||||||
function M.toggle_view()
|
function M.toggle_view()
|
||||||
|
snapshot_folds(task_bufnr)
|
||||||
if current_view == 'category' then
|
if current_view == 'category' then
|
||||||
current_view = 'priority'
|
current_view = 'priority'
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -224,12 +224,37 @@ function M._setup_autocmds(bufnr)
|
||||||
group = group,
|
group = group,
|
||||||
buffer = bufnr,
|
buffer = bufnr,
|
||||||
callback = function()
|
callback = function()
|
||||||
|
local cur_win = vim.api.nvim_get_current_win()
|
||||||
|
local tw = buffer.winid()
|
||||||
|
if tw and vim.api.nvim_win_is_valid(tw) and cur_win ~= tw then
|
||||||
|
local cursor = vim.api.nvim_win_get_cursor(cur_win)
|
||||||
|
vim.schedule(function()
|
||||||
|
if vim.api.nvim_win_is_valid(cur_win) and #vim.api.nvim_list_wins() > 1 then
|
||||||
|
pcall(vim.api.nvim_win_close, cur_win, false)
|
||||||
|
end
|
||||||
|
if vim.api.nvim_win_is_valid(tw) then
|
||||||
|
vim.api.nvim_set_current_win(tw)
|
||||||
|
pcall(vim.api.nvim_win_set_cursor, tw, cursor)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not tw or not vim.api.nvim_win_is_valid(tw) then
|
||||||
|
buffer.update_winid(cur_win)
|
||||||
|
end
|
||||||
if not vim.bo[bufnr].modified then
|
if not vim.bo[bufnr].modified then
|
||||||
get_store():load()
|
get_store():load()
|
||||||
buffer.render(bufnr)
|
buffer.render(bufnr)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
vim.api.nvim_create_autocmd({ 'TextChanged', 'TextChangedI' }, {
|
||||||
|
group = group,
|
||||||
|
buffer = bufnr,
|
||||||
|
callback = function()
|
||||||
|
buffer.clear_marks(bufnr)
|
||||||
|
end,
|
||||||
|
})
|
||||||
vim.api.nvim_create_autocmd('WinClosed', {
|
vim.api.nvim_create_autocmd('WinClosed', {
|
||||||
group = group,
|
group = group,
|
||||||
callback = function(ev)
|
callback = function(ev)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue