repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
tmux/tmux.conf
Raw# bugabinga tmux
#
# Mental model:
# • tmux server owns sessions.
# • Session owns windows.
# • Window owns panes.
# • Prefix key tells tmux: next key is a tmux command, not shell/editor input.
#
# Primary prefix here: Ctrl-Space.
# Reason: does not fight terminal/WezTerm/Ghostty Ctrl-A leader.
#
# Survival keys:
# • C-Space ? show help
# • C-Space r reload config
# • C-Space t new window
# • C-Space v vertical split: left/right panes
# • C-Space s horizontal split: top/bottom panes
# • C-Space h/j/k/l move panes
# • C-Space q show pane numbers / jump pane
# • C-Space x kill pane
# • C-Space f zoom pane
# • C-Space [ copy mode
# • C-Space / search history
# • C-Space p choose windows
# • C-Space Tab choose sessions
# • C-Space d project/session switcher
# ── Core ─────────────────────────────────────────────────────────────────────
# Start panes in Nushell login mode.
# Login mode loads env/login config like a real terminal session.
set -g default-command "nu --login"
# Tell apps inside tmux what terminal capability profile to use.
# tmux-256color is the modern tmux terminfo entry.
set -g default-terminal "tmux-256color"
# Advertise modern terminal features to apps inside tmux.
# RGB: truecolor.
# clipboard: OSC52/system clipboard integration.
# extkeys: distinguish more modified keys.
# focus: apps can know terminal focus gained/lost.
# hyperlinks: clickable terminal links.
set -ga terminal-features ",*:RGB,clipboard,ccolour,cstyle,extkeys,focus,hyperlinks,overline,strikethrough,usstyle"
# Let tmux talk to terminal clipboard when possible.
set -g set-clipboard on
# Emit focus events into panes.
# Useful for editors/shells that redraw or save state on focus change.
set -g focus-events on
# Enable extended key reporting in tmux itself.
set -g extended-keys on
# Use CSI-u extended key encoding.
# Pi needs this for modified Enter/key chords inside tmux.
set -g extended-keys-format csi-u
# Allow passthrough escape sequences.
# Needed by some terminal protocols/features behind tmux.
set -g allow-passthrough on
# Remove old vi/escape delay.
# Makes modal editors feel instant.
set -sg escape-time 0
# Time window where repeatable bindings can repeat without prefix.
set -g repeat-time 500
# Scrollback lines per pane.
set -g history-limit 100000
# Mouse enables click panes, resize panes, wheel scroll, status clicks.
set -g mouse on
# Wheel policy:
# • tmux copy mode keeps real wheel scrolling.
# • Mouse-aware apps receive real mouse wheel events.
# • Full-screen apps without mouse support receive Up/Down keys.
#
# Pi list widgets currently understand keyboard navigation better than raw tmux
# wheel events, so this makes the mouse wheel move Pi selections inside tmux.
# Outside full-screen apps, WheelUp still enters tmux copy-mode scrollback.
bind -n WheelUpPane if -F "#{pane_in_mode}" { send-keys -M } { if -F "#{mouse_any_flag}" { send-keys -M } { if -F "#{alternate_on}" { send-keys Up } { copy-mode -e } } }
bind -n WheelDownPane if -F "#{pane_in_mode}" { send-keys -M } { if -F "#{mouse_any_flag}" { send-keys -M } { if -F "#{alternate_on}" { send-keys Down } { send-keys -M } } }
# Renumber windows after one closes: 1,2,3 not 1,3,7.
set -g renumber-windows on
# Start window numbers at 1, easier keyboard reach than 0.
set -g base-index 1
# Start pane numbers at 1 too, consistent with windows.
setw -g pane-base-index 1
# If current session dies, keep client alive if other sessions exist.
set -g detach-on-destroy off
# How long tmux messages stay visible, ms.
set -g display-time 1200
# Refresh status bar every 5 sec.
set -g status-interval 5
# Put status bar at bottom.
set -g status-position bottom
# Window list alignment in status bar.
set -g status-justify left
# Max width of left status segment.
set -g status-left-length 80
# Max width of right status segment.
set -g status-right-length 120
# Mark windows with activity in background panes.
setw -g monitor-activity on
# Do not spam visible activity alerts.
set -g visual-activity off
# Disable bells.
set -g bell-action none
# Copy mode uses vi keys: h/j/k/l, /, n, v, y style.
setw -g mode-keys vi
# ── Prefix ───────────────────────────────────────────────────────────────────
# Remove tmux default prefix Ctrl-B.
unbind C-b
# Use Ctrl-Space as primary prefix.
# Some terminals encode Ctrl-Space as Ctrl-@ (NUL), so accept both spellings.
set -g prefix C-Space
set -g prefix2 C-@
# Press prefix twice to send literal prefix into app if needed.
bind C-Space send-prefix
bind C-@ send-prefix
# ── Nugu colors ──────────────────────────────────────────────────────────────
# Hidden variables keep repeated colors readable.
# They are not tmux options shown in status; just local config vars.
%hidden BG="#242424"
%hidden FG="#ededed"
%hidden ACCENT="#d86dd8"
%hidden MINOR="#9d9d9d"
%hidden DIM_FG="#5d5d5d"
%hidden DIM_BG="#050505"
%hidden FOCUS="#9aabae"
%hidden WARN="#9e9a69"
%hidden ERROR="#e46479"
# ── Chrome / UI ──────────────────────────────────────────────────────────────
# Base status bar colors.
set -g status-style "bg=$BG,fg=$FG"
# Popup message style: display-message, errors, confirmations.
set -g message-style "bg=$ACCENT,fg=$BG,bold"
# Command prompt style: command-prompt, rename prompts, etc.
set -g message-command-style "bg=$FOCUS,fg=$BG,bold"
# Copy-mode selection/current-match style.
set -g mode-style "bg=$ACCENT,fg=$BG,bold"
# Inactive pane content is dimmed.
# Hard limit: tmux can only style terminal *default* fg/bg.
# Full-screen TUIs/editors that paint explicit ANSI colors cannot be truly dimmed.
# For normal shell output, this is aggressive: dim attr + grey fg + near-black bg.
set -g window-style "fg=$DIM_FG,bg=$DIM_BG,dim"
# Active pane content uses strong Nugu defaults.
set -g window-active-style "fg=$FG,bg=$BG"
# Inactive pane border.
set -g pane-border-style "fg=$DIM_FG,bg=$DIM_BG,dim"
# Active pane border.
# Bold magenta is intentionally loud: active pane must be obvious.
set -g pane-active-border-style "fg=$ACCENT,bg=$BG,bold"
# Heavy borders make pane geometry visible at a glance.
set -g pane-border-lines heavy
# Active border indicators: colour + arrows.
set -g pane-border-indicators both
# Show a label in each pane border.
# Active pane gets a loud block badge; inactive panes are deliberately quiet.
set -g pane-border-status top
# Note: #[] style commas inside tmux conditionals must be escaped as #,.
set -g pane-border-format "#{?pane_active,#[fg=$BG#,bg=$ACCENT#,bold] █ ACTIVE #P █ #[fg=$ACCENT#,bg=$BG],#[fg=$DIM_FG#,bg=$DIM_BG#,dim] #P }"
# Colors used by Prefix+q display-panes overlay.
set -g display-panes-colour "$MINOR"
set -g display-panes-active-colour "$ACCENT"
# Popup body colors.
set -g popup-style "bg=$BG,fg=$FG"
# Popup border color.
set -g popup-border-style "fg=$ACCENT"
# Rounded popup borders.
set -g popup-border-lines rounded
# Left status: session name.
# #[] changes style until next style marker.
# #S is current session name.
# is Powerline separator.
set -g status-left "#[fg=$BG,bg=$ACCENT,bold] #S #[fg=$ACCENT,bg=$BG] "
# Right status:
# #{?client_prefix,A,B} is tmux conditional.
# Shows PREFIX warning only while prefix is armed.
# #{user} is current user. #{host_short} is hostname. %H:%M is time.
# Also shows PREFIX while prefix is armed and pane/resize while in key tables.
set -g status-right "#{?client_prefix,#[fg=$BG#,bg=$WARN#,bold] PREFIX #[fg=$WARN#,bg=$BG] ,}#{?#{!=:#{client_key_table},root},#[fg=$BG#,bg=$ACCENT#,bold] #{client_key_table} #[fg=$ACCENT#,bg=$BG] ,}#[fg=$MINOR]#{user}@#{host_short} #[fg=$ACCENT]%H:%M"
# No separator between window items; each item owns its spacing.
setw -g window-status-separator ""
# Inactive window label.
# #I index, #W name, #F flags.
setw -g window-status-format "#[fg=$MINOR,bg=$BG] #I:#W#{?window_flags, #F,} "
# Active window label.
# #{?window_zoomed_flag, ...} shows icon when pane zoomed.
setw -g window-status-current-format "#[fg=$BG,bg=$FOCUS,bold] #I:#W#{?window_zoomed_flag, ,} #[fg=$FOCUS,bg=$BG]"
# ── Windows / panes ──────────────────────────────────────────────────────────
# Prefix+t creates new window in same dir as current pane.
bind t new-window -c "#{pane_current_path}"
# Prefix+c also creates new window. tmux muscle memory.
bind c new-window -c "#{pane_current_path}"
# Prefix+x kills current pane.
# Destructive pane kill is on x, not q: q stays native tmux "show pane ids".
bind x kill-pane
# Prefix+X kills current window.
bind X kill-window
# Prefix+q shows pane ids and lets you jump by number.
# This is also a quick visual active-pane diagnostic.
bind q display-panes
# Prefix+Q kills whole session.
bind Q kill-session
# Prefix+r reloads config from installed dotfile path and confirms.
bind r source-file ~/.config/tmux/tmux.conf \; display-message "tmux reloaded"
# Prefix+? opens a native help popup.
# The help file lives beside this config in the dotfiles tmux dir.
bind ? display-popup -E -w 70% -h 80% -d "#{pane_current_path}" "sh -c 'cat ~/.config/tmux/help.txt; printf \"\\npress enter to close...\"; read _'"
# Prefix+e edits tmux config in a popup.
# Fast loop: edit → save → Prefix+r.
bind e display-popup -E -w 90% -h 90% -d ~/.config/tmux "nvim tmux.conf"
# Prefix+f toggles pane zoom.
# Zoom means one pane temporarily fills whole window.
bind f resize-pane -Z
# Prefix+g opens a scratch popup shell in current dir.
# Popup exits when shell exits.
bind g display-popup -E -w 90% -h 80% -d "#{pane_current_path}" "nu --login"
# Prefix+d opens a project/session switcher.
# Existing sessions and common project dirs go through fzf in a tmux popup.
bind d display-popup -E -w 90% -h 85% -d "#{pane_current_path}" "~/.config/tmux/session.sh '#{pane_current_path}'"
# Prefix+F prompts for session name, then creates/attaches it.
# new-session -A = attach if exists, otherwise create.
bind F command-prompt -p "session" "new-session -A -s '%%' -c '#{pane_current_path}'"
# Prefix+v splits current pane left/right.
bind v split-window -h -c "#{pane_current_path}"
# Prefix+s splits current pane top/bottom.
bind s split-window -v -c "#{pane_current_path}"
# Prefix+h/j/k/l move between panes, vim style.
# -r means repeatable: Prefix+h, then h/h/h keeps moving for repeat-time ms.
bind -r h select-pane -L
bind -r j select-pane -D
bind -r k select-pane -U
bind -r l select-pane -R
# Prefix+H/J/K/L resize panes in bigger jumps.
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5
# No global Alt-h/j/k/l here.
# Neovim already uses Alt-h/l for parameter swapping in this dotfiles repo.
# Prefix+h/j/k/l keeps tmux vim-like without stealing editor muscle memory.
# Prefix+< moves current window left in window list.
bind < swap-window -t -1\; select-window -t -1
# Prefix+> moves current window right in window list.
bind > swap-window -t +1\; select-window -t +1
# ── Pane key table ───────────────────────────────────────────────────────────
# Prefix+w enters a transient pane command table.
# Next key is read from table "pane".
# This mirrors your Ghostty/WezTerm leader+w pane mode.
bind w switch-client -T pane
# pane:h/j/k/l moves between panes.
bind -T pane h select-pane -L
bind -T pane j select-pane -D
bind -T pane k select-pane -U
bind -T pane l select-pane -R
# pane:a shows pane numbers and jumps to selected pane.
bind -T pane a display-panes
# pane:v/s split current pane.
bind -T pane v split-window -h -c "#{pane_current_path}"
bind -T pane s split-window -v -c "#{pane_current_path}"
# pane:f zooms/unzooms current pane.
bind -T pane f resize-pane -Z
# pane:q kills current pane.
bind -T pane q kill-pane
# pane:r/R rotates panes inside current window.
bind -T pane r rotate-window -D
bind -T pane R rotate-window -U
# pane:H/L moves current window in window list.
bind -T pane H swap-window -t -1\; select-window -t -1
bind -T pane L swap-window -t +1\; select-window -t +1
# pane:= enters resize table for repeated resize keys.
bind -T pane = switch-client -T resize
# ── Resize key table ─────────────────────────────────────────────────────────
# resize:h/j/k/l shrinks/grows by small jumps.
bind -T resize h resize-pane -L 2
bind -T resize j resize-pane -D 2
bind -T resize k resize-pane -U 2
bind -T resize l resize-pane -R 2
# resize:H/J/K/L resizes by large jumps.
bind -T resize H resize-pane -L 8
bind -T resize J resize-pane -D 8
bind -T resize K resize-pane -U 8
bind -T resize L resize-pane -R 8
# Escape exits resize table.
bind -T resize Escape switch-client -T root
# ── Copy/search ──────────────────────────────────────────────────────────────
# Prefix+/ enters copy mode and starts backward search.
bind / copy-mode \; send -X search-backward
# Prefix+[ enters copy mode.
bind [ copy-mode
# Prefix+] pastes latest tmux buffer.
bind ] paste-buffer
# Prefix+P opens buffer picker.
bind P choose-buffer
# In copy mode: v begins selection.
bind -T copy-mode-vi v send -X begin-selection
# In copy mode: Ctrl-v toggles rectangular/block selection.
bind -T copy-mode-vi C-v send -X rectangle-toggle
# In copy mode: y copies selection to tmux buffer and system clipboard.
# Clipboard tools tried in order: wl-copy, xclip, pbcopy.
bind -T copy-mode-vi y send -X copy-pipe-and-cancel "sh -c 'wl-copy 2>/dev/null || xclip -selection clipboard 2>/dev/null || pbcopy 2>/dev/null || cat >/dev/null'"
# In copy mode: Enter does same as y.
bind -T copy-mode-vi Enter send -X copy-pipe-and-cancel "sh -c 'wl-copy 2>/dev/null || xclip -selection clipboard 2>/dev/null || pbcopy 2>/dev/null || cat >/dev/null'"
# ── Pickers ──────────────────────────────────────────────────────────────────
# Prefix+p opens interactive tree picker, focused on windows.
# -Z zooms preview while choosing.
# -w shows windows.
bind p choose-tree -Zw
# Prefix+Tab opens interactive tree picker, focused on sessions.
bind Tab choose-tree -Zs
# ── Direct window jumps ──────────────────────────────────────────────────────
# Prefix+number jumps to window number.
bind 1 select-window -t :=1
bind 2 select-window -t :=2
bind 3 select-window -t :=3
bind 4 select-window -t :=4
bind 5 select-window -t :=5
bind 6 select-window -t :=6
bind 7 select-window -t :=7
bind 8 select-window -t :=8
bind 9 select-window -t :=9