feat: complete task editing coverage (#109)

Problem: the task editing surface had gaps — category and recurrence had
no keymaps, `:Pending edit` required knowing the task ID, tasks couldn't
be reordered with a keymap, priority was binary (0/1), and `wip`/`blocked`
states were documented but unimplemented.

Solution: fill every cell so every property is editable in every way.

- `gc`/`gr` keymaps for category select and recurrence prompt
- cursor-aware `:Pending edit` (omit ID to use task under cursor)
- `J`/`K` keymaps to reorder tasks within a category
- multi-level priorities (`max_priority` config, `g!` cycles 0→1→2→3→0)
- `+!!`/`+!!!` tokens in `:Pending edit`, `:Pending add`, `parse.body()`
- `PendingPriority2`/`PendingPriority3` highlight groups
- `gw`/`gb` keymaps toggle `wip`/`blocked` status
- `>`/`=` state chars in buffer rendering and diff parsing
- `PendingWip`/`PendingBlocked` highlight groups
- sort order: wip → pending → blocked → done
- `wip`/`blocked` filter predicates and icons
This commit is contained in:
Barrett Ruth 2026-03-08 19:44:03 -04:00 committed by GitHub
parent 073541424e
commit b06249f101
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 498 additions and 101 deletions

View file

@ -137,12 +137,27 @@ local function apply_inline_row(bufnr, row, m, icons)
end_col = #line,
hl_group = 'PendingDone',
})
elseif m.status == 'blocked' then
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+/')) or 0
vim.api.nvim_buf_set_extmark(bufnr, ns_inline, row, col_start, {
end_col = #line,
hl_group = 'PendingBlocked',
})
end
local line = vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false)[1] or ''
local bracket_col = (line:find('%[') or 1) - 1
local icon, icon_hl
if m.status == 'done' then
icon, icon_hl = icons.done, 'PendingDone'
elseif m.status == 'wip' then
icon, icon_hl = icons.wip or '>', 'PendingWip'
elseif m.status == 'blocked' then
icon, icon_hl = icons.blocked or '=', 'PendingBlocked'
elseif m.priority and m.priority >= 3 then
icon, icon_hl = icons.priority, 'PendingPriority3'
elseif m.priority and m.priority == 2 then
icon, icon_hl = icons.priority, 'PendingPriority2'
elseif m.priority and m.priority > 0 then
icon, icon_hl = icons.priority, 'PendingPriority'
else
@ -464,6 +479,10 @@ local function setup_highlights()
vim.api.nvim_set_hl(0, 'PendingOverdue', { link = 'DiagnosticError', default = true })
vim.api.nvim_set_hl(0, 'PendingDone', { link = 'Comment', default = true })
vim.api.nvim_set_hl(0, 'PendingPriority', { link = 'DiagnosticWarn', default = true })
vim.api.nvim_set_hl(0, 'PendingPriority2', { link = 'DiagnosticError', default = true })
vim.api.nvim_set_hl(0, 'PendingPriority3', { link = 'DiagnosticError', default = true })
vim.api.nvim_set_hl(0, 'PendingWip', { link = 'DiagnosticInfo', default = true })
vim.api.nvim_set_hl(0, 'PendingBlocked', { link = 'DiagnosticError', default = true })
vim.api.nvim_set_hl(0, 'PendingRecur', { link = 'DiagnosticInfo', default = true })
vim.api.nvim_set_hl(0, 'PendingFilter', { link = 'DiagnosticWarn', default = true })
end