tmux-shorten-path

May 29, 2026 · View on GitHub

Latest release License: MIT tmux 3.0+ macOS · Linux

Folder-aware path shortening for tmux status bars. Inspired by Powerlevel10k.

/Users/johndoe/myproject/server/api/middleware/auth.go

~/myproject/s../api/mid../auth.go
   anchor↑    ↑       ↑
              long segments → shortest unique prefix among siblings

Demo

tmux-shorten-path in action

#{shorten_path} rendered in pane-border-format as the cwd changes, switches between panes, and moves across pre-made windows. See demo/ for the vhs tape and setup script.

Why

Long pane paths chew up the status bar. This plugin shortens them while keeping the project-relative part legible:

  1. Folder anchors — when a directory contains .git, package.json, go.mod, etc., the path from that directory onwards is kept full (so you always see where you are inside the project).
  2. Unique prefix truncation — segments before/around the anchor are shortened to the shortest prefix that doesn't collide with sibling directories, so middleware becomes mid.. only if migrations exists alongside it; otherwise just m...

tmux has no built-in equivalent.

Install

Using TPM, add to ~/.tmux.conf:

set -g @plugin 'Amdhj22/tmux-shorten-path'

Then prefix + I to install.

Manual install:

git clone https://github.com/Amdhj22/tmux-shorten-path ~/.tmux/plugins/tmux-shorten-path
echo "run-shell ~/.tmux/plugins/tmux-shorten-path/shorten_path.tmux" >> ~/.tmux.conf

Usage

Use #{shorten_path} anywhere in status-left, status-right, window-status-format, window-status-current-format, or pane-border-format. The plugin rewrites it to a shell call at load time:

set -g status-left "#{shorten_path} | #S #I:#P "

Reload tmux config — the placeholder is replaced with the current pane's shortened path.

Options

Set before the run-shell (or set -g @plugin) line.

OptionDefaultDescription
@shorten_path_strategytruncate_to_uniqueOne of truncate_to_unique, truncate_from_right, truncate_to_last, none.
@shorten_path_seg_threshold5(truncate_to_unique) Only truncate segments longer than this.
@shorten_path_seg_length1(truncate_from_right) Chars kept per non-last segment. Hidden dirs get +1.
@shorten_path_markers.git .hg .svn .bzr CVS _darcs Cargo.toml go.mod package.json composer.json stack.yaml CMakeCache.txt .terraform .shorten_folder_marker(truncate_to_unique) Files that mark a directory as an anchor. Space-separated.
@shorten_path_shellautoWorker shell: bash, zsh, or fish. Unset = auto-detect in order bash → zsh → fish.

Example:

set -g @shorten_path_strategy truncate_to_unique
set -g @shorten_path_seg_threshold 3
set -g @shorten_path_markers ".git Makefile"
set -g @plugin 'Amdhj22/tmux-shorten-path'

To declare any directory as an anchor, drop a .shorten_folder_marker file in it:

touch ~/some/long/path/.shorten_folder_marker

The plugin ships three worker variants — scripts/shorten_path.bash, scripts/shorten_path.zsh, and scripts/shorten_path.fish — all producing identical output. At config-load time it picks whichever interpreter is installed and whose worker file is present, trying bash first. Set @shorten_path_shell to force a specific one. If none of the three is available the plugin disables itself gracefully: #{shorten_path} is left un-interpolated and no errors are raised. The worker runs as a subprocess via its shebang and has no relation to your login or interactive shell.

Strategies

All strategies collapse $HOME to ~.

StrategyWhat it does
truncate_to_unique(default) Folder-marker anchor + shortest unique prefix among siblings. See How it works below.
truncate_from_rightEvery non-last component → first N chars (@shorten_path_seg_length). Hidden dirs get +1.
truncate_to_lastOnly the basename. / stays as /.
noneAs-is (with $HOME collapsed to ~).

Same path, different strategies:

input: ~/myproject/server/api/middleware/auth.go

truncate_to_unique     →  ~/myproject/s../api/mid../auth.go
truncate_from_right    →  ~/m/s/a/m/auth.go
truncate_from_right    →  ~/my/se/ap/mi/auth.go   (seg_length=2)
truncate_to_last       →  auth.go
none                   →  ~/myproject/server/api/middleware/auth.go

How it works (truncate_to_unique)

The algorithm runs on every status redraw:

  1. Find anchor. Walk components from root, looking for a directory containing any marker file. The shallowest match wins. $HOME and its ancestors are never considered anchors (otherwise a single package.json in your home would defeat the whole purpose).
  2. Before the anchor: truncate each component to 1 char (2 for hidden dirs starting with .).
  3. The anchor: kept full.
  4. After the anchor (middle segments): if length > threshold, replace with the shortest prefix that doesn't collide with any sibling entry, suffixed with ...
  5. Last (current) segment: always kept full.
  6. No anchor: only the last component is kept full; everything else is one char.

Examples

Assume ~/myproject/.git exists (so ~/myproject is the anchor) and ~/myproject/server/api/ contains both middleware/ and migrations/:

Full pathShortened (truncate_to_unique)
~/myproject~/myproject
~/myproject/bin~/myproject/bin
~/myproject/server/db~/myproject/s../db
~/myproject/server/api~/myproject/s../api
~/myproject/server/api/middleware/auth.go~/myproject/s../api/mid../auth.go
~/.config/nvim/lua/plugins (no anchor)~/.c/n/l/plugins
/usr/local/share/zsh/site-functions (no anchor)/u/l/s/z/site-functions

Requirements

  • tmux 3.0+
  • one of: bash 3.2+, zsh, or fish 3.1+ (for the worker script — independent of your login shell)

One ls-style glob per middle segment per status redraw — negligible on local disks at the default 15s status-interval. For deep paths on network mounts, raise status-interval to throttle.

License

MIT