160 lines
9.9 KiB
Bash
160 lines
9.9 KiB
Bash
# Forward modified keys (Shift/Ctrl/Alt+Enter) to apps like pi-coding-agent.
|
|
# Without this, tmux collapses them to a plain Enter. Requires tmux 3.5+ for csi-u.
|
|
set -g extended-keys on
|
|
set -g extended-keys-format csi-u
|
|
|
|
# Mouse/touch reporting. Chiefly so the window list in the status bar is
|
|
# tappable — tmux binds MouseDown1Status to `switch-client -t =` out of the box,
|
|
# and status-format[1] below keeps the `range=window|…` markers that make each
|
|
# entry a hit target, so a tap on a tab switches to it with no extra binding.
|
|
# Wheel over the bar cycles windows; right-click a tab or the session name for
|
|
# tmux's built-in menus (no touch equivalent — a phone can't right-click).
|
|
#
|
|
# The cost: drag-select now goes to tmux instead of kitty, so hold Shift when you
|
|
# want kitty's own selection. Scroll wheel enters copy-mode on the pane rather
|
|
# than kitty's scrollback, and a click focuses the pane under it.
|
|
set -g mouse on
|
|
|
|
# Number windows (and panes) from 1 instead of 0 — easier to reach on the
|
|
# keyboard. renumber-windows keeps them gap-free when a window is closed.
|
|
set -g base-index 1
|
|
setw -g pane-base-index 1
|
|
set -g renumber-windows on
|
|
|
|
# --- Session persistence (survives reboot) ---------------------------------
|
|
# resurrect: save/restore sessions, windows, panes, layout and working dirs
|
|
# (prefix + Ctrl-s to save, prefix + Ctrl-r to restore).
|
|
# continuum: auto-saves every 15 min and auto-restores when the tmux server
|
|
# starts, so sessions come back after a reboot. Both via tpm.
|
|
set -g @plugin 'tmux-plugins/tpm'
|
|
set -g @plugin 'tmux-plugins/tmux-resurrect'
|
|
set -g @plugin 'tmux-plugins/tmux-continuum'
|
|
|
|
# Also capture pane scrollback and restore running programs (nvim, …).
|
|
# nvim 'session' strategy restores via Session.vim when present, else plain nvim.
|
|
set -g @resurrect-capture-pane-contents 'on'
|
|
set -g @resurrect-strategy-nvim 'session'
|
|
|
|
# Auto-restore the last saved environment on tmux server start.
|
|
set -g @continuum-restore 'on'
|
|
|
|
# Auto-start a detached tmux server at login: continuum writes and enables a
|
|
# systemd --user unit (~/.config/systemd/user/tmux.service). With the restore
|
|
# option above, sessions are already back and waiting after a reboot+login.
|
|
set -g @continuum-boot 'on'
|
|
|
|
# --- Status bar (Catppuccin Mocha, flat) -----------------------------------
|
|
# Palette: bg #1e1e2e · surface #313244 · divider #45475a · muted #6c7086/#7f849c
|
|
# text #cdd6f4 · subtext #a6adc8 · accent(mauve) #cba6f7
|
|
set -g status on
|
|
set -g status-position bottom # (also tmux's default)
|
|
set -g status-interval 5 # refresh clock + CPU every 5s
|
|
set -g status-justify left
|
|
set -g status-style "bg=default,fg=#cdd6f4" # transparent: no bar background
|
|
set -g status-left-length 40
|
|
set -g status-right-length 100
|
|
|
|
# --- Mobile view -----------------------------------------------------------
|
|
# status-left and status-right are re-evaluated per client on every draw, and
|
|
# #{client_width} is that client's own width — so in `auto` mode a phone attached
|
|
# to the same session as the desktop renders the compact bars while the desktop
|
|
# keeps the full ones, simultaneously and with no intervention.
|
|
#
|
|
# @status_mode is auto (per-client, by width) | full | compact, cycled with
|
|
# prefix+S. Rather than branch each bar three ways, the mode picks the width a
|
|
# client has to beat — 0 nothing can lose, 9999 nothing can win — so each
|
|
# decision below stays a single comparison. The 100 is the switch point: the full
|
|
# right segment is ~60 columns before the window list even starts. Set
|
|
# @status_mode without -g to scope an override to one session, so a grouped
|
|
# mobile session can sit on `compact` while the desktop session stays on `auto`.
|
|
#
|
|
# Each variant lives in its own option instead of inline because #{?a,b,c} splits
|
|
# its branches on commas and the styles are full of them (#[fg=…,bold]); option
|
|
# values are substituted after the ternary is parsed, so those commas are never
|
|
# seen as separators.
|
|
#
|
|
# NOTE: the comparisons MUST use #{e|>=:…}. Plain #{>=:…} compares as strings, so
|
|
# "144" >= "100" is false and every client would get the compact bar.
|
|
set -g @status_mode auto
|
|
set -g @status_cutoff "#{?#{==:#{@status_mode},full},0,#{?#{==:#{@status_mode},compact},9999,100}}"
|
|
|
|
# Left: session name (mauve/bold) + thin divider. Compact clips the name to two
|
|
# characters — enough to tell sessions apart when every column counts. #{=2:…}
|
|
# takes a format NAME, so it's session_name here rather than the #S shorthand.
|
|
set -g @left_full " #[fg=#cba6f7,bold]#S #[fg=#45475a]│ "
|
|
set -g @left_compact " #[fg=#cba6f7,bold]#{=2:session_name} #[fg=#45475a]│ "
|
|
set -g status-left "#{?#{e|>=:#{client_width},#{E:@status_cutoff}},#{E:@left_full},#{E:@left_compact}}"
|
|
|
|
# Middle: flat window list — inactive muted, active mauve/bold, 2-space gaps.
|
|
set -g window-status-separator " "
|
|
setw -g window-status-format "#[fg=#7f849c]#I #[fg=#6c7086]#W"
|
|
setw -g window-status-current-format "#[fg=#cba6f7,bold]#I #[fg=#cdd6f4,bold]#W"
|
|
setw -g window-status-activity-style "fg=#f9e2af"
|
|
|
|
# Right: net dl/ul · cpu · mem │ date │ clock. continuum prepends its invisible
|
|
# save hook to status-right (this block sits above the tpm `run` line, so the
|
|
# hook survives every reload). Metrics are scripts/*.sh, symlinked into
|
|
# ~/.config/tmux/scripts/. The hook lands ahead of the #{?} below, i.e. outside
|
|
# it, so it keeps running for every client regardless of which variant is drawn.
|
|
set -g @right_full "#[fg=#a6e3a1]#(~/.config/tmux/scripts/net.sh dl) #[fg=#f9e2af]#(~/.config/tmux/scripts/net.sh ul) #[fg=#89b4fa]#(~/.config/tmux/scripts/cpu.sh) #[fg=#94e2d5]#(~/.config/tmux/scripts/mem.sh) #[fg=#fab387]#(~/.config/tmux/scripts/temp.sh)#[fg=#45475a]│ #[fg=#a6adc8]%a %b %-d #[fg=#45475a]│ #[fg=#cba6f7,bold]%H:%M "
|
|
|
|
# Compact: cpu + mem only. Net rates and the temp glyph go first (widest, least
|
|
# useful on a phone), then the date, then the clock — a phone shows its own.
|
|
set -g @right_compact "#[fg=#89b4fa]#(~/.config/tmux/scripts/cpu.sh) #[fg=#94e2d5]#(~/.config/tmux/scripts/mem.sh) "
|
|
|
|
set -g status-right "#{?#{e|>=:#{client_width},#{E:@status_cutoff}},#{E:@right_full},#{E:@right_compact}}"
|
|
|
|
# Cycle auto -> compact -> full -> auto. Braces instead of nested quoted strings
|
|
# so the styles' commas and the inner if-shell don't need escaping.
|
|
bind S {
|
|
if -F '#{==:#{@status_mode},auto}' {
|
|
set -g @status_mode compact
|
|
display 'status bar: compact (forced)'
|
|
} {
|
|
if -F '#{==:#{@status_mode},compact}' {
|
|
set -g @status_mode full
|
|
display 'status bar: full (forced)'
|
|
} {
|
|
set -g @status_mode auto
|
|
display 'status bar: auto — switches at 100 columns'
|
|
}
|
|
}
|
|
refresh-client -S
|
|
}
|
|
|
|
# Two rows: [0] drawn top-border rule · [1] the bar content. The rule doubles as
|
|
# the separator from the pane content above; tmux status height is whole rows, so
|
|
# one row above the content is the smallest gap that still shows a border.
|
|
# Full-width run of ─ (yes|head|paste avoids %, backslashes and nested parens so
|
|
# tmux's strftime/quote/#() parsing leave it alone); tmux truncates it to width.
|
|
# status-format[1] is tmux 3.7's default content template (status-left/windows/right).
|
|
set -g status 2
|
|
set -g status-format[0] "#[fg=#6c7086,bg=default]#(yes ─ | head -n 400 | paste -sd '')"
|
|
set -g status-format[1] "#[align=left range=left #{E:status-left-style}]#[push-default]#{T;=/#{status-left-length}:status-left}#[pop-default]#[norange default]#[list=on align=#{status-justify}]#[list=left-marker]<#[list=right-marker]>#[list=on]#{W:#[range=window|#{window_index} #{E:window-status-style}#{?#{&&:#{window_last_flag},#{!=:#{E:window-status-last-style},default}}, #{E:window-status-last-style},}#{?#{&&:#{window_bell_flag},#{!=:#{E:window-status-bell-style},default}}, #{E:window-status-bell-style},#{?#{&&:#{||:#{window_activity_flag},#{window_silence_flag}},#{!=:#{E:window-status-activity-style},default}}, #{E:window-status-activity-style},}}]#[push-default]#{T:window-status-format}#[pop-default]#[norange default]#{?loop_last_flag,,#{E:window-status-separator}},#[range=window|#{window_index} list=focus #{?#{!=:#{E:window-status-current-style},default},#{E:window-status-current-style},#{E:window-status-style}}#{?#{&&:#{window_last_flag},#{!=:#{E:window-status-last-style},default}}, #{E:window-status-last-style},}#{?#{&&:#{window_bell_flag},#{!=:#{E:window-status-bell-style},default}}, #{E:window-status-bell-style},#{?#{&&:#{||:#{window_activity_flag},#{window_silence_flag}},#{!=:#{E:window-status-activity-style},default}}, #{E:window-status-activity-style},}}]#[push-default]#{T:window-status-current-format}#[pop-default]#[norange list=on default]#{?loop_last_flag,,#{E:window-status-separator}}}#[range=user|newwin] #[fg=#6c7086]+#[default] #[norange]#[nolist align=right range=right #{E:status-right-style}]#[push-default]#{T;=/#{status-right-length}:status-right}#[pop-default]#[norange default]"
|
|
|
|
# The `+` appended to the window list above sits in a `range=user|newwin`
|
|
# marker. Per tmux(1), a user range triggers the same `Status` mouse key as a
|
|
# window range and exposes its argument in #{mouse_status_range} — window ranges
|
|
# report the literal string "window" — so one binding can serve both: click a
|
|
# tab to select it (tmux's stock behaviour, kept in the else branch), click the
|
|
# `+` to open a new window. Padded with spaces on both sides so it's a wide
|
|
# enough target to hit with a thumb.
|
|
bind -n MouseDown1Status {
|
|
if -F '#{==:#{mouse_status_range},newwin}' {
|
|
new-window
|
|
} {
|
|
switch-client -t =
|
|
}
|
|
}
|
|
|
|
# Round out the theme so no default green leaks into borders/messages/modes.
|
|
set -g pane-border-style "fg=#313244"
|
|
set -g pane-active-border-style "fg=#cba6f7"
|
|
set -g message-style "bg=#313244,fg=#cdd6f4"
|
|
set -g message-command-style "bg=#313244,fg=#cdd6f4"
|
|
set -g mode-style "bg=#45475a,fg=#cdd6f4"
|
|
set -g clock-mode-colour "#cba6f7"
|
|
|
|
# Initialize tpm — KEEP THIS LINE AT THE VERY BOTTOM of tmux.conf.
|
|
run '~/.config/tmux/plugins/tpm/tpm'
|