feat(buffer): track line changes via on_bytes to keep _meta aligned
Problem: `_meta` is a positional array keyed by line number. Line insertions and deletions during editing desync it from actual buffer content, breaking `get_fold()`, cursor-based task lookups, and extmark re-application. Solution: attach an `on_bytes` callback that adjusts `_meta` on line insertions/deletions and tracks dirty rows. Remove the manual `_meta` insert from `open_line()` since `on_bytes` now handles it. Reset dirty rows on each full render.
This commit is contained in:
parent
a12e5b5763
commit
db391c5715
1 changed files with 48 additions and 1 deletions
|
|
@ -26,6 +26,10 @@ local _initial_fold_loaded = false
|
|||
local _filter_predicates = {}
|
||||
---@type table<integer, true>
|
||||
local _hidden_ids = {}
|
||||
---@type table<integer, true>
|
||||
local _dirty_rows = {}
|
||||
---@type boolean
|
||||
local _on_bytes_active = false
|
||||
|
||||
---@return pending.LineMeta[]
|
||||
function M.meta()
|
||||
|
|
@ -95,6 +99,48 @@ function M.clear_marks(b)
|
|||
vim.api.nvim_buf_clear_namespace(bufnr, ns_inline, 0, -1)
|
||||
end
|
||||
|
||||
---@return table<integer, true>
|
||||
function M.dirty_rows()
|
||||
return _dirty_rows
|
||||
end
|
||||
|
||||
---@return nil
|
||||
function M.clear_dirty_rows()
|
||||
_dirty_rows = {}
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@return nil
|
||||
function M.attach_bytes(bufnr)
|
||||
if _on_bytes_active then
|
||||
return
|
||||
end
|
||||
_on_bytes_active = true
|
||||
vim.api.nvim_buf_attach(bufnr, false, {
|
||||
on_bytes = function(_, buf, _, start_row, _, _, old_end_row, _, _, new_end_row, _, _)
|
||||
if buf ~= task_bufnr then
|
||||
_on_bytes_active = false
|
||||
return true
|
||||
end
|
||||
local delta = new_end_row - old_end_row
|
||||
if delta > 0 then
|
||||
for _ = 1, delta do
|
||||
table.insert(_meta, start_row + 2, { type = 'task' })
|
||||
end
|
||||
elseif delta < 0 then
|
||||
for _ = 1, -delta do
|
||||
if _meta[start_row + 2] then
|
||||
table.remove(_meta, start_row + 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
for r = start_row + 1, start_row + 1 + math.max(0, new_end_row) do
|
||||
_dirty_rows[r] = true
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
---@return nil
|
||||
function M.persist_folds()
|
||||
log.debug(
|
||||
|
|
@ -208,7 +254,6 @@ function M.open_line(above)
|
|||
local insert_row = above and (row - 1) or row
|
||||
vim.bo[bufnr].modifiable = true
|
||||
vim.api.nvim_buf_set_lines(bufnr, insert_row, insert_row, false, { '- [ ] ' })
|
||||
table.insert(_meta, insert_row + 1, { type = 'task' })
|
||||
vim.api.nvim_win_set_cursor(0, { insert_row + 1, 6 })
|
||||
vim.cmd('startinsert!')
|
||||
end
|
||||
|
|
@ -452,6 +497,7 @@ function M.render(bufnr)
|
|||
end
|
||||
|
||||
_meta = line_meta
|
||||
_dirty_rows = {}
|
||||
|
||||
snapshot_folds(bufnr)
|
||||
vim.bo[bufnr].modifiable = true
|
||||
|
|
@ -511,6 +557,7 @@ function M.open()
|
|||
if not (task_bufnr and vim.api.nvim_buf_is_valid(task_bufnr)) then
|
||||
task_bufnr = vim.api.nvim_create_buf(true, false)
|
||||
set_buf_options(task_bufnr)
|
||||
M.attach_bytes(task_bufnr)
|
||||
end
|
||||
|
||||
vim.cmd('botright new')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue