-
Notifications
You must be signed in to change notification settings - Fork 0
/
.tmux.conf
348 lines (289 loc) · 14.6 KB
/
.tmux.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
#
# NOTE TO MYSELF
# ---
# choose-buffer "clipboard manager" C-a C-p (was C-a =)
# choose-client "attach to different sessions" C-a D
# (not very useful with tmx)
# choose-tree "show panes and windows in a tree" C-a w
# list-keys "show key bindings" C-a ? (`list-keys -N`)
# C-a / (`command-prompt ... list-keys -1N`) to find interactively
# customize-mode "interactive settings" C-a C (`customize-mode -Z`)
# display-panes "identify" -
# ---
#
#
# Basic things
#
# Vi mode
setw -g mode-keys vi
set -g status-keys vi
# Mouse
set -g mouse on
# enter copy-mode, but only if NOT mouse_any_flag (i. e. the program does not
# want mouse itself) AND NOT pane_in_mode (i. e. we are not yet entered copy mode)
# NB: `if -F` checks for non-empty string, so concatenation of the flags is an "OR" here
bind -n WheelUpPane if -Ft= '#{mouse_any_flag}#{pane_in_mode}' 'send-keys -M' 'copy-mode; send-keys -M'
# TODO: use `select-pane -t=` in Wheel{Up,Down}Pane handlers in copy-mode{,-vi} tables
# to have scrolling focus follow mouse events
# Window titles
set -g set-titles on
# Default window title format is illegible, set it to something sane.
# #S: session name
# #h: short hostname (use #H for full hostname)
# #W: window name (set by auto-rename below, usually current command name or special mode in square brackets)
# #T: pane title (set by application running inside the pane, defaults to hostname)
# Do not show pane title (only window name) if pane title is default (== hostname).
# Likewise, do not show window name (only pane title) if pane title contains window name (== current command).
set -g set-titles-string "tmux (#S@#h): #{?#{==:#T,#H},#W,#{?#{m:*#W*,#T},#T,#W: #T}} #{session_alerts}"
setw -g automatic-rename on
setw -g allow-rename on
set -g base-index 1
#setw -g automatic-rename-format "#{?pane_title,#{pane_title},#{?pane_in_mode,[tmux],#{pane_current_command}}#{?pane_dead,[dead],}"
#setw -g set-titles-string "tmux (#S@#h): #{?#{==:#T,#H},#W,#{?#{m:*#W*,#T},#T,#W: #T}} #{session_alerts}"
# 500ms escape time is really excessive
# I use mosh where possible over slow links, so I'd like to think that it actually sends C1s as C1s
# (cf. https://unix.stackexchange.com/a/608179/21885)
set -g escape-time 10
# Forward bells from the applications to the terminal emulator
# (which will hopefully do something sane)
set -g bell-action any
set -g visual-bell off
# Set a reasonable $TERM
set -g default-terminal "tmux-256color"
# Forward focus events from the terminal emulator to the applications
set -g focus-events on
# Enable status bar
bind s set status
# Scrollback buffer
set -g history-limit 1000000
# I don't like gaps in window numbers.
set -g renumber-windows on
# enable OSC 52 support for the built-in selection/clipboard (see below)
set -g set-clipboard on
set -ag terminal-features "tmux*:clipboard:ccolour:cstyle:focus:title"
# emit OSC 52 in a form acceptable to unpatched mosh (see mobile-shell/mosh#1054)
# set -ag terminal-overrides "xterm*:Ms=\\E]52;c;%p2%s\\7"
# set -ag terminal-overrides "tmux*:Ms=\\E]52;c;%p2%s\\7"
# enable "true color" support
set -ag terminal-overrides "alacritty:RGB"
set -ag terminal-overrides "xterm*:RGB"
set -ag terminal-overrides "tmux*:RGB"
# Rebind select-pane commands to disable key repeat (really annoying)
bind Up select-pane -U
bind Down select-pane -D
bind Left select-pane -L
bind Right select-pane -R
#
# Copy mode
#
# Enter/exit
unbind [
bind Escape copy-mode
# General copy mode operations
unbind -T copy-mode-vi C-b # page-up
unbind -T copy-mode-vi C-f # page-down
bind -T copy-mode-vi C-v send-keys -X rectangle-toggle
bind -T copy-mode-vi Enter send-keys -X cancel
bind -T copy-mode-vi v send-keys -X begin-selection
bind -T copy-mode-vi V send-keys -X select-line
# Copy directly into desktop (Wayland/X11) keyboard instead of using tmux clipboard
# (tmux clipboard integrates with OSC 52 to read/write system clipboard,
# which gnome-terminal does not support)
bind -T copy-mode-vi Y send-keys -X copy-pipe-and-cancel "clip --desktop -i"
# For reference, the original tmux selection/clipboard interface
bind -T copy-mode-vi y send-keys -X copy-selection-and-cancel
# However, nested tmux _will_ make use of OSC 52 to pass the copied selection
# to parent tmux, which will then get "stuck" in the toplevel tmux (see above)
# TODO: somehow teach tmux to react to clipboard events such that we _both_ use
# OSC 52 to pass the selection "above" _and_ use `~/bin/clip` to write to
# Wayland/X11 clipboard?
# HACK: add a dedicated binding to copy existing buffer into desktop clipboard
# (bind `C-y` for similarity with `y`)
bind C-y run -b "tmux show-buffer | clip --desktop -i"
# same interface can be done for mouse, but I don't like the idea that releasing mouse exits copy mode, so just get rid of it
unbind -T copy-mode-vi MouseDragEnd1Pane
#bind -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "clip --desktop -i"
# per the logic above, also do not exit copy mode on double/triple click
bind-key -T copy-mode-vi DoubleClick1Pane select-pane \; send-keys -X select-word
bind-key -T copy-mode-vi TripleClick1Pane select-pane \; send-keys -X select-line
# similarly, interface with the desktop (Wayland/X11) clipboard in the other direction
bind P run "clip --desktop -o | tmux load-buffer -btmp -" \; paste-buffer -p -btmp -d #\; send-keys -X cancel
# similarly, for reference, the original tmux sesection/clipboard interface
unbind ]
bind p paste-buffer -p
# HACK: add a dedicated binding to copy existing desktop clipboard into tmux buffer (with OSC 52)
# (I'd bind `C-p` for similarity with `p`, but it's taken by `choose-buffer`)
bind C-o run -b "clip --desktop -o | tmux load-buffer -w -"
# FIXME: drop `run "..."` wrapping around `tmux wait tmp` (pending release of https://github.com/tmux/tmux/commit/7339845c01727b209b3b96e5b1d917129b2c8a83)
# FIXME: drop `wait -S`/`wait` completely (pending resolution of https://github.com/tmux/tmux/issues/1517)
# Upload to 0x0 and copy the URL, else display the error
#bind -T copy-mode-vi Y send-keys -X copy-pipe-and-cancel "resp=\"\$(curl --fail-with-body -sS '-Ffile=@-;filename=stdin.log' https://0x0.st 2>&1)\" && rc=0 || rc=\$?; if (( \$rc != 0 )); then tmux set-buffer -berr \"\$resp\"; else tmux set-buffer -w \"\$resp\"; tmux delete-buffer -berr; fi; tmux wait -S tmp" \; wait tmp \; if-shell "tmux show-buffer -berr &>/dev/null" { show-buffer -berr }
# Upload to 0x0 and display the URL
bind -T copy-mode-vi X send-keys -X copy-pipe-and-cancel "curl --fail-with-body -sS '-Ffile=@-;filename=stdin.log' https://0x0.st |& tmux load-buffer -btmp -; tmux wait -S tmp" \; wait tmp \; show-buffer -btmp
#
# Main key bindings
#
# screen forever
unbind C-b
set -g prefix C-a
# misc
bind r source-file ~/.tmux.conf
bind a send-prefix # C-a-a-a-a-a-aaaaaa!
bind C-a send-prefix # ergonomics: alleviate the need to release Ctrl ... (see below)
bind m send-keys C-b # I'd bind 'b' for similarity with 'a', but 'b' is taken for previous-window
bind q kill-window \; kill-session
unbind ]
bind p paste-buffer -p
unbind &
bind X confirm-before -p "kill-window #W (y/n)?" kill-window # FIXME: find a way to move binding instead of hardcoding
bind C-r respawn-pane -k
unbind =
bind C-p choose-buffer -Z
# Pane splitting
unbind %
bind v split-window -h
bind V split-window -h -f
unbind '"'
bind h split-window -v
bind H split-window -v -f
unbind o
# Pane (re-)creation preserving $PWD
# tmux does not support binding key sequences, sunrise by hand
bind k switch-client -T keep-cwd
# ergonomics: alleviate the need to release Ctrl in chords like C-a k C-r
bind C-k switch-client -T keep-cwd
# split-window (C-a [vV]/[hH], see above)
bind -T keep-cwd v split-window -c "#{pane_current_path}" -h
bind -T keep-cwd V split-window -c "#{pane_current_path}" -h -f
bind -T keep-cwd h split-window -c "#{pane_current_path}" -v
bind -T keep-cwd H split-window -c "#{pane_current_path}" -v -f
# new-window (C-a c)
bind -T keep-cwd c new-window -c "#{pane_current_path}"
# respawn-pane (C-a C-r, see above)
bind -T keep-cwd C-r respawn-pane -c "#{pane_current_path}" -k
# Layouts
# mnemonic: vertical dash (pipe) for vertical split bar, horizontal dash for horizontal split bar
bind | select-layout even-horizontal
bind - select-layout even-vertical
bind = select-layout -E
# Organization
unbind .
bind . command-prompt "swap-window -t '%%'" # we use renumber-windows, default move-window is unusable in this configuration
# Mark/swap (with marked)
unbind M
bind M select-pane -m # mark
unbind S
bind S swap-pane # swap with marked
# Break/join (implicitly with marked)
unbind B
bind B break-pane
unbind J
bind J join-pane
bind C-j switch-client -T join-pane
bind -T join-pane v join-pane -h
bind -T join-pane V join-pane -h -f
bind -T join-pane h join-pane -v
bind -T join-pane H join-pane -v -f
# Bindings to move windows around
# (see below for original bindings)
bind-key -r < swap-window -t - -d
bind-key -r > swap-window -t + -d
# Pane navigation
bind z select-pane -t :.+ # switch to previous pane
bind -n C-n next-window
bind n next-window
bind -n C-b previous-window
bind b previous-window
# Focus
bind C-f run "tmux-focus c #D"
bind C-u run "tmux-focus d #D"
#
# Appearance
#
# Statusbar
set -g status-position bottom
set -g status-interval 4
set -g status-left ''
set -g status-right ''
set -g status-justify centre # center align window list
setw -g status-style ''
setw -g window-status-format '#[bg=black,fg=brightblack] #I #[blink,bg=brightblack,fg=black] #W ' # gnome-terminal, urxvt, Linux VT (blink == bg=bright)
setw -g window-status-current-format '#[fg=brightwhite,bg=cyan] #I #[fg=cyan,bg=default] #W '
# Panel borders
set -g pane-border-style fg=black,bg=default
set -g pane-active-border-style fg=cyan,bg=default
# Resize
setw -g aggressive-resize on
# Restore pre-3.2 behavior: when more than one shared session is looking at the same window,
# limit window size to the smallest of shared sessions (instead of playing the tug-of-war).
set -g window-size latest
#
# Names and titles
#
# 1. "Pane title" is the title of the specific pane, externally set by the
# command that's running in the pane using the xterm "set window title" sequence
# (in case of nested tmux, tmux's "window title" becomes this one);
# 2. "Window name" is the tmux-internal name of the window (tab), auto-updated
# using automatic-rename.
# Okay, this is getting awkward.
# This is at the wrong side of the limits of what I can reasonably write with
# the (fugly) tmux format mini-language, so set a temporary variable to the
# beautified format string, and then set the real one to the minified string.
# this sets the tmux's own title (which becames _pane title_ in case of nesting)
# (the #{n:...} replacement counts the number of alerts in the list)
set -g @set-titles-string "
(#{user}@#{host_short})
#{?#{window_name}, #{window_name},}
#{?#{session_alerts}, (#{n:#{s/[^,]+(,|$)/./:session_alerts}} alerts),}
"
set -gF set-titles-string "#{s/\n//:#{@set-titles-string}}"
# sudo sets title to the entire command line plus trailing garbage,
# reduce it aggressively
# (the regex matches 10 chars + at most 10 chars until the next word boundary, the rest is ellipsized)
set -g @ellipsized-pane-title-sudo "#{s/^(.{10#}([^ ]{0,10#} |.{10#})).*/\\1…/:#{s/^sudo +//:#{pane_title}}}"
# this even uglier regex matches first word + at most 10 chars until the next word boundary
set -g @ellipsized-pane-title-ssh-mosh "#{s/^([^ ]+) +([^ ]{0,10#} ?).*/\\1 \\2…/:#{s/^(^ssh|mosh|mosh-client|\\[mosh\\]) +//:#{pane_title}}}"
# this sets the _window name_ (which is internal to tmux)
set -g @automatic-rename-format "
#{?pane_in_mode,
[tmux],
#{?#{pane_title},
#{?#{==:#{pane_current_command},mosh-client},
[mosh] #{E:@ellipsized-pane-title-ssh-mosh},
#{?#{==:#{pane_current_command},ssh},
[ssh] #{E:@ellipsized-pane-title-ssh-mosh},
#{?#{==:#{pane_current_command},sudo},
[sudo] #{E:@ellipsized-pane-title-sudo},
#{?#{m/r:^#{pane_current_command}($| ),#{pane_title}},
#{pane_title},
#{pane_current_command} \"#{pane_title}\"
}
}
}
},
#{pane_current_command}
}
}
#{?pane_dead,
\u0020
#{?pane_dead_signal,
[killed with #{pane_dead_signal}],
#{?pane_dead_status,
[exited with #{pane_dead_status}],
[exited]
}
},
}
"
set -gF automatic-rename-format "#{s/\n//:#{@automatic-rename-format}}"
#
# Misc
#
# Original bindings on < an >, responsible for spawning the window and pane menus respectively
# (note that we swap the order:
# - `C-a >` -> `C-a [` (pane),
# - `C-a <` -> `C-a ]` (window))
# TODO: find a way to rebind those without open-coding their definitions
# (https://unix.stackexchange.com/questions/774022/move-rebind-tmux-keybinding-to-a-different-key-without-spelling-it-out)
bind-key -T prefix ] display-menu -T "#[align=centre]#{window_index}:#{window_name}" -x W -y W "#{?#{>:#{session_windows},1},,-}Swap Left" l { swap-window -t :-1 } "#{?#{>:#{session_windows},1},,-}Swap Right" r { swap-window -t :+1 } "#{?pane_marked_set,,-}Swap Marked" s { swap-window } '' Kill X { kill-window } Respawn R { respawn-window -k } "#{?pane_marked,Unmark,Mark}" m { select-pane -m } Rename n { command-prompt -F -I "#W" { rename-window -t "#{window_id}" "%%" } } '' "New After" w { new-window -a } "New At End" W { new-window }
bind-key -T prefix [ display-menu -T "#[align=centre]#{pane_index} (#{pane_id})" -x P -y P "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}" < { send-keys -X history-top } "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}" > { send-keys -X history-bottom } '' "#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}" C-r { if-shell -F "#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}" "copy-mode -t=" ; send-keys -X -t = search-backward "#{q:mouse_word}" } "#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}" C-y { copy-mode -q ; send-keys -l "#{q:mouse_word}" } "#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}" c { copy-mode -q ; set-buffer "#{q:mouse_word}" } "#{?mouse_line,Copy Line,}" l { copy-mode -q ; set-buffer "#{q:mouse_line}" } '' "#{?mouse_hyperlink,Type #[underscore]#{=/9/...:mouse_hyperlink},}" C-h { copy-mode -q ; send-keys -l "#{q:mouse_hyperlink}" } "#{?mouse_hyperlink,Copy #[underscore]#{=/9/...:mouse_hyperlink},}" h { copy-mode -q ; set-buffer "#{q:mouse_hyperlink}" } '' "Horizontal Split" h { split-window -h } "Vertical Split" v { split-window -v } '' "#{?#{>:#{window_panes},1},,-}Swap Up" u { swap-pane -U } "#{?#{>:#{window_panes},1},,-}Swap Down" d { swap-pane -D } "#{?pane_marked_set,,-}Swap Marked" s { swap-pane } '' Kill X { kill-pane } Respawn R { respawn-pane -k } "#{?pane_marked,Unmark,Mark}" m { select-pane -m } "#{?#{>:#{window_panes},1},,-}#{?window_zoomed_flag,Unzoom,Zoom}" z { resize-pane -Z }