# 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