obsidian/wiki/dotfiles/wezterm-hyperlinks.md
2026-04-17 13:23:16 +01:00

111 lines
3.7 KiB
Markdown

---
title: "WezTerm Hyperlinks (OSC-8)"
aliases: [wezterm-osc8, terminal-hyperlinks, wezterm-clickable-links]
tags: [wezterm, hyperlinks, osc8, lua, terminal, neovim, fish]
sources: [raw/Use hyperlinks directly in the terminal - Wez's Terminal Emulator.md]
created: 2026-04-17
updated: 2026-04-17
---
## WezTerm Hyperlinks (OSC-8)
WezTerm supports clickable hyperlinks in the terminal via **OSC-8 escape sequences**. With the right config, clicking a file link opens it in Neovim; clicking a directory `cd`s into it.
## How It Works
Terminal apps emit hyperlinks using the OSC-8 protocol (`\e]8;;URL\e\\text\e]8;;\e\\`). WezTerm intercepts clicks on these links via the `open-uri` event in Lua.
## Enabling Hyperlinks in CLI Tools
By default, tools like `ls` don't emit OSC-8. Add these aliases:
```sh
alias ls='ls --hyperlink --color=auto'
alias delta="delta --hyperlinks --hyperlinks-file-link-format='file://{path}#{line}'"
alias rg='rg --hyperlink-format=kitty'
```
> **macOS**: GNU `ls` (coreutils) required — install via Homebrew, or use [[wiki/dotfiles/linux-terminal-ricing|eza]] instead.
## open-uri Handler
The core Lua snippet hooks into `wezterm.on('open-uri', ...)` to route `file://` links:
| Condition | Action |
|-----------|--------|
| `file://` URI + pane is a shell + target is directory | `cd <dir>` + `ls` |
| `file://` URI + pane is a shell + target is text file | `nvim [+line] <file>` |
| `file://` URI + pane is NOT a shell (SSH, etc.) | Fallback shell one-liner |
| Any other URI | WezTerm default behavior |
### Shell Detection
```lua
local function is_shell(foreground_process_name)
local shell_names = { 'bash', 'zsh', 'fish', 'sh', 'ksh', 'dash' }
local process = string.match(foreground_process_name, '[^/\\]+$')
or foreground_process_name
for _, shell in ipairs(shell_names) do
if process == shell then return true end
end
return false
end
```
Uses `pane:get_foreground_process_name()` — see [[wiki/dotfiles/wezterm-pane-to-lua|Pane to Lua]] for other pane data APIs.
### URI Format
`file://[HOSTNAME]/PATH[#linenr]` — the `#linenr` fragment is passed as `+N` to Neovim.
## Optional: Require CTRL to Click
Prevent accidental clicks by requiring a modifier:
```lua
config.mouse_bindings = {
{
event = { Up = { streak = 1, button = 'Left' } },
mods = 'CTRL',
action = act.OpenLinkAtMouseCursor,
},
-- Disable Down event to avoid weird behavior
{
event = { Down = { streak = 1, button = 'Left' } },
mods = 'CTRL',
action = act.Nop,
},
}
```
See [[wiki/dotfiles/wezterm-mouse-bindings|Mouse Bindings]] for full mouse config reference.
## tmux Users
Enable the hyperlinks terminal feature in tmux config:
```sh
set -sa terminal-features ",*:hyperlinks"
```
May also need `Shift`+click depending on mouse reporting settings.
## Key Takeaways
- OSC-8 hyperlinks let CLI tools (`ls`, `rg`, `delta`) emit clickable file/dir links
- WezTerm's `open-uri` Lua event intercepts `file://` URIs for smart routing
- Click directory → auto `cd` + `ls`; click text file → open in Neovim at correct line
- SSH/non-shell panes fall back to a portable shell one-liner (slightly clutters prompt)
- CTRL+click modifier is optional but prevents accidental navigation
- tmux requires `terminal-features` opt-in for hyperlinks to pass through
## Drawbacks
- Only works when the active pane is at an **empty shell prompt** — won't work inside vim, less, etc.
- Existing text in the prompt will be corrupted if a hyperlink is clicked mid-edit
- The non-shell fallback emits a long command visible in the terminal history
## Sources
- `raw/Use hyperlinks directly in the terminal - Wez's Terminal Emulator.md`
- Source URL: https://wezterm.org/recipes/hyperlinks.html