feat(terminal): cmd-click bare file paths to open them - #73
Open
jiweiyuan wants to merge 3 commits into
Open
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Agent CLIs print bare file references like `BranchModel.swift`, `src/foo.ts:42`, or `App.swift:88:15`. These are plain text — not OSC 8 hyperlinks and not a URL scheme — so libghostty's link detector never lights them up (its regex only matches real schemes, and Ghostty upstream has declined to add row/column parsing). VS Code makes the same paths clickable with its own terminalLinkParsing layer; what makes that layer stable rather than a false-positive machine is filesystem validation, not the regex. Mirror that shape: on a cmd-click that libghostty didn't resolve to a link, reconstruct the token under the click from the grid text (readViewportText), peel a trailing `:line[:col]`, resolve it against the surface's working directory, and open it in the read-only preview only if it resolves to a real file on disk. An imprecise click column or a stray word is silently dropped — every candidate on the row is validated and the nearest hit wins, so column precision is never load-bearing. - TerminalPathScanner: pure, tested token → path/line parsing + fs gate - TermioStore.openBarePathUnderCommandClick: click → cell → row → open, reusing the wrapper's own point→cell convention and the delegate-is-TerminalViewState surface lookup - wired as a fallback in the existing cmd-click monitor; the hovered-URL path (OSC 8 / detected URLs) is unchanged
Resolve a clicked bare path against multiple base dirs (live kernel cwd via PROC_PIDVNODEPATHINFO, session worktree, project root) instead of only the OSC 7 cwd, which is stale when the shell doesn't report it. Carries temporary [PATHCLICK] trace logging (to be removed before merge).
jiweiyuan
force-pushed
the
feat/clickable-file-paths
branch
from
July 24, 2026 20:03
cec3e5b to
07d2273
Compare
A path that contains a space (`Application Support/settings.json`, `my notes.md`) is torn in half by the whitespace split, so rejoin adjacent tokens into wider candidates — but only spans that cover the clicked column, so the widening can never wander onto a file the user never pointed at. Also try the shell-unescaped spelling, since a shell echoes `my\ file.ts` for a name that has no backslash on disk. Skip the fallback entirely on an `ssh` session: those paths live on the remote box, and `src/main.rs` exists on both machines, so resolving against the local filesystem would quietly open the wrong file. Drop the bring-up NSLog trace.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Makes bare file paths in terminal output — the kind agent CLIs print, like
BranchModel.swift,src/foo.ts:42,App.swift:88:15— cmd-clickable to open in the read-only preview at the referenced line. This is the gap versus VS Code, where the same paths are already clickable.Why they weren't clickable
libghostty only lights up a link when the program emits an OSC 8 hyperlink or the text matches its built-in URL regex (real schemes only:
http,file, …). A bare relative path is neither, and Ghostty upstream has explicitly declined to add row/column detection ("zero standardization"). SohoveredURLstays nil and termio's cmd-click interceptor has nothing to open.VS Code closes this gap with its own
terminalLinkParsinglayer. The thing that makes it stable — not a false-positive machine — is filesystem validation, not the regex. This PR mirrors that philosophy rather than Ghostty's regex.How
On a cmd-click that libghostty didn't resolve to a link (the new fallback; the OSC 8 / detected-URL path is unchanged):
surfaceSize.cell*Pixels / backingScaleFactor).readViewportText().:line[:col], strip wrapping punctuation, try git-diffa/ b/prefixes, expand~.Because validation is the gate, an off-by-one click column or a stray English word never opens the wrong thing; column precision is never load-bearing.
Files
TerminalPathScanner— pure, unit-tested token → path/line parsing + fs gateTermioStore.openBarePathUnderCommandClick— click → cell → row → open, reusing thedelegate == TerminalViewStatesurface lookup (same pattern asTerminalPane.terminalView(matching:))Tests
TerminalPathScannerTests(11 cases, against real temp files): bare/nested/absolute paths,:lineand:line:colpeeling, wrapping punctuation, git-diff prefix, nearest-column disambiguation, and the negative guards (nonexistent path, plain words, directory → no match). All green; fullswift buildclean.Not in this first version