Architecture

tmux-dispatch is built as a single-script-with-modes design: one main script (dispatch.sh) handles all modes via a --mode flag, and fzf’s become action enables seamless mode switching without restarting the popup. There is no build step – the plugin is seven shell scripts that are sourced or executed directly.

Mode tree

The plugin operates as a mode tree rooted at the files (home) mode. Prefix characters switch into sub-modes, and backspace on an empty query returns to home, similar to VS Code’s command palette.

dispatch.sh --mode=files  (home mode, prompt: "  ")
  +-- fd | fzf (filtering, bookmarks, git indicators, frecency ranking)
  |   +-- ">" prefix --> become(dispatch.sh --mode=grep --query={q})
  |   +-- "@" prefix --> become(dispatch.sh --mode=sessions --query={q})
  |   +-- "!" prefix --> become(dispatch.sh --mode=git --query={q})
  |   +-- "#" prefix --> become(dispatch.sh --mode=dirs --query={q})
  |   +-- Ctrl+R --> become(dispatch.sh --mode=rename)
  |
dispatch.sh --mode=grep  (prompt: "> ")
  +-- fzf --disabled + change:reload:rg (live search)
  |   +-- backspace on empty --> become(dispatch.sh --mode=files)
  |
dispatch.sh --mode=git  (prompt: "! ")
  +-- git status --porcelain | fzf (stage/unstage with Tab, diff preview)
  |   +-- backspace on empty --> become(dispatch.sh --mode=files)
  |
dispatch.sh --mode=dirs  (prompt: "# ")
  +-- zoxide/fd/find directories | fzf (tree preview, cd on Enter)
  |   +-- backspace on empty --> become(dispatch.sh --mode=files)
  |
dispatch.sh --mode=sessions  (prompt: "@ ")
  +-- tmux list-sessions | fzf (session picker + creator)
  |   +-- backspace on empty --> become(dispatch.sh --mode=files)
  |   +-- Ctrl+N --> become(dispatch.sh --mode=session-new)
  |   +-- Ctrl+W --> become(dispatch.sh --mode=windows --session={1})
  |   +-- Ctrl+R --> become(dispatch.sh --mode=rename-session)
  |
dispatch.sh --mode=windows
  +-- tmux list-windows | fzf (2D grid navigation with arrow keys)
  |   +-- backspace on empty --> become(dispatch.sh --mode=sessions)
  |
dispatch.sh --mode=session-new
  +-- fd directories | fzf (project directory picker)
  |   +-- backspace on empty --> become(dispatch.sh --mode=sessions)
  |
dispatch.sh --mode=rename
  +-- fzf query as new filename (inline rename for selected files)
  |
dispatch.sh --mode=rename-session
  +-- fzf query as new session name (inline rename for selected session)

Script roles

The plugin consists of seven scripts, each with a focused responsibility.

dispatch.tmux

The TPM entry point. Reads all @dispatch-* tmux options and registers keybindings accordingly. Detects the tmux version to decide between display-popup (tmux 3.2+) and the split-window fallback for older versions. This script does not use set -euo pipefail because TPM entry points must not exit on error.

scripts/helpers.sh

Sourced by all other scripts. Provides shared utility functions:

  • get_tmux_option – Reads tmux options with fallback defaults
  • Tool detectiondetect_fd, detect_bat, detect_rg, detect_zoxide, detect_popup_editor, detect_pane_editor. Handles Debian/Ubuntu renamed binaries (fdfind, batcat)
  • fzf visual options – Consistent styling (colors, borders, layout) across all modes
  • File history and frecency – Per-directory tracking of recently and frequently opened files
  • Bookmarks – Persistent file bookmarks with starred indicators

This script omits set -euo pipefail because it is sourced into other scripts’ environments.

scripts/dispatch.sh

The main script. Accepts a --mode flag with nine possible values: files, grep, git, dirs, sessions, session-new, windows, rename, and rename-session. Each mode configures fzf differently (prompt, preview command, keybindings, reload behavior). Uses fzf’s become action to re-execute itself with a different mode, enabling seamless mode switching within a single popup.

scripts/actions.sh

Extracted action handlers called by fzf key bindings. Includes:

  • File edit (popup and send-to-pane)
  • Grep edit (with line number positioning)
  • File delete and rename
  • Bookmark toggle
  • Git stage/unstage
  • Session list, switch, and rename
  • Preview helper functions

scripts/preview.sh

Preview command for grep mode. Displays file content with the matching line highlighted using bat (with --highlight-line). Falls back to head when bat is not available.

scripts/git-preview.sh

Preview command for git status mode. Shows the diff for the selected file. Handles staged changes, unstaged changes, and combined diffs depending on the file’s git status.

scripts/session-preview.sh

Preview command for both session mode and window mode. Renders a 2-column grid of windows belonging to the selected session. Each window cell shows a pane content snapshot captured via tmux capture-pane. Uses Perl for ANSI-aware width handling to properly truncate and pad content within the box-drawing grid. Accepts an optional second argument (window index) to highlight the fzf-selected window with bright cyan borders in window mode.

Design principles

Graceful fallbacks. Every optional tool has a fallback path. fd falls back to find, bat falls back to head, zoxide falls back to fd/find for directories. The plugin works (with reduced features) on minimal systems.

No build step. The plugin is pure bash – no compilation, transpilation, or bundling. Install via TPM or clone and source.

Bash 4.0+ required. The scripts use associative arrays and other bash 4.0 features. macOS users need to install a modern bash via Homebrew (brew install bash) since the system /bin/bash is version 3.2.


tmux-dispatch is released under the MIT License.

This site uses Just the Docs, a documentation theme for Jekyll.