--- 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 ` + `ls` | | `file://` URI + pane is a shell + target is text file | `nvim [+line] ` | | `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