refactor(buffer): update syntax, extmarks, and render for checkbox format

Problem: syntax patterns matched the old indent/[N] format; right_align
virtual text produced a broken layout in narrow windows; the done
strikethrough skipped past the '  ' indent leaving '- [x] ' unstyled;
render() added undo history entries so 'u' could undo a re-render.

Solution: update taskHeader/taskLine patterns for '## '/'- [.]'; rename
taskPriority -> taskCheckbox matching '[!]'; switch virt_text_pos to
'eol'; drop the +2 col_start offset so strikethrough covers '- [x] ';
guard nvim_buf_set_lines with undolevels=-1 so renders are not undoable.
Also fix open_line to insert '- [ ] ' and position cursor at col 6.
This commit is contained in:
Barrett Ruth 2026-02-24 23:14:53 -05:00
parent fe2ee47b5e
commit d243d5897a
2 changed files with 15 additions and 12 deletions

View file

@ -56,9 +56,9 @@ local function setup_syntax(bufnr)
vim.cmd([[ vim.cmd([[
syntax clear syntax clear
syntax match taskId /^\/\d\+\// conceal syntax match taskId /^\/\d\+\// conceal
syntax match taskHeader /^\S.*$/ contains=taskId syntax match taskHeader /^## .*$/ contains=taskId
syntax match taskPriority /\[\d\+\] / contained containedin=taskLine syntax match taskCheckbox /\[!\]/ contained containedin=taskLine
syntax match taskLine /^\/\d\+\/ .*$/ contains=taskId,taskPriority syntax match taskLine /^\/\d\+\/- \[.\] .*$/ contains=taskId,taskCheckbox
]]) ]])
end) end)
end end
@ -72,8 +72,8 @@ function M.open_line(above)
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
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, { '- [ ] ' })
vim.api.nvim_win_set_cursor(0, { insert_row + 1, 2 }) vim.api.nvim_win_set_cursor(0, { insert_row + 1, 6 })
vim.cmd('startinsert!') vim.cmd('startinsert!')
end end
@ -113,18 +113,18 @@ local function apply_extmarks(bufnr, line_meta)
if virt_text then if virt_text then
vim.api.nvim_buf_set_extmark(bufnr, task_ns, row, 0, { vim.api.nvim_buf_set_extmark(bufnr, task_ns, row, 0, {
virt_text = virt_text, virt_text = virt_text,
virt_text_pos = 'right_align', virt_text_pos = 'eol',
}) })
end end
elseif m.due then elseif m.due then
vim.api.nvim_buf_set_extmark(bufnr, task_ns, row, 0, { vim.api.nvim_buf_set_extmark(bufnr, task_ns, row, 0, {
virt_text = { { m.due, due_hl } }, virt_text = { { m.due, due_hl } },
virt_text_pos = 'right_align', virt_text_pos = 'eol',
}) })
end end
if m.status == 'done' then if m.status == 'done' then
local line = vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false)[1] or '' local line = vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false)[1] or ''
local col_start = line:find('/%d+/') and select(2, line:find('/%d+/')) + 2 or 0 local col_start = line:find('/%d+/') and select(2, line:find('/%d+/')) or 0
vim.api.nvim_buf_set_extmark(bufnr, task_ns, row, col_start, { vim.api.nvim_buf_set_extmark(bufnr, task_ns, row, col_start, {
end_col = #line, end_col = #line,
hl_group = 'PendingDone', hl_group = 'PendingDone',
@ -168,8 +168,11 @@ function M.render(bufnr)
_meta = line_meta _meta = line_meta
vim.bo[bufnr].modifiable = true vim.bo[bufnr].modifiable = true
local saved = vim.bo[bufnr].undolevels
vim.bo[bufnr].undolevels = -1
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
vim.bo[bufnr].modified = false vim.bo[bufnr].modified = false
vim.bo[bufnr].undolevels = saved
setup_syntax(bufnr) setup_syntax(bufnr)
apply_extmarks(bufnr, line_meta) apply_extmarks(bufnr, line_meta)

View file

@ -3,12 +3,12 @@ if exists('b:current_syntax')
endif endif
syntax match taskId /^\/\d\+\// conceal syntax match taskId /^\/\d\+\// conceal
syntax match taskHeader /^\S.*$/ contains=taskId syntax match taskHeader /^## .*$/ contains=taskId
syntax match taskPriority /!\ze / contained syntax match taskCheckbox /\[!\]/ contained containedin=taskLine
syntax match taskLine /^\/\d\+\/ .*$/ contains=taskId,taskPriority syntax match taskLine /^\/\d\+\/- \[.\] .*$/ contains=taskId,taskCheckbox
highlight default link taskHeader PendingHeader highlight default link taskHeader PendingHeader
highlight default link taskPriority PendingPriority highlight default link taskCheckbox PendingPriority
highlight default link taskLine Normal highlight default link taskLine Normal
let b:current_syntax = 'task' let b:current_syntax = 'task'