feat(file-token): file: inline metadata token with gf navigation (#45)

* feat(file-token): add file: inline metadata token with gf navigation

Problem: there was no way to link a task to a specific location in a
source file, or to quickly jump from a task to the relevant code.

Solution: add a file:<path>:<line> inline token that stores a relative
file reference in task._extra.file. Virtual text renders basename:line
in a new PendingFile highlight group. A buffer-local gf mapping
(configurable via keymaps.goto_file) opens the file at the given line.
M.add_here() lets users attach the current cursor position to any task
via vim.ui.select(). M.edit() gains -file support to clear the
reference. <Plug>(pending-goto-file) and <Plug>(pending-add-here) are
exposed for custom mappings.

* test(file-token): add parse, diff, views, edit, and navigation tests

Problem: the file: token implementation had no test coverage.

Solution: add spec/file_spec.lua covering parse.body extraction,
malformed token handling, duplicate token stop-parsing, diff
reconciliation (store/update/clear/round-trip), LineMeta population
in both views, :Pending edit -file, and goto_file notify paths for
no-file and unreadable-file cases. All 292 tests pass.

* style: apply stylua formatting

* fix(types): remove empty elseif block, fix file? annotation nullability
This commit is contained in:
Barrett Ruth 2026-02-26 19:12:48 -05:00 committed by GitHub
parent 994294393c
commit 1748e5caa1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 605 additions and 8 deletions

View file

@ -164,6 +164,10 @@ local function apply_extmarks(bufnr, line_meta)
if m.due then
table.insert(virt_parts, { m.due, due_hl })
end
if m.file then
local display = m.file:match('([^/]+:%d+)$') or m.file
table.insert(virt_parts, { display, 'PendingFile' })
end
if #virt_parts > 0 then
for p = 1, #virt_parts - 1 do
virt_parts[p][1] = virt_parts[p][1] .. ' '
@ -199,6 +203,7 @@ local function setup_highlights()
vim.api.nvim_set_hl(0, 'PendingPriority', { link = 'DiagnosticWarn', default = true })
vim.api.nvim_set_hl(0, 'PendingRecur', { link = 'DiagnosticInfo', default = true })
vim.api.nvim_set_hl(0, 'PendingFilter', { link = 'DiagnosticWarn', default = true })
vim.api.nvim_set_hl(0, 'PendingFile', { link = 'Directory', default = true })
end
local function snapshot_folds(bufnr)