# Hyperlinks (OSC 8)

> Make text a link, the way an anchor does in HTML.

- **Sequence:** `OSC 8 ; Pp ; Pu ST`
- **ECMA-48:** [§8.3.89 OSC – Operating System Command, p. 51](https://archive.org/details/ecma-48-5th-edition-june-1991/page/n64/mode/1up)

`OSC 8 ; Pp ; Pu ST` starts a link to the URI `Pu`, and the text written
after it is part of the link until `OSC 8 ; ; ST`, with an empty URI, ends
it. The text looks as it would anyway; what changes is that a terminal can
open the link when it is clicked, as `ls --hyperlink` and many compilers'
error messages expect. `Pp` is a list of `key=value` parameters separated by
`:`. The one in use is `id`: cells with the same `id` and URI are one link,
even when what is between them, such as an editor's border, is not.

It came from GNOME Terminal and has spread to most terminals, but not to
xterm. A default xterm has no OSC 8
([the OSC numbers it knows](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L3476-L3504)),
ignores it, and shows the text as plain text. The cases follow xterm.

libghostty-vt keeps the link with each cell it covers, which is what the
`link` word in an `attr` line checks. A link is not part of SGR: `CSI 0 m`
does not end it, and nor does a new line; only another OSC 8 does. The case
that checks for the link is a known difference.

## Validation

### OSC8-1: The text appears as usual

Input, one step per line:

```text
\e]8;;https://example.com/\e\\
AB
\e]8;;\e\\
C
```

Expected screen:

```text
|ABC___|
cursor 1,4
reply none
```

### OSC8-2: A default xterm makes no link

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e]8;id=1;https://example.com/\a
A
\e]8;;\a
B
```

Expected screen:

```text
|AB____|
attr 1,1 -link
```

### OSC8-3: After the end there is no link

Input, one step per line:

```text
\e]8;;https://example.com/\a
A
\e]8;;\a
B
```

Expected screen:

```text
|AB____|
attr 1,2 -link
```

---

This is the Markdown version of <https://control-codes.page/osc/hyperlink/>. On that page every validation case runs live in libghostty-vt, the terminal emulation core of Ghostty, compiled to WebAssembly.

The validation cases are written in the notation described in <https://control-codes.page/notation/index.html.md>.
