fix(buffer): correct extmark drift on open_line for done tasks (#118)
* fix(config): update default keymaps to match vimdoc
Problem: four keymap defaults in `config.lua` still used the old
deprecated keys (`!`, `D`, `U`, `F`) while `doc/pending.txt` documents
the `g`-prefixed replacements (`g!`, `gd`, `gz`, `gf`).
Solution: update `priority`, `date`, `undo`, and `filter` defaults to
`g!`, `gd`, `gz`, and `gf` respectively.
* fix(buffer): correct extmark drift on `open_line` above/below done tasks
Problem: `open_line` used `nvim_buf_set_lines` which triggered `on_bytes`
with a `start_row` offset designed for native `o`/`O` keypresses. The
`_meta` entry was inserted one position too late, causing the done task's
`PendingDone` highlight to attach to the new blank line instead.
Solution: suppress `on_bytes` during `open_line` by reusing the
`_rendering` guard, insert the meta entry at the correct position, and
immediately reapply inline extmarks for the affected rows.
* fix(buffer): infer task status from line text in `reapply_dirty_inline`
Problem: `on_bytes` inserts bare `{ type = 'task' }` meta entries with
no `status` field for any new lines (paste, undo, native edits). When
meta positions also shift incorrectly (e.g. `P` paste above), existing
meta with the wrong status ends up on the wrong row. This causes done
tasks to lose their `PendingDone` highlight and pending tasks to appear
greyed out.
Solution: always re-infer `status` from the actual buffer line text for
dirty task rows before applying extmarks. The checkbox character (`[x]`,
`[>]`, `[=]`, `[ ]`) is the source of truth, with fallback to the
existing meta status if the line doesn't match a task pattern.
This commit is contained in:
parent
0c1f509129
commit
979c4339b8
1 changed files with 38 additions and 0 deletions
|
|
@ -182,6 +182,23 @@ local function apply_inline_row(bufnr, row, m, icons)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param line string
|
||||||
|
---@return string?
|
||||||
|
local function infer_status(line)
|
||||||
|
local ch = line:match('^/%d+/- %[(.)%]') or line:match('^- %[(.)%]')
|
||||||
|
if not ch then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if ch == 'x' then
|
||||||
|
return 'done'
|
||||||
|
elseif ch == '>' then
|
||||||
|
return 'wip'
|
||||||
|
elseif ch == '=' then
|
||||||
|
return 'blocked'
|
||||||
|
end
|
||||||
|
return 'pending'
|
||||||
|
end
|
||||||
|
|
||||||
---@param bufnr integer
|
---@param bufnr integer
|
||||||
---@return nil
|
---@return nil
|
||||||
function M.reapply_dirty_inline(bufnr)
|
function M.reapply_dirty_inline(bufnr)
|
||||||
|
|
@ -191,6 +208,10 @@ function M.reapply_dirty_inline(bufnr)
|
||||||
local icons = config.get().icons
|
local icons = config.get().icons
|
||||||
for row in pairs(_dirty_rows) do
|
for row in pairs(_dirty_rows) do
|
||||||
local m = _meta[row]
|
local m = _meta[row]
|
||||||
|
if m and m.type == 'task' then
|
||||||
|
local line = vim.api.nvim_buf_get_lines(bufnr, row - 1, row, false)[1] or ''
|
||||||
|
m.status = infer_status(line) or m.status
|
||||||
|
end
|
||||||
if m then
|
if m then
|
||||||
vim.api.nvim_buf_clear_namespace(bufnr, ns_inline, row - 1, row)
|
vim.api.nvim_buf_clear_namespace(bufnr, ns_inline, row - 1, row)
|
||||||
apply_inline_row(bufnr, row - 1, m, icons)
|
apply_inline_row(bufnr, row - 1, m, icons)
|
||||||
|
|
@ -345,8 +366,25 @@ function M.open_line(above)
|
||||||
end
|
end
|
||||||
local row = vim.api.nvim_win_get_cursor(0)[1]
|
local row = vim.api.nvim_win_get_cursor(0)[1]
|
||||||
local insert_row = above and (row - 1) or row
|
local insert_row = above and (row - 1) or row
|
||||||
|
local meta_pos = insert_row + 1
|
||||||
|
|
||||||
|
_rendering = true
|
||||||
vim.bo[bufnr].modifiable = true
|
vim.bo[bufnr].modifiable = true
|
||||||
vim.api.nvim_buf_set_lines(bufnr, insert_row, insert_row, false, { '- [ ] ' })
|
vim.api.nvim_buf_set_lines(bufnr, insert_row, insert_row, false, { '- [ ] ' })
|
||||||
|
_rendering = false
|
||||||
|
|
||||||
|
table.insert(_meta, meta_pos, { type = 'task' })
|
||||||
|
|
||||||
|
local icons = config.get().icons
|
||||||
|
local total = vim.api.nvim_buf_line_count(bufnr)
|
||||||
|
for r = meta_pos, math.min(meta_pos + 1, total) do
|
||||||
|
vim.api.nvim_buf_clear_namespace(bufnr, ns_inline, r - 1, r)
|
||||||
|
local m = _meta[r]
|
||||||
|
if m then
|
||||||
|
apply_inline_row(bufnr, r - 1, m, icons)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
vim.api.nvim_win_set_cursor(0, { insert_row + 1, 6 })
|
vim.api.nvim_win_set_cursor(0, { insert_row + 1, 6 })
|
||||||
vim.cmd('startinsert!')
|
vim.cmd('startinsert!')
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue