Files
tty7/docs/terminal/links.mdx
T
l0ng-aiandl0ng-ai d343fd8a13 feat(links): open file links in tty7, resolved on the pane's own host (#568)
* feat(links): open file links in tty7, resolved on the pane's own host

A clicked file path now opens in the built-in editor at the line and
column the link named, and the Files panel reveals it; a directory link
opens the panel on that directory. Settings -> Terminal -> Links -> Open
files with picks between the built-in editor, the OS file association
and a command, migrating anyone who had already set link_file_command.

Detection is split into a filesystem-free candidate parser and a probe
callback, so a pane whose paths live on another machine resolves them
there instead of against the local filesystem -- an absolute path used
to open this machine's copy silently. A pane running ssh typed into a
local shell can answer for neither side and no longer offers file links
at all.

Relative paths are measured from the directory the work is happening in
(the agent's, not the shell's kernel cwd) and then from the repository
around it, and a path that matches nothing under either now says so
instead of the click doing nothing.

* fix(links): keep a remote path off the local openers, and off a dead end

Review follow-ups on the file-link work.

- A file resolved on another machine now opens in the built-in editor
  whatever `link_file_open` says. Under `system` or `command` the path was
  handed to a local `open` / `code --goto`, which threw away the resolution
  just done on the pane's host and silently showed this machine's copy — the
  same bug this branch set out to fix, left live for two of the three modes.
  A directory outside every tree root says so instead of opening a local file
  manager on a path that belongs to the far side.

- `flush_link_probes` takes the host before it takes the wanted paths.
  `take_wanted` moves them into the in-flight set on the promise that a call
  is carrying them; a host that had gone away broke that promise for good and
  left those paths permanently unanswered — no underline, and a click that
  says nothing.

- `~` no longer borrows this machine's `$HOME` for a pane whose paths are
  elsewhere. A cwd outside `/home` and `/Users` used to fall back to it, so
  `~/.zshrc` on a Linux box became `/Users/me/.zshrc` and was asked about —
  and possibly answered — over there.

- An unresolved absolute or `~`-rooted path no longer claims it was looked
  for under the pane's directory. It never was: roots are only for relative
  paths.

- A pending tree reveal counts down whether or not its row was found. A row
  that never reported bounds kept the request alive for good, re-issuing a
  scroll on every render and holding the column against a hand scroll.

- The repo root comes from `GitStatusCache` when the git-status probe has
  already asked about that directory, rather than a second round trip.

Tests: the migration `link_file_open` exists for (an old config with a
command lands on Command, one without on the editor), a probe with no host
staying wanted, and `~` refusing this machine's home for another one.

* test(links): only claim a leading slash is absolute where it is

`is_rooted` asks `Path::is_absolute`, the same question `FileCandidate::paths`
asks before it decides the roots do not apply — and on Windows `/etc/hosts`
answers no to both. The predicate is consistent; the assertion was not, so it
now lives in a unix-gated test of its own next to the untouched one.

---------

Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
2026-08-12 22:48:16 +08:00

79 lines
3.1 KiB
Plaintext

---
title: "Links"
description: "Opening URLs, files, and localhost ports straight out of the terminal."
---
Hold <kbd>⌘</kbd> (<kbd>Ctrl</kbd> on Windows and Linux) and links under the
pointer underline; click to open one.
## URLs
Anything that looks like a URL is detected, including one the shell wrapped
across two lines — tty7 stitches it back together before opening it.
Turn detection off with **Settings → Terminal → Links → Detect URLs**
(`link_url: false`).
## Files
A file path in the output — a compiler error, a test failure, a `grep -n` hit —
opens in tty7's own editor, on the line the link named, and the Files panel
selects it if it is open. A path to a directory opens the Files panel on it
instead.
Both absolute and relative paths are detected. A relative one is measured
against the directory the pane is working in, and then against the repository
around it — which is what makes a path a build tool printed from the workspace
root resolve while the shell sits in a member directory. A path that matches
nothing under either says so rather than doing nothing.
Paths in a pane connected to another machine are resolved *on that machine*,
so the underline appears a moment after the pointer settles rather than
instantly. A pane running `ssh` typed into a local shell has no host that can
answer for its paths, so file links are off there.
**Settings → Terminal → Links → Open files with** picks what a click opens:
| Mode | Opens in |
| --- | --- |
| Built-in editor | tty7's editor, at `:line:column`. The default. |
| Default app | Whatever the OS associates with the file type. |
| Command | A command of your own — see below. |
A file on another machine always opens in the built-in editor, whichever mode
is set: a path that was just resolved on the far side means nothing to a local
`open` or `code`, which would show this machine's copy of that path or nothing
at all.
Under **Command**, the command runs with placeholders substituted:
```
code --goto {path}:{line}:{column}
zed {path}:{line}
herdr edit {path} --line={line}
```
`{path}`, `{line}`, and `{column}` are filled in from the link. A flag whose
value is not available is dropped rather than passed empty — so
`--line={line}` simply disappears when the link had no line number.
The settings are `link_file_open` (`internal`, `system`, or `command`) and
`link_file_command` in `config.json`. A config written before `link_file_open`
existed keeps working: one that set a command stays on **Command**, and one
that did not moves to the built-in editor.
## localhost ports
<kbd>⌘</kbd>-clicking `localhost:3000` opens it in your browser, which is only
useful if the server is on this machine.
When the pane is inside an SSH session it usually is not. Turn on **Settings →
Terminal → Links → Forward SSH loopback links** (`ssh_loopback_forward: true`)
and tty7 opens a temporary port forward through that connection first, so the
link reaches the server on the remote machine.
<Tip>
For a forward you want to keep, set one up properly instead —
[port forwarding](/remote/port-forwarding).
</Tip>