Skip to content

Configure tmux and keep the iTerm2 tab titles working inside it - #122

Open
mattmenefee wants to merge 1 commit into
mainfrom
add-tmux-configuration
Open

Configure tmux and keep the iTerm2 tab titles working inside it#122
mattmenefee wants to merge 1 commit into
mainfrom
add-tmux-configuration

Conversation

@mattmenefee

Copy link
Copy Markdown
Owner

Summary

  • Adds home/.tmux.conf, the first tmux configuration in this repo, and records tmux in the Brewfile — it was installed on this machine but never tracked, so a fresh machine got the ta alias without the binary behind it.
  • Fixes ta, which has never worked when no session was running: it falls back to tn, and nothing defined tn — not this repo, and not the oh-my-zsh tmux plugin (which is not in the plugin list and defines tksv/tl/tmuxconf/tds instead). Adds tn, plus tm for attach-or-create against a fixed session name.
  • Makes home/.zsh/iterm2-tab-title.zsh tmux-aware. Without this, adding a tmux config would have silently killed the tab titles: that file emits OSC 1, and tmux discards OSC 1 while acting on OSC 2. Titles now go out as OSC 2 inside a pane, and set-titles-string "#T" republishes them to iTerm2 unchanged. The SetUserVar sequence carrying the directory is wrapped in tmux's DCS passthrough for the same reason, which is what allow-passthrough on in the config enables.

On the config's contents

Most of it is conventional — mouse support, a large scrollback, 1-indexed windows that renumber on close, vi copy keys, splits that inherit the pane's directory, vim's home row for pane movement, and a status line on bg=default so it inherits the terminal background instead of fighting the active iTerm2 profile.

The settings were picked against tmux 3.7's measured defaults rather than the ones most guides still quote:

Setting Why it's here
escape-time 10 Already the default in current tmux, but it sat at 500ms for years. Pinned so an older tmux doesn't reintroduce a visible delay in front of every Esc.
mode-keys vi Already inferred from $EDITOR="mvim -v". Pinned so copy mode doesn't change keys if $EDITOR does.
set-clipboard on The outbound half (yank → terminal clipboard, including through SSH) already works at the default external. on adds the inbound half, letting an application in a pane populate a tmux buffer over OSC 52.
aggressive-resize on The one genuine behavior change: windows size to the smallest client actually viewing them rather than the smallest client attached at all, so a second, smaller client stops shrinking the first one's panes.

Note on activation

home/.tmux.conf is a new top-level file rather than a member of an already-symlinked directory, so it needs a homesick link run (or a single symlink) before it takes effect.

Test plan

  • tmux -f home/.tmux.conf new-session -d loads with no config errors on tmux 3.7c
  • ~/.tmux.conf symlink resolves, and a default-path tmux server reads back allow-passthrough=on, aggressive-resize=on, set-titles-string=#T — none of which are defaults
  • Inside tmux, _tab_title_idle sets pane_title to the git branch (main), and _tab_title_running rspec sets it to ▶ rspec
  • Outside tmux, _tab_title_emit emits the original OSC 1 byte-for-byte (^[]1;BRANCH^G)
  • OSC 1 vs OSC 2 handling confirmed empirically against a live tmux server rather than from the manual
  • All six zsh files pass zsh -n, the same gate CI runs
  • ta, tn, and tm all resolve in a fresh zsh
  • In a real iTerm2 window: a tab inside tmux shows the branch when idle and ▶ cmd while a command runs, and user.dir keeps updating through the DCS passthrough
  • brew bundle reconciles the new tmux entry

tmux has been installed and aliased here without ever being configured,
and without being recorded in the Brewfile, so a fresh machine got the
alias but not the binary behind it. That alias was broken in its own
right: `ta` falls back to `tn`, which no plugin or file ever defined —
not the oh-my-zsh tmux plugin, which is not in the plugin list and does
not define it either — so `ta` exited with "command not found: tn"
whenever there was no session to attach to.

Most of the new configuration is conventional: mouse support, a large
scrollback, 1-indexed windows that renumber on close, vi copy keys,
splits that inherit the pane's directory, vim's home row for moving
between panes, and a status line drawn on `bg=default` so it inherits
the terminal background rather than fighting whichever iTerm2 profile
is loaded.

Three settings were chosen against tmux's measured defaults rather than
its remembered ones. `escape-time` and `mode-keys` already hold the
wanted values here — the first because tmux lowered that default from
500ms only recently, the second because tmux reads vi from an $EDITOR
of `mvim -v` — and both are pinned so that neither an older tmux nor a
changed $EDITOR moves them. `set-clipboard` goes to `on` rather than
the default `external`, which adds only the inbound half, an
application in a pane populating a tmux buffer over OSC 52; the
outbound half that carries a yank back through SSH is already on by
default. `aggressive-resize` is the one that changes behavior
materially: windows size to the smallest client actually viewing them
instead of the smallest client attached at all, so a second, smaller
client stops shrinking the first one's panes.

Adding the config alone would have quietly broken the tab titles, which
is why home/.zsh/iterm2-tab-title.zsh changes here too. It emitted
OSC 1, and tmux discards OSC 1 while acting on OSC 2 — checked by
sending each to a live server and reading pane_title back rather than
by reading the manual. Inside a pane the title now goes out as OSC 2,
tmux keeps it as the pane title, and `set-titles-string "#T"`
republishes it to iTerm2 unchanged, so a tab still shows the branch
when idle and the running command otherwise, branch first. Outside tmux
the bytes are unchanged, OSC 1 still being the sequence that names a
tab without also retitling the window.

The SetUserVar sequence that publishes the directory fails inside tmux
for a different reason — tmux forwards only what it is told to — so it
is now wrapped in tmux's DCS passthrough, which `allow-passthrough on`
in the config enables. Both halves are needed: with either one missing
the titles freeze at whatever was set before tmux started, and nothing
says why.

`tm` joins the newly defined `tn` for attach-or-create against a fixed
session name, the form worth having when the reason to reach for tmux
is a connection that may drop.

home/.tmux.conf is a new top-level file rather than a member of an
already-symlinked directory, so it needs a `homesick link` run before
it takes effect.
@mattmenefee mattmenefee self-assigned this Aug 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant