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

3.7 KiB

title aliases tags sources created updated
WezTerm Hyperlinks (OSC-8)
wezterm-osc8
terminal-hyperlinks
wezterm-clickable-links
wezterm
hyperlinks
osc8
lua
terminal
neovim
fish
raw/Use hyperlinks directly in the terminal - Wez's Terminal Emulator.md
2026-04-17 2026-04-17

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 cds 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.

By default, tools like ls don't emit OSC-8. Add these aliases:

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 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

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 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:

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 for full mouse config reference.

tmux Users

Enable the hyperlinks terminal feature in tmux config:

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