feat(views): filter views (§8.2) — saved agenda slices
Some checks failed
Build / validate (pull_request) Failing after 18m44s

Make the owner's saved filters first-class so the agenda isn't one flat
list. `list` now takes a ListFilter predicate-as-data (heph-core::filter):
attention include/exclude sets, project-id scope, exclude_projects, and an
actionable do-date gate. New Store::view(name) resolves a built-in ViewSpec
— looking project names up to ids and subtree-expanding them through parent
links — then lists.

Five built-ins seeded from the Todoist queries (design §6.2.1): tom, ondeck,
chores, work, tasks (Schedule dropped — time-of-day isn't modeled on
date-grained do-dates). Surfaced as `heph view <name>` (no name lists them),
the `view` RPC + RemoteStore forward, and `:Heph view <name>` in nvim.

The list RPC/RemoteStore/CLI/heph.nvim migrate to the filter wire; legacy
--scope/--attention/--no-blue map onto it (nvim view.lua updated).

Tests: filter unit predicate, a views integration suite (subtree
scope+exclude, actionable gate, unknown-view error, absent-project empties),
a socket list/view dispatch test, two nvim e2e specs. 154 Rust tests + 18
nvim e2e green; clippy/fmt clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erich Blume 2026-06-03 06:39:07 -07:00
commit a5fc578525
20 changed files with 772 additions and 98 deletions

View file

@ -65,6 +65,14 @@ M.subs = {
list = function(args)
require("heph.view").list({ attention = args[1] })
end,
view = function(args)
local name = args[1]
if not name then
require("heph.util").notify("usage: :Heph view <tom|ondeck|chores|work|tasks>", vim.log.levels.WARN)
return
end
require("heph.view").view(name)
end,
capture = function(args)
local title = table.concat(args, " ")
if #title == 0 then