feat: one-key linkify — write [[link]] into the source file (slice 3b) #8

Merged
fiatcode merged 8 commits from feat/linkify into main 2026-06-16 14:11:36 +07:00
Owner

Summary

Slice 3b — the write half of page-level connect, and peekseq's first writer to files other than the current page.

From the backlinks panel's Unlinked references section, press l on a mention → a before/after preview confirms (y writes, n/esc cancels) → the bare mention is wrapped as [[<matched>]] in its source file → the graph reindexes synchronously and the panel refreshes so the reference moves from unlinked to linked.

Design choices:

  • Casing preserved — wraps the author's bytes ([[alpha]] still resolves to Alpha via fold-keyed Resolve).
  • Authoritative re-match at write timegraph.LinkifyMention re-reads the file fresh and re-finds the first unlinked, whole-word, Unicode-aware occurrence on the raw line, splicing by absolute byte offset (CRLF + trailing-newline preserved; no double-wrap). It does NOT trust the offset captured when the panel opened, so a file changed since detection fails safely.
  • Failures render inside the panel (SetLinkifyError) — a status-bar hint would be invisible behind the overlay.

Spec: docs/superpowers/specs/2026-06-14-one-key-linkify-design.md
Plan: docs/superpowers/plans/2026-06-14-one-key-linkify.md

Test Plan

  • go vet ./... && go test ./... green
  • Unit: graph.LinkifyMention — casing, CRLF, no-trailing-newline, first-occurrence, skip-already-linked, whole-word, Unicode (Über/C++), out-of-range, regex-meta target
  • Overlay: confirm sub-state transitions, error line, dynamic hint, confirm-view golden
  • App e2e: b → ↓ → l → y writes [[…]] and refreshes panel; mention-gone leaves file untouched + shows in-panel error
  • Opus whole-branch review: brute-forced detection↔write occurrence parity (0 mismatches), verified byte-splice + Unicode folds
## Summary Slice 3b — the **write half** of page-level *connect*, and peekseq's first writer to files other than the current page. From the backlinks panel's **Unlinked references** section, press `l` on a mention → a before/after preview confirms (`y` writes, `n`/`esc` cancels) → the bare mention is wrapped as `[[<matched>]]` in its source file → the graph reindexes synchronously and the panel refreshes so the reference moves from unlinked to linked. Design choices: - **Casing preserved** — wraps the author's bytes (`[[alpha]]` still resolves to `Alpha` via fold-keyed `Resolve`). - **Authoritative re-match at write time** — `graph.LinkifyMention` re-reads the file fresh and re-finds the first unlinked, whole-word, Unicode-aware occurrence on the raw line, splicing by absolute byte offset (CRLF + trailing-newline preserved; no double-wrap). It does NOT trust the offset captured when the panel opened, so a file changed since detection fails safely. - **Failures render inside the panel** (`SetLinkifyError`) — a status-bar hint would be invisible behind the overlay. Spec: `docs/superpowers/specs/2026-06-14-one-key-linkify-design.md` Plan: `docs/superpowers/plans/2026-06-14-one-key-linkify.md` ## Test Plan - [x] `go vet ./... && go test ./...` green - [x] Unit: `graph.LinkifyMention` — casing, CRLF, no-trailing-newline, first-occurrence, skip-already-linked, whole-word, Unicode (`Über`/`C++`), out-of-range, regex-meta target - [x] Overlay: confirm sub-state transitions, error line, dynamic hint, confirm-view golden - [x] App e2e: `b → ↓ → l → y` writes `[[…]]` and refreshes panel; mention-gone leaves file untouched + shows in-panel error - [x] Opus whole-branch review: brute-forced detection↔write occurrence parity (0 mismatches), verified byte-splice + Unicode folds
Add Linkify/*LinkifyTarget* fields to OverlayResult so the App can
receive a linkify request. Add confirming/errMsg fields plus the l-key
confirm sub-state to Backlinks, and SetLinkifyError for App-side failure
feedback. Five new tests cover all confirm paths; all 20 backlinks tests
and the full suite pass.
docs: changelog entry for one-key linkify
All checks were successful
CI / vet-and-test (pull_request) Successful in 26s
05c863baec
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
fiatcode/weft!8
No description provided.