feat(terminal): bare root-level filenames are clickable links - #177
feat(terminal): bare root-level filenames are clickable links#177ghackett wants to merge 1 commit into
Conversation
The path grammar demands a slash, so root-level references (README.md, pyproject.toml) never underlined. A shape can't take them — bare-filename shapes over-match prose — but an alternation of the names actually sitting at the project root can: the underline then only ever lands on a name that exists. bare_names_pattern builds that grammar (same boundary discipline and :line[:col] suffix as FILE_PATTERN, longest name first so an entry extending another wins), and _RootNameLinks keeps it registered per terminal — built on first map from the tab's link_root (the directory the editor opens at), rebuilt via a debounced directory monitor when the root's name set changes. Files only: root directory names are everyday prose words, and `docs/` already belongs to the path grammar. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KBnWBFL3yHBnJy4kupKZgk
|
@claude review |
|
Claude finished @ghackett's task in 3m 50s —— View job Review complete
(No Nicely done overall — the regex reasoning is careful and the docstrings actually explain the why (boundary discipline, longest-first ordering, the name-set-not-monitor-event debounce guard). I traced 1. The PR body's testing claims outrun what's actually in the diff. 2. "Debounced 500ms" is actually a leading-edge throttle, not a debounce. 3. Home-directory fallback widens 4. Minor: I wasn't able to actually execute Nothing here blocks merging — #1 and #3 are worth a sentence of clarification, #2 is a wording nit. |
Problem
Clickable file references (#173) require a slash:
collins/foo.py:12underlines, but root-level references likeREADME.mdorpyproject.toml— which Claude emits constantly — stay inert. The slash requirement exists for a good reason: a bare-filename shape (\w+\.\w+) would underlinee.g.,Node.js, and1.2.3in ordinary prose, and VTE has no per-match callback that would let the hover underline consult the filesystem.Approach
Match the actual names at the project root instead of a shape.
linkpatterns.bare_names_pattern(names)builds a PCRE2/re-shared alternation of literal names with the same boundary discipline asFILE_PATTERN::line[:col]suffix after;README.md.sheds its sentence period whileREADME.mdxnever half-matches an entryREADME.md;README.md.bakbeats its own prefix;:or/are unboundable/ambiguous and stay out (as agreed, spaces remain out of scope)._RootNameLinkskeeps the tag registered on each terminal (agent tab and shell-panel tabs alike):link_root— the directory the editor opens at (the tab's cwd, falling back to home), kept even when GtkSourceView is missing;Gio.FileMonitoron the root rebuilds the tag when the name set changes (debounced 500ms; content-only writes don't churn it), closing the staleness gap;docs,tests) are everyday prose words, anddocs/already belongs to the slashed grammar;"file"kind end-to-end:resolve_file_referencealready handles bare relative candidates, so images still hit the lightbox and text files open in the editor at the referenced line.Performance: VTE evaluates match regexes only against the row under the pointer, and PCRE2 compiles a literal alternation efficiently — a typical root is 15–40 entries, a few hundred bytes of pattern.
Testing
bare_names_pattern(matching, suffixes, trailing-punctuation shedding, half-match boundaries, longest-first ordering, metacharacter escaping, unboundable-name filtering).TerminalTab: map-time root resolution and tag registration, monitor-driven rebuild on a created file, no rebuild on content-only writes, monitor teardown on destroy — all pass.re.No screenshots: the change is a hover underline over live terminal rows, which an in-process snapshot can't show without synthetic pointer motion.
🤖 Generated with Claude Code
https://claude.ai/code/session_01KBnWBFL3yHBnJy4kupKZgk