heph.nvim: RPC client + buffer editing + wiki-links + journal (slice 11a)
The primary surface begins (tech-spec §8): a Neovim plugin that is a thin
client of the local hephd over its unix-socket JSON-RPC.
- node.resolve {title} → Node|null (heph-core Store + dispatch): exact,
owner-scoped, non-tombstoned alias-then-title match — the same mapping that
materializes wiki links, so follow-link jumps to the node the stored link
points at (never fuzzy search). Unit + rpc_socket integration tests.
- heph.nvim/: vim.uv unix-socket JSON-RPC client (blocking call via vim.wait,
id-demuxed, partial-line buffered, luanil so JSON null → Lua nil; isolated
Sessions for tests). Buffer-backed nodes (heph://node/<id>, acwrite;
BufReadCmd→node.get / BufWriteCmd→node.update, whole-buffer body round-trips
exactly through the CRDT). [[wiki-link]] follow on <CR>. Daily journal.
:Heph command surface + completion.
- Headless e2e (§9): a self-contained busted-style runner (tests/e2e/runner.lua)
— no external plugins, no network, deterministic CI exit codes. Specs: journal
round-trip, follow-link (+ unresolved no-op), link-two-docs/backlink.
`make -C heph.nvim test` builds hephd and runs it.
Docs: heph-nvim reference card, §14 tracker (11a done; 11b/11c/11d queued),
changelog fragment.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 20:33:29 -07:00
|
|
|
--- Daily journal (tech-spec §8). `journal.open_or_create` is idempotent (the
|
|
|
|
|
--- node id is deterministic in (owner, date)), so opening today's note twice is
|
|
|
|
|
--- safe.
|
|
|
|
|
|
|
|
|
|
local rpc = require("heph.rpc")
|
|
|
|
|
local util = require("heph.util")
|
|
|
|
|
|
|
|
|
|
local M = {}
|
|
|
|
|
|
|
|
|
|
--- Open (creating if absent) the journal for `date` (default: today), in a
|
|
|
|
|
--- buffer. Returns the node.
|
|
|
|
|
function M.open(date)
|
|
|
|
|
date = date or util.iso_today()
|
|
|
|
|
local node = rpc.call("journal.open_or_create", { date = date })
|
|
|
|
|
require("heph.node").open(node.id)
|
|
|
|
|
return node
|
|
|
|
|
end
|
|
|
|
|
|
2026-06-02 11:26:45 -07:00
|
|
|
local function iso_to_time(iso)
|
|
|
|
|
local y, m, d = iso:match("(%d+)-(%d+)-(%d+)")
|
|
|
|
|
return os.time({ year = tonumber(y), month = tonumber(m), day = tonumber(d), hour = 12 })
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--- Entries for the `n` most recent days ending at `today` (ISO; default today),
|
|
|
|
|
--- newest first. Each: `{ date, node|nil, exists }`. Journals are titled by
|
|
|
|
|
--- their ISO date, so each day resolves directly.
|
|
|
|
|
function M.recent_entries(n, today)
|
|
|
|
|
today = (today and #today > 0) and today or util.iso_today()
|
|
|
|
|
local t0 = iso_to_time(today)
|
|
|
|
|
local entries = {}
|
|
|
|
|
for i = 0, n - 1 do
|
|
|
|
|
local date = os.date("%Y-%m-%d", t0 - i * 86400)
|
|
|
|
|
local node = rpc.call("node.resolve", { title = date })
|
|
|
|
|
entries[#entries + 1] = { date = date, node = node, exists = node ~= nil }
|
|
|
|
|
end
|
|
|
|
|
return entries
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--- Pick among recent journal days — existing days preview their content, new
|
|
|
|
|
--- days show `@create` — and open the chosen day's journal (creating if new).
|
|
|
|
|
function M.pick(opts)
|
|
|
|
|
opts = opts or {}
|
|
|
|
|
local days = opts.days or (require("heph").config or {}).journal_days or 7
|
|
|
|
|
require("heph.picker").select(M.recent_entries(days), {
|
|
|
|
|
prompt = "heph journals",
|
|
|
|
|
format = function(e)
|
|
|
|
|
return e.exists and e.date or (e.date .. " @create")
|
|
|
|
|
end,
|
|
|
|
|
preview = function(e)
|
|
|
|
|
if e.exists and e.node and e.node.body and #e.node.body > 0 then
|
|
|
|
|
return vim.split(e.node.body, "\n", { plain = true })
|
|
|
|
|
end
|
|
|
|
|
return { "@create — new journal for " .. e.date }
|
|
|
|
|
end,
|
|
|
|
|
}, function(e)
|
|
|
|
|
if e then
|
|
|
|
|
M.open(e.date)
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
end
|
|
|
|
|
|
heph.nvim: RPC client + buffer editing + wiki-links + journal (slice 11a)
The primary surface begins (tech-spec §8): a Neovim plugin that is a thin
client of the local hephd over its unix-socket JSON-RPC.
- node.resolve {title} → Node|null (heph-core Store + dispatch): exact,
owner-scoped, non-tombstoned alias-then-title match — the same mapping that
materializes wiki links, so follow-link jumps to the node the stored link
points at (never fuzzy search). Unit + rpc_socket integration tests.
- heph.nvim/: vim.uv unix-socket JSON-RPC client (blocking call via vim.wait,
id-demuxed, partial-line buffered, luanil so JSON null → Lua nil; isolated
Sessions for tests). Buffer-backed nodes (heph://node/<id>, acwrite;
BufReadCmd→node.get / BufWriteCmd→node.update, whole-buffer body round-trips
exactly through the CRDT). [[wiki-link]] follow on <CR>. Daily journal.
:Heph command surface + completion.
- Headless e2e (§9): a self-contained busted-style runner (tests/e2e/runner.lua)
— no external plugins, no network, deterministic CI exit codes. Specs: journal
round-trip, follow-link (+ unresolved no-op), link-two-docs/backlink.
`make -C heph.nvim test` builds hephd and runs it.
Docs: heph-nvim reference card, §14 tracker (11a done; 11b/11c/11d queued),
changelog fragment.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 20:33:29 -07:00
|
|
|
return M
|