--- Task list views (tech-spec §8): Tactical `next` (the "what is next?" ranking) --- and Organizational `list` (the whole outstanding set). Both render the same --- titled rows the daemon returns into a scratch buffer; `` opens the task --- under the cursor's canonical-context doc (the one-keystroke jump). local rpc = require("heph.rpc") local M = {} -- buf -> { tasks = }; line N maps to tasks[N]. M._views = {} local function row(t) local tag = t.attention and ("[" .. t.attention .. "]") or "[ ]" return string.format("%s %s", tag, t.title) end -- Find or create the named scratch buffer and fill it with task rows. local function render(name, tasks) local buf for _, b in ipairs(vim.api.nvim_list_bufs()) do if vim.api.nvim_buf_get_name(b) == name then buf = b break end end if not buf then buf = vim.api.nvim_create_buf(false, true) -- unlisted scratch vim.api.nvim_buf_set_name(buf, name) end vim.bo[buf].buftype = "nofile" vim.bo[buf].bufhidden = "hide" vim.bo[buf].swapfile = false local lines = {} for _, t in ipairs(tasks) do lines[#lines + 1] = row(t) end if #lines == 0 then lines = { "(nothing here)" } end vim.bo[buf].modifiable = true vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) vim.bo[buf].modifiable = false M._views[buf] = { tasks = tasks } vim.keymap.set("n", "", function() M.open_under_cursor(buf) end, { buffer = buf, desc = "heph: open task context" }) vim.api.nvim_set_current_buf(buf) return buf end --- Open the canonical-context doc of the task on the cursor line. function M.open_under_cursor(buf) buf = buf or vim.api.nvim_get_current_buf() local view = M._views[buf] if not view then return end local lnum = vim.api.nvim_win_get_cursor(0)[1] local t = view.tasks[lnum] if not t then return end require("heph.node").open(t.canonical_context_id or t.node_id) end --- Tactical "what is next?" — render the ranking, return the rows. function M.next(opts) opts = opts or {} local tasks = rpc.call("next", { scope = opts.scope, limit = opts.limit or 5 }) render("heph://next", tasks) return tasks end --- Organizational survey — render the outstanding set, return the rows. function M.list(opts) opts = opts or {} local tasks = rpc.call("list", { scope = opts.scope, attention = opts.attention, include_blue = opts.include_blue ~= false, }) render("heph://list", tasks) return tasks end return M