mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1497 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1497 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
# Options {{{1
 | 
						||
# Server {{{2
 | 
						||
 | 
						||
# Don't pile up more than 10 buffers (down from 50 by default).{{{
 | 
						||
#
 | 
						||
# Rationale: Keeping  a tidy  stack, with  relevant information,  could help  us
 | 
						||
# integrate tmux buffers in our workflow more often.
 | 
						||
#
 | 
						||
# However,  maybe we  could keep  a big  stack of  buffers, and  filter them  by
 | 
						||
# pressing `f` in the window opened by `choose-buffer`.
 | 
						||
# Alternatively,  we could  also try to  use fzf to  fuzzy search  through their
 | 
						||
# contents...
 | 
						||
#}}}
 | 
						||
set -s buffer-limit 10
 | 
						||
 | 
						||
 | 
						||
# What does this option control?{{{
 | 
						||
#
 | 
						||
# It sets the time in milliseconds for which tmux waits after an escape is input
 | 
						||
# to determine if it is part of a function or meta key sequences.
 | 
						||
# The default is 500 millisec onds.
 | 
						||
#}}}
 | 
						||
# Why do you reset it?{{{
 | 
						||
#
 | 
						||
# The default  value introduces lag  when we use Vim  and escape from  insert to
 | 
						||
# normal mode.  We want to reduce the timeout.
 | 
						||
#}}}
 | 
						||
# Why don't you set it to 0 ?{{{
 | 
						||
#
 | 
						||
# >     Some people set  it to zero but  I consider that risky  if you're connecting
 | 
						||
# >     over a wide-area  network or there is anything else  that might insert small
 | 
						||
# >     delays between the delivery of chars in such a sequence.
 | 
						||
#
 | 
						||
# Source: https://github.com/tmux/tmux/issues/353#issuecomment-294570322
 | 
						||
#
 | 
						||
# Basically, we should still  let a few ms to be sure all  the keys in a control
 | 
						||
# sequence will have enough time to reach tmux.
 | 
						||
#}}}
 | 
						||
set -s escape-time 10
 | 
						||
 | 
						||
# If the terminal supports focus events, they will be requested by the tmux
 | 
						||
# client and passed through to the tmux server, then to the programs it runs.
 | 
						||
# Necessary to be able to listen to `FocusGained` and `FocusLost`.
 | 
						||
# Also necessary for `pane-focus-[in|out]` hooks.
 | 
						||
set -s focus-events on
 | 
						||
 | 
						||
# history of tmux commands (pfx :)
 | 
						||
set -s history-file "$HOME/.tmux/command_history"
 | 
						||
 | 
						||
# What does this do?{{{
 | 
						||
#
 | 
						||
# It makes  tmux sometimes  send an OSC  52 sequence –  which sets  the terminal
 | 
						||
# clipboard content – if  there is an `Ms` entry in  the terminfo description of
 | 
						||
# the outer terminal.
 | 
						||
#}}}
 | 
						||
#   What are the possible values of this option?{{{
 | 
						||
#
 | 
						||
#    - `on`
 | 
						||
#    - `external`
 | 
						||
#    - `off`
 | 
						||
#
 | 
						||
# ---
 | 
						||
#
 | 
						||
# There are 3 ways to create a tmux buffer:
 | 
						||
#
 | 
						||
#    1. invoke the `set-buffer` or `load-buffer` tmux commands
 | 
						||
#    2. copy text in copy mode (`send -X copy-selection`, `copy-pipe`, ...)
 | 
						||
#    3. send an OSC 52 sequence from an application inside tmux (e.g. `$ printf ...`)
 | 
						||
#
 | 
						||
# `1.` always creates a tmux buffer; never sets the X clipboard.
 | 
						||
# `2.` always creates a tmux buffer; sets the X clipboard via OSC 52 iff `set-clipboard` is not `off`.
 | 
						||
# `3.`        creates a tmux buffer *and* sets the X clipboard via OSC 52 iff `set-clipboard` is `on`.
 | 
						||
#
 | 
						||
# IOW, `external` makes  tmux *automatically* set the X clipboard  when you yank
 | 
						||
# sth in  copy mode via  OSC 52, while  `on` does the  same, but also  allows an
 | 
						||
# application to *manually* set a tmux buffer/the X clipboard via a OSC 52.
 | 
						||
#
 | 
						||
# Source: https://unix.stackexchange.com/a/560464/289772
 | 
						||
#}}}
 | 
						||
#   What is the possible drawback of the value `on`?{{{
 | 
						||
#
 | 
						||
# https://github.com/tmux/tmux/wiki/Clipboard#security-concerns
 | 
						||
#}}}
 | 
						||
#   How to disable OSC 52 for some terminals, but not all?{{{
 | 
						||
#
 | 
						||
#     # or use 'external'
 | 
						||
#     set -s set-clipboard on
 | 
						||
#     set -as terminal-overrides 'yourTERMname:Ms@'
 | 
						||
#                                                ^
 | 
						||
#       man terminfo /Similar Terminals/;/canceled
 | 
						||
#}}}
 | 
						||
set -s set-clipboard external
 | 
						||
 | 
						||
# Why do you move your 'terminal-overrides' settings in another file?{{{
 | 
						||
#
 | 
						||
# It makes it easier to source the settings only when the tmux server is started;
 | 
						||
# not when we manually re-source `tmux.conf`.
 | 
						||
#}}}
 | 
						||
#   Why do you need them to be sourced only once?{{{
 | 
						||
#
 | 
						||
# We *append* strings to the value of the 'terminal-overrides' option.
 | 
						||
# I don't want to append the same strings again and again every time I re-source
 | 
						||
# `tmux.conf`.
 | 
						||
#}}}
 | 
						||
#   Why don't you simply reset the option before appending a value?{{{
 | 
						||
#
 | 
						||
# That would make us lose the default value of the option:
 | 
						||
#
 | 
						||
#     terminal-overrides[0] "xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007:Cs=\\E]12;%p1%s\\007:Cr=\\E]112\\007:Ss=\\E[%p1%d q:Se=\\E[2 q"
 | 
						||
#     terminal-overrides[1] screen*:XT
 | 
						||
#
 | 
						||
# ---
 | 
						||
#
 | 
						||
# Besides, one of the value we append to 'terminal-overrides' depends on the value of `$TERM`.
 | 
						||
#
 | 
						||
#     if '[ "$TERM" != "st-256color" ]' 'set -as terminal-overrides ",*:Cr=\\E]112\\007"'
 | 
						||
#           ^----------------------^
 | 
						||
#
 | 
						||
# And the value of `$TERM` will be correct only the first time we source `tmux.conf`.
 | 
						||
#}}}
 | 
						||
 | 
						||
# What's the value of `$TERM` here?{{{
 | 
						||
#
 | 
						||
# The  first time  our `tmux.conf`  is sourced,  it matches  the `$TERM`  of the
 | 
						||
# outer terminal;  the next  times, it's the  value of  'default-terminal' (i.e.
 | 
						||
# 'tmux-256color').
 | 
						||
#}}}
 | 
						||
# What's the meaning of this `if` guard?{{{
 | 
						||
#
 | 
						||
# The condition `[ "$TERM" != "tmux-256color" ]` is true only the first time our
 | 
						||
# `tmux.conf` is sourced.
 | 
						||
# So, this part of the guard means: “if this is the first time the file is sourced”.
 | 
						||
# This is equivalent to `has('vim_starting')` in Vim.
 | 
						||
#
 | 
						||
# The condition `[ -n "$DISPLAY" ]` is true only in a GUI environment.
 | 
						||
# So, this part of the guard means: “don't source the file if we are in a console”.
 | 
						||
# Indeed, I doubt  a linux console is  able to understand any  sequence we might
 | 
						||
# want to use.
 | 
						||
#}}}
 | 
						||
#   Could we use `%if` instead of `if`?{{{
 | 
						||
#
 | 
						||
# You could try this:
 | 
						||
#
 | 
						||
#     %if "#{!=:$TERM,#{default-terminal}}"
 | 
						||
#     source-file "$HOME/.config/tmux/terminal-overrides.conf"
 | 
						||
#     %endif
 | 
						||
#
 | 
						||
# But it doesn't seem to work; the guard would not prevent the file from being re-sourced.
 | 
						||
# I think  that's because,  in this  case, `$TERM`  refers to  the value  in the
 | 
						||
# environment of  the tmux  server process;  and for  the latter,  `TERM` always
 | 
						||
# matches the outer terminal.
 | 
						||
#}}}
 | 
						||
if '[ "$TERM" != "#{default-terminal}" -a -n "$DISPLAY" ]' { source "$HOME/.config/tmux/terminal-overrides.conf" }
 | 
						||
 | 
						||
# Leave `default-terminal` at the end.{{{
 | 
						||
#
 | 
						||
# In my limited testing, moving it above would not cause an issue, but better be
 | 
						||
# safe than sorry.
 | 
						||
# In  particular,  I  want  to  be  sure  that  the  value  of  `$TERM`  is  not
 | 
						||
# 'tmux-256color'  the   first  time  our  `tmux.conf`   is  sourced;  otherwise
 | 
						||
# `terminal-overrides.conf` would never be sourced.
 | 
						||
#}}}
 | 
						||
# Why `-s` instead of `-g`? {{{
 | 
						||
#
 | 
						||
# Since tmux 2.1, `default-terminal` is a server option, not a session option.
 | 
						||
#
 | 
						||
# >     As a side effect this changes default-terminal  to be a server rather than a
 | 
						||
# >     session option.
 | 
						||
#
 | 
						||
# https://github.com/tmux/tmux/commit/7382ba82c5b366be84ca55c7842426bcf3d1f521
 | 
						||
# Confirmed by the  fact that `default-terminal` is described in  the section of
 | 
						||
# the server options in the man page.
 | 
						||
# Also confirmed by the fact that it's listed in the output of:
 | 
						||
#
 | 
						||
#     tmux show -s
 | 
						||
#
 | 
						||
# However, according to nicm:
 | 
						||
#
 | 
						||
# >     You do not have to use -s or -w for set-option except for user options.
 | 
						||
# >     tmux can work it out from the option name.
 | 
						||
# >     For show-option you do need it.
 | 
						||
#
 | 
						||
# So, we could omit `-s`, but I prefer to be explicit.
 | 
						||
#}}}
 | 
						||
# Why not let tmux use the default value `screen` (for `$TERM`)?{{{
 | 
						||
#
 | 
						||
# By default, most terminals set `$TERM` to `xterm` because the `xterm` entry is
 | 
						||
# present and set in the terminfo db of most machines.
 | 
						||
# tmux sets it to  `screen`, again, because it's a popular  entry (more than the
 | 
						||
# `tmux` one).
 | 
						||
# The `xterm`/`screen` value  implies that the terminal  will declare supporting
 | 
						||
# only 8 colors; confirmed by `$ tput colors`.
 | 
						||
#
 | 
						||
# Because of this,  the theme of some  programs might be off  (including Vim and
 | 
						||
# the terminal itself).  We want the terminal to declare it supports 256 colors,
 | 
						||
# which anyway is usually true.
 | 
						||
#}}}
 | 
						||
# Do we need `$TERM` to contain `tmux`?{{{
 | 
						||
#
 | 
						||
# Yes.  To support italics:
 | 
						||
#
 | 
						||
# The `screen-256color` entry in the terminfo db doesn't have a `sitm` field.
 | 
						||
# IOW, the db reports that screen is unable to support italics, which is true.
 | 
						||
# So, if we set `$TERM` to `screen-256color`, when an application will want to
 | 
						||
# make some text appear italicized, it will think it's not possible.
 | 
						||
# But  it *is*  possible, because  we  use tmux,  not screen.   And tmux  *does*
 | 
						||
# support the italics style.
 | 
						||
# The solution is to set `$TERM`  to `tmux-256color` so that when an application
 | 
						||
# queries  the terminfo  db, it  finds  the field  `sitm` with  the right  value
 | 
						||
# `\E[3m`.
 | 
						||
#
 | 
						||
# See also:
 | 
						||
# https://github.com/tmux/tmux/wiki/FAQ#i-dont-see-italics-or-italics-and-reverse-are-the-wrong-way-round
 | 
						||
# https://github.com/tmux/tmux/issues/175#issuecomment-152719805
 | 
						||
#}}}
 | 
						||
#   `256color`?{{{
 | 
						||
#
 | 
						||
# For a Vim color scheme to be correctly applied, no.
 | 
						||
# Because  it seems  that our  current theme  automatically sets  the number  of
 | 
						||
# colors to 256:
 | 
						||
#
 | 
						||
#     :runtime colors/seoul256.vim
 | 
						||
#     :echo &t_Co
 | 
						||
#
 | 
						||
# But, for the color schemes of other programs, maybe.
 | 
						||
#}}}
 | 
						||
set -s default-terminal tmux-256color
 | 
						||
 | 
						||
# Session {{{2
 | 
						||
 | 
						||
# Don't ring the bell in the current window.
 | 
						||
set -g bell-action other
 | 
						||
 | 
						||
# Why?{{{
 | 
						||
#
 | 
						||
# If a new window is created without any command to execute, tmux reads the
 | 
						||
# session option `default-command` to find one.
 | 
						||
# By default,  its value  is an empty  string which instructs  tmux to  create a
 | 
						||
# *login* shell using the value of the default-shell option.
 | 
						||
# The default value of the latter is `$SHELL` (atm: `/usr/local/bin/zsh`).
 | 
						||
#
 | 
						||
# When we create a new window, we  want a *non*-login shell, because a login zsh
 | 
						||
# shell  sources `~/.zprofile`,  which  we use  to execute  code  specific to  a
 | 
						||
# virtual *console* (set the background to white in the console).
 | 
						||
# This code is not suited to a virtual *terminal*.
 | 
						||
#
 | 
						||
# More  generally, we  don't  want a  *non*-login shell  to  source login  files
 | 
						||
# (`.profile`, `.zprofile`, `.zlogin`).
 | 
						||
#
 | 
						||
# So, we give the value zsh to `default-command` to prevent tmux from starting a
 | 
						||
# login shell.
 | 
						||
#}}}
 | 
						||
set -g default-command "$SHELL"
 | 
						||
 | 
						||
# Don't detach the client when the current session is killed.
 | 
						||
set -g detach-on-destroy off
 | 
						||
 | 
						||
# display status line messages and other on-screen indicators for 1s
 | 
						||
# (or until a key is pressed)
 | 
						||
set -g display-time 1000
 | 
						||
# display the indicators shown by the display-panes command for 5s
 | 
						||
set -g display-panes-time 5000
 | 
						||
 | 
						||
# increase scrollback buffer (2000 → 50000)
 | 
						||
#
 | 
						||
# `history-limit` has nothing to do with the history of executed tmux commands.
 | 
						||
# It controls the amount of lines you can scroll back when you enter copy mode.
 | 
						||
set -g history-limit 50000
 | 
						||
 | 
						||
# Index options
 | 
						||
# When we create a new window, tmux looks for an unused index, starting from 0.{{{
 | 
						||
#
 | 
						||
# I prefer 1, because:
 | 
						||
#
 | 
						||
#    - I usually count from 1, not 0
 | 
						||
#    - this lets us run `:movew -t :0` to move the current window in first position
 | 
						||
#
 | 
						||
# Note that you can't  run `:movew -t :1` to move the  window in first position,
 | 
						||
# because 1 is already taken by the first window.
 | 
						||
# `:movew` expects an index which is “free” (i.e. not used by any existing window).
 | 
						||
#
 | 
						||
# Also,  note that  when  running `:movew  -t :0`,  tmux  renumbers all  windows
 | 
						||
# automatically from whatever value is assigned to the 'base-index' option.
 | 
						||
#}}}
 | 
						||
set -g base-index 1
 | 
						||
#    │
 | 
						||
#    └ must be applied globally to all sessions
 | 
						||
#
 | 
						||
# same thing for the panes
 | 
						||
set -gw pane-base-index 1
 | 
						||
#    ││
 | 
						||
#    │└ window option
 | 
						||
#    └ must be applied globally to all windows
 | 
						||
 | 
						||
# make tmux capture the mouse and allow mouse events to be bound as key bindings
 | 
						||
set -g mouse on
 | 
						||
 | 
						||
# use `M-space` as a prefix
 | 
						||
set -g prefix M-space
 | 
						||
 | 
						||
# renumber windows, when:{{{
 | 
						||
#
 | 
						||
#    - we destroy one of them
 | 
						||
#    - we move the first window (index 1) at the end (index 99), by running `movew -t :99`
 | 
						||
#
 | 
						||
# to prevent holes in the sequence of indexes
 | 
						||
#}}}
 | 
						||
set -g renumber-windows on
 | 
						||
 | 
						||
# time for repeating of a hotkey bound using the -r flag without having to type the prefix again; default: 500
 | 
						||
set -g repeat-time 1000
 | 
						||
 | 
						||
# Some consoles don't like attempts to set the window title.
 | 
						||
# This might cause tmux to freeze the terminal when you attach to a session.
 | 
						||
# https://github.com/tmux/tmux/wiki/FAQ#tmux-freezes-my-terminal-when-i-attach-to-a-session-i-have-to-kill--9-the-shell-it-was-started-from-to-recover
 | 
						||
set -g set-titles off
 | 
						||
 | 
						||
# update the status line every 5 seconds (instead of 15s by default)
 | 
						||
set -g status-interval 5
 | 
						||
 | 
						||
# emacs key bindings in tmux command prompt (prefix + :) are better than vi keys,
 | 
						||
# even for vim users.
 | 
						||
set -g status-keys emacs
 | 
						||
 | 
						||
# color of status line
 | 
						||
set -g -F status-style "bg=#{?#{==:$DISPLAY,},blue,colour138}"
 | 
						||
 | 
						||
# Center the position of the window list component of the status line
 | 
						||
set -g status-justify centre
 | 
						||
 | 
						||
# cache the number of cpu cores in `~/.ncore`, which a shell command in 'status-right' is going to need
 | 
						||
if '[ ! -s "${HOME}/.ncore" ]' \
 | 
						||
    { run "lscpu | awk '/^CPU\\(s\\):\\s*[0-9]/ { print $2 }' >\"${HOME}/.ncore\"" }
 | 
						||
 | 
						||
# set the contents of the status line
 | 
						||
# What's `#[...]`?{{{
 | 
						||
#
 | 
						||
# It lets you embed some styles.
 | 
						||
# If you want to  apply the same style all over the left  part or the right part
 | 
						||
# of the status line, you can also use `status-left-style` or `status-right-style`:
 | 
						||
#
 | 
						||
#     set -g status-left '#[fg=colour15,bold] #S'
 | 
						||
#     ⇔
 | 
						||
#     set -g status-left       ' #S'
 | 
						||
#     set -g status-left-style '#[fg=colour15,bold]'
 | 
						||
#
 | 
						||
# However, I prefer  embedding the styles inside the value  of `status-left` and
 | 
						||
# `status-right`, because:
 | 
						||
#
 | 
						||
#    - it's more concise
 | 
						||
#    - it's more powerful: you can set the style of an arbitrary *portion* of the status line
 | 
						||
#
 | 
						||
# ---
 | 
						||
#
 | 
						||
# Note that you  can use this syntax only  in the value of an  option which sets
 | 
						||
# the *contents* of sth, not its style.
 | 
						||
# So, this is *not* a valid syntax:
 | 
						||
#
 | 
						||
#     # ✘
 | 
						||
#     set -g status-left-style '#[fg=colour15,bold]'
 | 
						||
#
 | 
						||
# Here, you must get rid of `#[...]`:
 | 
						||
#
 | 
						||
#     # ✔
 | 
						||
#     set -g status-left-style 'fg=colour15,bold'
 | 
						||
#}}}
 | 
						||
# What's `#{?...}`?{{{
 | 
						||
#
 | 
						||
# A conditional:
 | 
						||
#
 | 
						||
#     #{?test,val1,val2}
 | 
						||
#
 | 
						||
# For example:
 | 
						||
#
 | 
						||
#     {?client_prefix,#[bold],}
 | 
						||
#
 | 
						||
# This will be evaluated  into the style `bold` if the  prefix has been pressed,
 | 
						||
# or nothing otherwise.
 | 
						||
#}}}
 | 
						||
# Why do you use `nobold`?{{{
 | 
						||
#
 | 
						||
# We set the style `bold` for some part of the status line.
 | 
						||
# But a style applies to *all* the remaining text in the status line.
 | 
						||
# We need `nobold` to reset the style.
 | 
						||
#}}}
 | 
						||
# How can I include the time of the day or the hour in the status line?{{{
 | 
						||
#
 | 
						||
# Use `date(1)` and `%` items:
 | 
						||
#
 | 
						||
#     %a = day of week
 | 
						||
#     %d = day of month
 | 
						||
#     %b = month
 | 
						||
#     %R = hour
 | 
						||
#
 | 
						||
# See `man date`.
 | 
						||
#}}}
 | 
						||
set -g status-left ' #[fg=colour7]#{?client_prefix,#[fg=colour0],}#S#[fg=colour7]'
 | 
						||
 | 
						||
# Which alternative could I use to get the cpu load?{{{
 | 
						||
#
 | 
						||
#     $ uptime|awk '{split(substr($0, index($0, "load")), a, ":"); print a[2]}'
 | 
						||
#
 | 
						||
# https://github.com/tmux/tmux/wiki/FAQ#what-is-the-best-way-to-display-the-load-average-why-no-l
 | 
						||
#}}}
 | 
						||
# Why don't you write the code in a script and invoke it with `#(my-script.sh)`?{{{
 | 
						||
#
 | 
						||
# A script needs another shell to be interpreted.
 | 
						||
# The latter adds overhead, which would almost double the time the code needs to
 | 
						||
# be run.
 | 
						||
#
 | 
						||
# Check this:
 | 
						||
#
 | 
						||
#     $ cat <<'EOF' >/tmp/sh.sh
 | 
						||
#     awk 'BEGIN { getline load <"/proc/loadavg"; getline ncore <(ENVIRON["HOME"]"/.ncore"); printf("%d", 100 * load / ncore) }'
 | 
						||
#     EOF
 | 
						||
#     $ chmod +x /tmp/sh.sh
 | 
						||
#
 | 
						||
#     $ time zsh -c 'repeat 100 /tmp/sh.sh'
 | 
						||
#     ... 0,420 total˜
 | 
						||
#     $ time zsh -c 'repeat 100 awk '\''BEGIN { getline load <"/proc/loadavg"; getline ncore <(ENVIRON["HOME"]"/.ncore"); printf("%d", 100 * load / ncore) }'\'''
 | 
						||
#     ... 0,193 total˜
 | 
						||
#}}}
 | 
						||
# Why do you double the percent sign in `printf("%%d", ...)`?{{{
 | 
						||
#
 | 
						||
# The code is going to be expanded inside the value of 'status-right'.
 | 
						||
# And the  latter is always passed  to `strftime(3)` for which  the percent sign
 | 
						||
# has a special meaning.
 | 
						||
# As a result, if you don't double the  percent sign – to make it literal – `%d`
 | 
						||
# will be replaced with the current day of the month (01, 02, ..., 31).
 | 
						||
#
 | 
						||
# From `man tmux /status-right`:
 | 
						||
#
 | 
						||
# >     As  with status-left,  string will  be passed  to strftime(3)  and character
 | 
						||
# >     pairs are replaced.
 | 
						||
#}}}
 | 
						||
cpu='awk '\''BEGIN { \
 | 
						||
    getline load <"/proc/loadavg"; \
 | 
						||
    getline ncore <(ENVIRON["HOME"]"/.ncore"); \
 | 
						||
    printf("%%d", 100 * load / ncore) }'\'''
 | 
						||
 | 
						||
mem='free | awk '\''/Mem/ { total = $2; used = $3 }; \
 | 
						||
    END { printf("%%d", 100 * used / total) }'\'''
 | 
						||
# TODO: Maybe we could get rid of `free(1)`, by inspecting `/proc/meminfo`.
 | 
						||
# However,  I can  find the  second field  ("total") of  `free(1)` in  this file
 | 
						||
# (first line: "MemTotal"), but not the third one ("used").
 | 
						||
#
 | 
						||
# Update: From `man free`:
 | 
						||
#
 | 
						||
#     used   Used memory (calculated as total - free - buffers - cache)
 | 
						||
#
 | 
						||
# You would have to read 4 files to compute the `used` field.
 | 
						||
# Make some tests (with `time(1)`) to see whether the resulting `awk(1)` command
 | 
						||
# is slower than what we currently run.
 | 
						||
 | 
						||
# TODO: Color the numbers in red if they exceed some threshold.
 | 
						||
# Try to capture the  output of the 2 shell commands in  tmux variables, so that
 | 
						||
# we can test them in a conditional.
 | 
						||
set -g  status-right '#[fg=colour235]M #[fg=colour15,bold]'
 | 
						||
set -ga status-right "#($mem) "
 | 
						||
set -ga status-right '#[fg=colour235,nobold]C #[fg=colour15,bold]'
 | 
						||
set -ga status-right "#($cpu) "
 | 
						||
 | 
						||
setenv -gu cpu
 | 
						||
setenv -gu mem
 | 
						||
 | 
						||
# Why do you want `COLORTERM` to be automatically updated?{{{
 | 
						||
#
 | 
						||
# It can be useful to detect a terminal which lies about its identity.
 | 
						||
# E.g., xfce4-terminal advertises  itself as `xterm-256color`, but  the value of
 | 
						||
# its `COLORTERM` variable is 'xfce4-terminal'.
 | 
						||
#
 | 
						||
# So, the more reliable  `COLORTERM` is, the better we can  detect that we're in
 | 
						||
# xfce4-terminal, and react appropriately.
 | 
						||
# This can be useful, for example, to prevent vim-term from sending `CSI 2 SPC q`
 | 
						||
# when we're leaving Vim from xfce4-terminal on Ubuntu 16.04.
 | 
						||
# The latter  doesn't understand this sequence,  and once sent to  the terminal,
 | 
						||
# tmux will regularly reprint the sequence wherever our cursor is.
 | 
						||
#}}}
 | 
						||
# Why could I be tempted to run the same command for `LESSOPEN`, `LESSCLOSE`, `LS_COLORS`?{{{
 | 
						||
#
 | 
						||
#     setenv -gu LESSOPEN
 | 
						||
#     setenv -gu LESSCLOSE
 | 
						||
#     setenv -gu LS_COLORS
 | 
						||
#
 | 
						||
# These environment variables are set in  `~/.zshenv`, but only on the condition
 | 
						||
# they've not been set yet.
 | 
						||
# The purpose of the condition is to make the shell quicker to start.
 | 
						||
# Indeed, setting these variables adds around 8ms to the shell's startup time.
 | 
						||
# However, if they are set in the tmux global environment, then they'll never be
 | 
						||
# reset  when  we  start a  new  shell,  because  the  condition will  never  be
 | 
						||
# satisfied.
 | 
						||
#
 | 
						||
# This means that we can't change the value of these variables by simply editing
 | 
						||
# `~/.zshenv`, which can be an issue.
 | 
						||
#}}}
 | 
						||
#   Why don't you do it?{{{
 | 
						||
#
 | 
						||
# Because it would add around 8ms to the startup time of every shell we ask tmux
 | 
						||
# to open.
 | 
						||
#}}}
 | 
						||
#     Isn't this an issue?{{{
 | 
						||
#
 | 
						||
# No.
 | 
						||
# If you want to modify one of these variables, and if you want the change to be
 | 
						||
# applied immediately without  restarting the tmux server, do it  in the context
 | 
						||
# of the tmux global environment:
 | 
						||
#
 | 
						||
#     $ tmux setenv -g LESSOPEN new_value
 | 
						||
#}}}
 | 
						||
if '[ "$TERM" != "#{default-terminal}" ]' { set -ga update-environment COLORTERM }
 | 
						||
# TODO: We have several similar `if` conditions.  Maybe we should write only one,
 | 
						||
# and put inside all the commands we want to run.
 | 
						||
# This would make tmux start a little faster.
 | 
						||
 | 
						||
# display a message when activity is detected in a window
 | 
						||
# Why?{{{
 | 
						||
#
 | 
						||
# We  haven't customized  the  status line  to include  an  indicator when  some
 | 
						||
# activity is detected in a window, because by default we don't monitor activity
 | 
						||
# ('monitor-activity' is off).
 | 
						||
# Indeed, generally, most windows will produce some output and have some activity.
 | 
						||
# Seeing a lot of indicators in the status line, all the time, is meaningless.
 | 
						||
#
 | 
						||
# But we do  have a key binding to temporarily  toggle 'monitor-activity' in the
 | 
						||
# current window; so, we  need a way to be notified when  some activity is later
 | 
						||
# detected in it.
 | 
						||
#}}}
 | 
						||
set -g visual-activity on
 | 
						||
 | 
						||
# Window {{{2
 | 
						||
 | 
						||
# Use vi key bindings in copy mode.
 | 
						||
set -gw mode-keys vi
 | 
						||
 | 
						||
# colors of *borders* of focused and non-focused panes
 | 
						||
set -gw pane-active-border-style 'fg=colour138,bg=#cacaca'
 | 
						||
set -gw pane-border-style        'fg=colour138,bg=#cacaca'
 | 
						||
 | 
						||
# How to insert the index of a window?{{{
 | 
						||
#
 | 
						||
# Use the alias `#I`.
 | 
						||
#}}}
 | 
						||
# How to insert its flags, like `Z` for a zoomed window?{{{
 | 
						||
#
 | 
						||
# Use the alias `#F`.
 | 
						||
#}}}
 | 
						||
# Set what to display for the current window (then for the other ones), and how,
 | 
						||
# in the status line window list.
 | 
						||
# See: https://github.com/tmux/tmux/issues/74#issuecomment-129130023
 | 
						||
set -gw window-status-current-format '#[fg=colour232,bg=colour253]#W#F#{?window_zoomed_flag, #[fg=blue]#P/#{window_panes},}'
 | 
						||
set -gw window-status-format '#[fg=colour232#,bg=colour248]#W#F#[bg=default]'
 | 
						||
 | 
						||
# Pane {{{2
 | 
						||
 | 
						||
# colors of focused and non-focused panes
 | 
						||
# Because we use `-gw`, the colors will affect any pane.{{{
 | 
						||
#
 | 
						||
# But, at runtime, you could use `-p` to set the color of a given pane when it's
 | 
						||
# (un)focused differently.
 | 
						||
#}}}
 | 
						||
set -gw window-active-style 'bg=#dbd6d1'
 | 
						||
set -gw window-style        'bg=#cacaca'
 | 
						||
# }}}1
 | 
						||
# Key Bindings {{{1
 | 
						||
# root {{{2
 | 
						||
 | 
						||
# `F1`, ..., `F10` are used in `htop(1)`.
 | 
						||
# `F11` and `F12` are used in WeeChat to scroll in the nicklist bar.
 | 
						||
bind -T root S-F8 run -b 'tmux_log'
 | 
						||
 | 
						||
# Why do you rebind `command-prompt` to `pfx + ;`?  It's already bound to `pfx + :`...{{{
 | 
						||
#
 | 
						||
# We  often press  the prefix  key by  accident, then  press `:`  to open  Vim's
 | 
						||
# command-line.  As a result, we open tmux command-line; it's distracting.
 | 
						||
#}}}
 | 
						||
bind ';' command-prompt
 | 
						||
unbind :
 | 
						||
# Do *not* bind `command-prompt` to `M-:`; we press it by accident too frequently.
 | 
						||
 | 
						||
# focus next/previous window
 | 
						||
# I'm frequently pressing these key bindings in Vim's insert mode.  It's distracting!{{{
 | 
						||
#
 | 
						||
# Idea1: Use `pfx w` to focus an  arbitrary window, and supercharge `pfx h/l` to
 | 
						||
# focus the next/previous pane or window.
 | 
						||
#
 | 
						||
#     bind -r h if -F '#{pane_at_left}' 'prev' 'selectp -L'
 | 
						||
#     bind -r l if -F '#{pane_at_right}' 'next' 'selectp -R'
 | 
						||
#
 | 
						||
# Idea2: Use `M-h/l` twice when the current pane is running Vim.
 | 
						||
#
 | 
						||
#     set -g @foo 0
 | 
						||
#     bind -T root M-l if -F '#{m:*vim,#{pane_current_command}}' { if -F '#{@foo}' { set -g @foo 0 ; next } { set -g @foo 1 } } { next }
 | 
						||
#     bind -T root M-h if -F '#{m:*vim,#{pane_current_command}}' { if -F '#{@foo}' { set -g @foo 0 ; prev } { set -g @foo 1 } } { prev }
 | 
						||
#
 | 
						||
# Idea3: Make tmux send `M-h` or `M-l` when  Vim is running in the current pane,
 | 
						||
# and let Vim decide what to do, based on whether we're in insert mode or normal
 | 
						||
# mode.
 | 
						||
#
 | 
						||
#     noremap! <expr> <m-h> <sid>m_hl('h')
 | 
						||
#     noremap! <expr> <m-l> <sid>m_hl('l')
 | 
						||
#     nno <expr> <m-h> <sid>m_hl('h')
 | 
						||
#     nno <expr> <m-l> <sid>m_hl('l')
 | 
						||
#     xno <expr> <m-h> <sid>m_hl('h')
 | 
						||
#     xno <expr> <m-l> <sid>m_hl('l')
 | 
						||
#
 | 
						||
#     fu s:m_hl(seq) abort
 | 
						||
#         if mode() =~# '^[ic]$'
 | 
						||
#             return ''
 | 
						||
#         endif
 | 
						||
#         call system('tmux '..(a:seq is# 'l' ? 'next' : 'prev'))
 | 
						||
#         return ''
 | 
						||
#     endfu
 | 
						||
#     bind -T root M-l if -F '#{m:*vim,#{pane_current_command}}' 'send M-l' 'next'
 | 
						||
#     bind -T root M-h if -F '#{m:*vim,#{pane_current_command}}' 'send M-h' 'prev'
 | 
						||
#
 | 
						||
# Problem: When we're running Vim without config (`-Nu NONE`), we can't focus another tmux window.
 | 
						||
# This is because those custom mappings are not installed then.
 | 
						||
#}}}
 | 
						||
# Why do you inspect these window flags?{{{
 | 
						||
#
 | 
						||
# To prevent the commands from wrapping around the edges.
 | 
						||
# They do that by default, and that bothers me at the moment.
 | 
						||
#
 | 
						||
# For example, I often want to focus  the next window, and press `¹` by accident
 | 
						||
# instead of  `²`.  It  still works,  because we  only have  2 windows,  but that
 | 
						||
# prevents me from learning to press the correct keys.
 | 
						||
#
 | 
						||
# Once you're confident that those keys are well-chosen, and they've passed into
 | 
						||
# your muscle memory, you could just install:
 | 
						||
#
 | 
						||
#     bind -T root ¹ prev
 | 
						||
#     bind -T root ² next
 | 
						||
#}}}
 | 
						||
bind -T root ¹ if -F '#{window_start_flag}' {} { prev }
 | 
						||
bind -T root ² if -F '#{window_end_flag}' {} { next }
 | 
						||
# TODO: Sometimes, we press these keys by accident.  Find better ones?{{{
 | 
						||
#
 | 
						||
# In particular,  when we press  `[ox` (where `x`  is some character)  to toggle
 | 
						||
# some Vim setting, we  need to press `AltGr` to produce  `[`; but sometimes, we
 | 
						||
# don't release the key before pressing `o`.
 | 
						||
# As a  result, we  press `AltGr  + o`  which produce  `²`; tmux  intercepts the
 | 
						||
# keypress, and tries to visit the  previous window, while in reality, we wanted
 | 
						||
# to toggle some Vim setting.
 | 
						||
#}}}
 | 
						||
 | 
						||
# `M-s` to enter copy mode
 | 
						||
# Do *not* bind `M-s` to anything while in copy mode!{{{
 | 
						||
#
 | 
						||
# This would  make you lose  an interesting  feature of the  `copy-mode` command
 | 
						||
# while you're already in copy mode, reading  the output of some command such as
 | 
						||
# `list-keys`.
 | 
						||
#
 | 
						||
# The default behavior makes tmux show you the contents of the original window:
 | 
						||
#
 | 
						||
#     # you're reading a file
 | 
						||
#     :list-keys
 | 
						||
#     :copy-mode
 | 
						||
#     # the window shows again the file you were reading
 | 
						||
#     # press `q`, and you get back the output of `:list-keys`
 | 
						||
#
 | 
						||
# I don't know where this is documented.
 | 
						||
# And I don't  know why the `copy-mode`  command is invoked when  we press `M-s`
 | 
						||
# while in copy mode.
 | 
						||
# We only  have one key  binding using `M-s`  as its lhs,  and it's in  the root
 | 
						||
# table, not in the copy-mode table.
 | 
						||
#
 | 
						||
# Note that this feature is not specific to our `M-s` key binding.
 | 
						||
# I can reproduce with no config (and `C-b [` instead of `M-s`).
 | 
						||
#}}}
 | 
						||
bind -T root M-s copy-mode
 | 
						||
 | 
						||
bind -T root M-z resize-pane -Z
 | 
						||
bind -T root M-Z lastp \; resize-pane -Z
 | 
						||
 | 
						||
# Do *not* exit copy mode when when we reach the bottom of the scrollback buffer.{{{
 | 
						||
#
 | 
						||
# We remove the `-e` flag which is  passed to `copy-mode` by default, so that if
 | 
						||
# we enter  copy mode by scrolling  the mouse wheel  upward, and we press  a key
 | 
						||
# which reaches the bottom of the scrollback buffer, we don't quit copy mode.
 | 
						||
#
 | 
						||
# If you leave `-e` in the default key binding, here's what could happen:
 | 
						||
# you  scroll the  wheel upward  to  enter copy  mode;  at one  point, you  keep
 | 
						||
# pressing `C-d` to scroll toward the  bottom; once you reach the bottom, you'll
 | 
						||
# quit copy mode, and `C-d` will close the shell if the command-line is empty.
 | 
						||
#}}}
 | 
						||
# Where did you find the code?{{{
 | 
						||
#
 | 
						||
#     $ tmux -Lx -f/dev/null start \; lsk | grep 'root.*WheelUpPane'
 | 
						||
#}}}
 | 
						||
bind -T root WheelUpPane \
 | 
						||
    if -F -t= '#{mouse_any_flag}' \
 | 
						||
        { send -M } \
 | 
						||
        { if -Ft= '#{pane_in_mode}' 'send -M' 'copy-mode -t=' }
 | 
						||
 | 
						||
# But *do* exit copy mode if we scroll downward with the mouse wheel and reach the bottom of the buffer.
 | 
						||
bind -T copy-mode-vi WheelDownPane \
 | 
						||
    selectp \; \
 | 
						||
    send -X -N 5 scroll-down \; \
 | 
						||
    if -F '#{scroll_position}' '' 'send -X cancel'
 | 
						||
 | 
						||
# copy-mode-vi {{{2
 | 
						||
 | 
						||
bind -T copy-mode-vi C-Space send -X set-mark
 | 
						||
# actually, it should be named "exchange-point-and-mark"...
 | 
						||
bind -T copy-mode-vi C-x send -X jump-to-mark
 | 
						||
 | 
						||
# jump Back to the Beginning of the previous shell command{{{
 | 
						||
#
 | 
						||
# Look  for the  previous shell  prompt, to  get to  the beginning  of the  last
 | 
						||
# command output.  After  pressing the key binding, you can  visit all the other
 | 
						||
# prompts by pressing `n` or `N`.
 | 
						||
#
 | 
						||
# Inspiration: https://www.youtube.com/watch?v=uglorjY0Ntg
 | 
						||
#}}}
 | 
						||
bind -T copy-mode-vi ! send -X start-of-line \; send -X search-backward '٪'
 | 
						||
 | 
						||
# Make  tmux use the  prefix 'buf_' instead of  'buffer' when naming  the buffer
 | 
						||
# storing the copied selection.
 | 
						||
bind -T copy-mode-vi Enter send -X copy-selection-and-cancel 'buf_'
 | 
						||
 | 
						||
bind -T copy-mode-vi g switchc -T g-prefix
 | 
						||
bind -T g-prefix     g send -X history-top
 | 
						||
# Open a visually selected text (filepath or url) by pressing `gf` or `gx`.
 | 
						||
# TODO: The key binding will break if the file name contains double quotes.{{{
 | 
						||
#
 | 
						||
# Find a way to escape special characters.
 | 
						||
#
 | 
						||
# I tried `$ tmux display -p '#{q:#(tmux pasteb)}'`, but it doesn't work.
 | 
						||
# You probably need `q:`,  but a modifier needs to be followed by  the name of a
 | 
						||
# replacement variable and `#(tmux pasteb)` is not one.
 | 
						||
#
 | 
						||
# Update:
 | 
						||
# I don't think you should use `q:`.
 | 
						||
# Maybe you should  try to find a shell utility  which quotes special characters
 | 
						||
# in a given text.
 | 
						||
# Does such a tool exist?
 | 
						||
# If it does, maybe you could try: `#(magic_tool $(tmux pasteb))`.
 | 
						||
#
 | 
						||
# Update:
 | 
						||
# `#{}` can be used for a user option (`@foo`).
 | 
						||
# You could temporarily  set a user option with the  the filepath/url, and quote
 | 
						||
# it with `q:`.
 | 
						||
#
 | 
						||
# Make some tests on that:
 | 
						||
#
 | 
						||
#     http://example.org/foo/bar"baz.html
 | 
						||
#     http://example.org/foo/bar'baz.html
 | 
						||
#     https://www.reddit.com/r/Fantasy/
 | 
						||
#
 | 
						||
#     bind -T copy-mode-vi x send -X copy-selection-and-cancel \; \
 | 
						||
#         run 'tmux set @copied_url "$(tmux showb)"' \; \
 | 
						||
#         run 'xdg-open "#{q:@copied_url}"'
 | 
						||
#
 | 
						||
# For  some reason,  we need  2 `run-shell`,  otherwise, it  seems that  the key
 | 
						||
# binding doesn't update the url, when we try a new one.
 | 
						||
#
 | 
						||
# For some reason, when we try to open this:
 | 
						||
#
 | 
						||
#     http://example.org/a'b.html
 | 
						||
#
 | 
						||
# tmux opens this instead:
 | 
						||
#
 | 
						||
#     http://example.org/a/'b.html
 | 
						||
#                         ^
 | 
						||
#                         ✘
 | 
						||
#
 | 
						||
# For some reason, when we try to open this:
 | 
						||
#
 | 
						||
#     http://example.org/a"b.html
 | 
						||
#
 | 
						||
# tmux doesn't escape the double quote.
 | 
						||
#
 | 
						||
#     Text ended before matching quote was found for ".˜
 | 
						||
#     (The text was '/usr/bin/firefox "http://example.org/foo/bar"baz.html"')˜
 | 
						||
#
 | 
						||
#     $ tmux set @foo "a'b" \; display -p '#{q:@foo}'
 | 
						||
#     a\'b˜
 | 
						||
#
 | 
						||
#     $ tmux set @foo "a'b" \; run 'echo #{q:@foo}'
 | 
						||
#     a'b˜
 | 
						||
#
 | 
						||
# Why doesn't `run-shell` expand the `#{q:}` format?
 | 
						||
#
 | 
						||
# Update: you need to quote the format:
 | 
						||
#
 | 
						||
#     $ tmux set @foo "a'b" \; run 'echo "#{q:@foo}"'
 | 
						||
#     a\'b˜
 | 
						||
#
 | 
						||
# Update:
 | 
						||
# I don't think it's possible.
 | 
						||
# Try to open the urls via `urlscan(1)`.
 | 
						||
# The latter fails for the first urls.
 | 
						||
# If a specialized tool fails, I doubt we can do better.
 | 
						||
#}}}
 | 
						||
# FIXME: `gf` fails to open a file path starting with `~/`.
 | 
						||
bind -T g-prefix f send -X pipe "xargs -I {} tmux run 'xdg-open \"{}\"'"
 | 
						||
bind -T g-prefix x send -X pipe "xargs -I {} tmux run 'xdg-open \"{}\"'"
 | 
						||
 | 
						||
bind -T copy-mode-vi  v    if -F '#{selection_present}' { send -X clear-selection } { send -X begin-selection }
 | 
						||
bind -T copy-mode-vi  V    if -F '#{selection_present}' { send -X clear-selection } { send -X select-line }
 | 
						||
bind -T copy-mode-vi  C-v  if -F '#{selection_present}' \
 | 
						||
    { if -F '#{rectangle_toggle}' \
 | 
						||
        { send -X rectangle-toggle ; send -X clear-selection } \
 | 
						||
        { send -X rectangle-toggle } \
 | 
						||
    } { send -X begin-selection ; send -X rectangle-toggle }
 | 
						||
 | 
						||
# set -s copy-command 'xsel -i'
 | 
						||
# if there's a selection, make `y` yank it
 | 
						||
# without selection, make `yy` yank the current line and `yiw` the current word
 | 
						||
bind -T copy-mode-vi y if -F '#{selection_present}' \
 | 
						||
    { send -X copy-pipe-and-cancel 'xsel -i -b' 'buf_' } \
 | 
						||
    { switchc -T operator-pending-and-cancel }
 | 
						||
# y**y**
 | 
						||
bind -T operator-pending-and-cancel y send -X copy-line 'buf_'
 | 
						||
# y**iw**
 | 
						||
bind -T operator-pending-and-cancel i switchc -T text-object-and-cancel
 | 
						||
# Do *not* use `select-word`: https://github.com/tmux/tmux/issues/2126
 | 
						||
bind -T text-object-and-cancel w \
 | 
						||
    { send -X cursor-right
 | 
						||
      send -X previous-word
 | 
						||
      send -X begin-selection
 | 
						||
      send -X next-word-end
 | 
						||
      send -X copy-selection-and-cancel 'buf_' }
 | 
						||
 | 
						||
bind -T copy-mode-vi . run "zsh -c \"tmux source =(sed -n '/^# #{@dot_command}/,/^$/p' $HOME/.config/tmux/repeat.conf)\""
 | 
						||
 | 
						||
# **"A**yiw  **"A**yy  v_**"A**y
 | 
						||
bind -T copy-mode-vi '"' switchc -T specify-register
 | 
						||
bind -T specify-register A switchc -T operate-on-register
 | 
						||
# Why the `if 'tmux showb'`?{{{
 | 
						||
#
 | 
						||
# `append-selection` doesn't accept the optional prefix buffer name argument.
 | 
						||
# If there's no buffer, `append-selection` will  create a buffer with the prefix
 | 
						||
# name `buffer`; we want the prefix `buf_`.
 | 
						||
#}}}
 | 
						||
# "A**y**iw  "A**y**y  v_"A**y**
 | 
						||
bind -T operate-on-register y if -F '#{selection_present}' \
 | 
						||
    { if 'tmux showb' { send -X append-selection } { send -X copy-selection 'buf_' }} \
 | 
						||
    { switchc -T operator-pending }
 | 
						||
# "Ay**i**w
 | 
						||
bind -T operator-pending i switchc -T text-object
 | 
						||
# "Ay**y**
 | 
						||
bind -T operator-pending y { run "zsh -c \"tmux source =(sed -n '/^# yy/,/^$/p' $HOME/.config/tmux/repeat.conf)\"" }
 | 
						||
 | 
						||
# v**i**w
 | 
						||
bind -T copy-mode-vi i switchc -T text-object
 | 
						||
# Why pass a second command to the first `if`?{{{
 | 
						||
#
 | 
						||
# To support `"Ayiw`.
 | 
						||
#}}}
 | 
						||
# vi**w**  "Ayi**w**
 | 
						||
bind -T text-object w if -F '#{selection_present}' \
 | 
						||
    { send -X stop-selection
 | 
						||
      send -X cursor-right
 | 
						||
      send -X previous-word
 | 
						||
      send -X begin-selection
 | 
						||
      send -X next-word-end } \
 | 
						||
    { run "zsh -c \"tmux source =(sed -n '/^# yiw/,/^$/p' $HOME/.config/tmux/repeat.conf)\"" }
 | 
						||
 | 
						||
bind -T copy-mode-vi Y send -X copy-end-of-line 'buf_'
 | 
						||
 | 
						||
# Why don't you pass `-b` to run?{{{
 | 
						||
#
 | 
						||
# There's no need to.
 | 
						||
# `pipe-and-cancel` doesn't block.
 | 
						||
# The shell command passed as an argument is forked.
 | 
						||
#}}}
 | 
						||
bind -T copy-mode-vi S send -X pipe-and-cancel \
 | 
						||
    "xargs -I {} tmux run 'xdg-open \"https://www.startpage.com/do/dsearch?query={}\"'"
 | 
						||
 | 
						||
# Why? {{{
 | 
						||
#
 | 
						||
# `search-backward-incremental`  is  better  than `search-forward`,  because  it
 | 
						||
# highlights  all the  matches as  you  type (like  in Vim  when 'hlsearch'  and
 | 
						||
# 'incsearch' are both set); you need to pass `-i` to `command-prompt` for it to work.
 | 
						||
#
 | 
						||
# Also, these key bindings make the prompt less noisy (`/` is shorter than `search down`).
 | 
						||
#
 | 
						||
# Inspired from the default emacs key bindings in copy mode.
 | 
						||
# }}}
 | 
						||
bind -T copy-mode-vi / command-prompt -ip '/' { send -X search-forward-incremental '%%' }
 | 
						||
bind -T copy-mode-vi ? command-prompt -ip '?' { send -X search-backward-incremental '%%' }
 | 
						||
 | 
						||
bind -T copy-mode-vi % send -X next-matching-bracket
 | 
						||
bind -T copy-mode-vi _ send -X start-of-line
 | 
						||
 | 
						||
# move current window position forward/backward
 | 
						||
# Why not using `h` and `l`, or `j` and `k`?{{{
 | 
						||
#
 | 
						||
# `M-C-[jk]` could  be more  useful for something  else (WeeChat?),  and doesn't
 | 
						||
# match a horizontal motion.
 | 
						||
# `M-C-[hl]` conflicts with our window manager (move virtual desktop).
 | 
						||
# `M-C-[HL]` is hard to press.
 | 
						||
#}}}
 | 
						||
bind -r > if -F '#{window_end_flag}' { movew -t :0 } { swapw -t :+ ; selectw -n }
 | 
						||
bind -r < if -F '#{window_start_flag}' { movew -t :99 } { swapw -t :- ; selectw -p }
 | 
						||
# If you don't like `:99`, you could write this instead:{{{
 | 
						||
#
 | 
						||
#     bind -r < if -F '#{window_start_flag}' \
 | 
						||
#         { run 'tmux movew -t:$((#{W:#{?window_end_flag,#I,}}+1))' } \
 | 
						||
#         { swapw -t :- ; selectw -p }
 | 
						||
#}}}
 | 
						||
 | 
						||
# prefix {{{2
 | 
						||
 | 
						||
# NOTE: `C-\` is free.
 | 
						||
 | 
						||
# cycle through predefined layouts
 | 
						||
# Do *not* pass `-r` to `bind`!{{{
 | 
						||
#
 | 
						||
# We use Space in Vim as a prefix key.
 | 
						||
# If you use  `-r` here, when you're in  Vim there's a risk that  when you press
 | 
						||
# Space as a prefix key, it's consumed by tmux to run `nextl` instead.
 | 
						||
#}}}
 | 
						||
bind Space nextl
 | 
						||
 | 
						||
# focus last pane, without breaking the zoomed state of the window
 | 
						||
bind M-Space lastp -Z
 | 
						||
 | 
						||
# display short description for the next keypress (inspired from a default key binding)
 | 
						||
bind M-h command-prompt -k -p key { lsk -1N '%%' }
 | 
						||
#                       ├┘              ├─┘{{{
 | 
						||
#                       │               └ -N instead show keys and attached notes in the root and prefix key tables;
 | 
						||
#                       │                 with -1 only the first matching key and note is shown
 | 
						||
#                       └ -k is like -1 but the key press is translated to a key name
 | 
						||
#}}}
 | 
						||
# What is the side effect of `-1`?{{{
 | 
						||
#
 | 
						||
# Not only does it limit the output of the command to the first matching key and
 | 
						||
# note, but it also redirects where it's displayed.
 | 
						||
# Without `-1`, it's displayed on the terminal in copy-mode.
 | 
						||
# With `-1`, it's displayed as a message on the tmux status line.
 | 
						||
#}}}
 | 
						||
 | 
						||
# display short description for the next 2 keypresses
 | 
						||
bind M-l command-prompt -1p 'key1,key2' \
 | 
						||
    { run "tmux lsk | awk '/-T prefix\s+%1\s+/ { print \$NF }' | xargs -I {} tmux lsk -1N -P 'M-Space %1 ' -T {} '%2'" }
 | 
						||
 | 
						||
# repeat last shell command in last active pane
 | 
						||
# Warning: This overrides a default key binding:{{{
 | 
						||
#
 | 
						||
#     bind-key -T prefix . command-prompt -T target "move-window -t '%%'"
 | 
						||
#}}}
 | 
						||
bind . if -F -t '{last}' '#{m:*sh,#{pane_current_command}}' { send -t '{last}' Up Enter }
 | 
						||
 | 
						||
# copy clipboard selection into tmux buffer
 | 
						||
# Why `run`?{{{
 | 
						||
#
 | 
						||
# To make the shell evaluate the command substitution.
 | 
						||
#}}}
 | 
						||
#   `--`?{{{
 | 
						||
#
 | 
						||
# The evaluation of the substitution command could start with a hyphen.
 | 
						||
# And  if that  happens,  tmux could  parse  the  text as  an  option passed  to
 | 
						||
# `set-buffer` (i.e. `-a`, `-b`, or `-n`).
 | 
						||
#}}}
 | 
						||
#   `-o`?{{{
 | 
						||
#
 | 
						||
# To make `xsel(1x)` output something.
 | 
						||
#}}}
 | 
						||
bind b switchc -T buffer
 | 
						||
bind -T buffer -N 'copy clipboard into tmux buffer' > run 'tmux setb -- "$(xsel -ob)"' \; display 'clipboard copied into tmux buffer'
 | 
						||
bind -T buffer -N 'copy tmux buffer into clipboard' < choose-buffer -F '#{buffer_sample}' \
 | 
						||
    { run 'tmux showb -b "%%" | xsel -ib' ; display 'tmux buffer copied into clipboard' }
 | 
						||
 | 
						||
# We use `*` instead of `q` because it's more consistent with `#`.
 | 
						||
# They  both show  information.  Besides, if  I hit  `pfx q`  by accident  (which
 | 
						||
# happens often), I won't be distracted by the panes numbers.
 | 
						||
 | 
						||
bind * displayp
 | 
						||
 | 
						||
bind ! show-messages
 | 
						||
 | 
						||
# make these default key bindings repeatable
 | 
						||
# Do *not* pass `-r` to `bind`!{{{
 | 
						||
#
 | 
						||
# Suppose you're in the  'study' session, Vim is running, and  the Vim window is
 | 
						||
# horizontally split in 2 viewports.
 | 
						||
# You press `pfx +  )` to switch to the 'fun' session, then  you press `)` to go
 | 
						||
# back to the 'study' session.
 | 
						||
# Finally you press C-j to focus the Vim split below; it won't work because of this:
 | 
						||
#
 | 
						||
#     bind -r C-j resizep -D 5
 | 
						||
#}}}
 | 
						||
bind ( switchc -p
 | 
						||
bind ) switchc -n
 | 
						||
 | 
						||
# Problem: tmux-fingers doesn't let us search outside the current screen.
 | 
						||
# Solution: Install a key binding which lets us search through the scrollback buffer, in a Vim buffer.
 | 
						||
# What does `-J` do for `capture-pane`?{{{
 | 
						||
#
 | 
						||
# It joins wrapped lines.
 | 
						||
#
 | 
						||
# Suppose that we have a long line in a file, which doesn't fit on a single line
 | 
						||
# of the terminal, but on two.
 | 
						||
# If  you  run `$  cat  file`,  this too-long  line  will  be displayed  on  two
 | 
						||
# consecutive lines of the terminal.
 | 
						||
# Without `-J`, tmux  would copy – in  one of its buffers –  the two consecutive
 | 
						||
# lines on two different lines.
 | 
						||
#
 | 
						||
# But that's not what we want.
 | 
						||
# We want the buffer to join back these two lines, as they were originally in the file.
 | 
						||
#}}}
 | 
						||
#   `-S -`? {{{
 | 
						||
#
 | 
						||
# `-S` specifies the starting line number, from where to copy.
 | 
						||
# The special value `-` refers to the start of the history.
 | 
						||
# Without this, `capture-pane` would capture only from the first visible line in
 | 
						||
# the pane; we want the *whole* scrollback buffer.
 | 
						||
#}}}
 | 
						||
# Why don't you use `split-window` instead of `popup`?{{{
 | 
						||
#
 | 
						||
# With `split-window`, you would also need to run `resize-pane -Z`.
 | 
						||
# But what if there's already a zoomed pane in the current window?
 | 
						||
# After quitting Vim, the latter would be unzoomed.
 | 
						||
# So, we use `popup` to preserve a possible zoomed pane in the current window.
 | 
						||
#}}}
 | 
						||
bind -T root M-c if -F \
 | 
						||
    '#{||:#{m:*vim,#{pane_current_command}},#{==:#{pane_current_command},man}}' \
 | 
						||
    '' \
 | 
						||
    { capture-pane -b scrollback -J -S -
 | 
						||
      popup -E -xC -yC -w75% -h75% -d '#{pane_current_path}' \
 | 
						||
          "tmux showb -b scrollback | vim --not-a-term +'call tmux#formatCapture#main()' - ; \
 | 
						||
           tmux deleteb -b scrollback" }
 | 
						||
 | 
						||
# split window vertically / horizontally
 | 
						||
# When the window is zoomed, we often forget that it's already split, and wrongly press `pfx _`.{{{
 | 
						||
#
 | 
						||
# Make `pfx _`  smarter; i.e. if the  window is already split  and zoomed, don't
 | 
						||
# split it again, instead focus the previous pane.
 | 
						||
#}}}
 | 
						||
bind _   if -F '#{window_zoomed_flag}' 'lastp' 'split-window -v  -c "#{pane_current_path}"'
 | 
						||
bind |   if -F '#{window_zoomed_flag}' 'lastp' 'split-window -h  -c "#{pane_current_path}"'
 | 
						||
bind -   if -F '#{window_zoomed_flag}' 'lastp' 'split-window -fv -c "#{pane_current_path}"'
 | 
						||
bind '\' if -F '#{window_zoomed_flag}' 'lastp' 'split-window -fh -c "#{pane_current_path}"'
 | 
						||
#                                                                ├───────────────────────┘
 | 
						||
#                                                                └ keep current working directory
 | 
						||
 | 
						||
bind -N 'bring arbitrary pane in current window' [ command-prompt -p 'join pane from:' { join-pane -s '%%' }
 | 
						||
bind -N 'send current pane in arbitrary window' ] command-prompt -p 'send pane to:' { join-pane -t '%%' }
 | 
						||
bind T breakp
 | 
						||
 | 
						||
# Why a space before every shell command (` cmus`, ` weechat`, ...)?{{{
 | 
						||
#
 | 
						||
# It's useful  to prevent  zsh from saving  the command in  the history  when we
 | 
						||
# cancel the search with `C-c` or `C-d` (`setopt HIST_IGNORE_SPACE`).
 | 
						||
#}}}
 | 
						||
# What's the `-n` option passed to `neww`?{{{
 | 
						||
#
 | 
						||
# It sets the name of the window.
 | 
						||
#}}}
 | 
						||
# What about the `-c` option?{{{
 | 
						||
#
 | 
						||
# It sets the cwd of the shell.
 | 
						||
#}}}
 | 
						||
bind M-1 rename -t 0 fun \; \
 | 
						||
    renamew -t 1 music \; \
 | 
						||
    send ' cmus' 'Enter' '2' 'Enter' 'Enter' \; \
 | 
						||
    neww -n irc -c $HOME \; \
 | 
						||
    send ' weechat' 'Enter' \; \
 | 
						||
    new -s study \; \
 | 
						||
    send ' nv' 'Enter'
 | 
						||
 | 
						||
# you need the display command to force tmux to clear the log (`set message-limit 0` is not enough)
 | 
						||
bind C set -F @message-limit-save '#{message-limit}' \; \
 | 
						||
       set message-limit 0 \; display 'message log cleared' \; \
 | 
						||
       set -F message-limit '#{@message-limit-save}' \; set -u @message-limit-save
 | 
						||
 | 
						||
# Note that `clear-history` doesn't clear *all* the history.{{{
 | 
						||
#
 | 
						||
# The last lines of the scrollback buffer which fits in one screen are preserved.
 | 
						||
# So, if you enter copy mode, you'll still  be able to scroll back *some* lines,
 | 
						||
# but not more than a few dozens.
 | 
						||
#}}}
 | 
						||
# We can't use `C-l` for the lhs, because we already use it in another key binding:{{{
 | 
						||
#
 | 
						||
#     bind -r C-l resizep -R 5
 | 
						||
#}}}
 | 
						||
bind C-c send C-l \; clear-history
 | 
						||
#             │      │
 | 
						||
#             │      └ clear tmux scrollback buffer
 | 
						||
#             └ clear terminal screen
 | 
						||
 | 
						||
# Do *not* use `q` in the prefix table; pressed by accident too frequently.
 | 
						||
bind Q switchc -T Q-prefix
 | 
						||
bind -T Q-prefix q confirm 'kill-pane'
 | 
						||
bind -T Q-prefix Q confirm 'kill-window'
 | 
						||
 | 
						||
# Why `TERM="#{client_termname}"` in the 'sourced files' entry?{{{
 | 
						||
#
 | 
						||
# When `$  tmux -v -Ldm` is  started, it inherits  the TERM of the  current tmux
 | 
						||
# server, which is set by 'default-terminal'.
 | 
						||
# As a  result, the condition `[  if '[ "$TERM" !=  #{default-terminal} ]'` is
 | 
						||
# true, and several files which we expect to be sourced, won't be sourced.
 | 
						||
#
 | 
						||
# We want to see all files which would  be sourced if we were to start tmux from
 | 
						||
# a regular shell; so we need to reset TERM.
 | 
						||
#}}}
 | 
						||
# Why don't you pass `-v` to `show-options`?{{{
 | 
						||
#
 | 
						||
# If you do, it would considerably simplify our commands; we wouldn't need `sed(1)` at all.
 | 
						||
# Unfortunately, it would also fuck up the output if one of the alias is defined
 | 
						||
# on several lines.
 | 
						||
#
 | 
						||
# By avoiding `-v`, we make sure that each alias is output on a single line.
 | 
						||
#}}}
 | 
						||
bind i display-menu -x 0 -y 0 \
 | 
						||
    'server information' i info \
 | 
						||
    'key bindings' K lsk \
 | 
						||
    'aliases' a { run 'tmux show -s command-alias | column -t -s= | sed "s/^command-alias\[[0-9]*]\s*//; s/^\"\|\"$//g"' } \
 | 
						||
    'sourced files' f { run 'cd "$(mktemp -d /tmp/.tmux.XXXXXXXXXX)" \
 | 
						||
        ; TERM="#{client_termname}" tmux -v -Ldm start \
 | 
						||
        ; grep loading tmux-server*.log | grep -v grep | sed "s/.*loading \(.*\)/\1/"' } \
 | 
						||
    '' \
 | 
						||
    'options' o { display-menu -y 0 \
 | 
						||
        'server options' C-s { show -s } \
 | 
						||
        'global session options' s { show -g } \
 | 
						||
        'local session options' S { show } \
 | 
						||
        '' \
 | 
						||
        'global window options' w { show -gw } \
 | 
						||
        'local window options' W { show -w } \
 | 
						||
        'local pane options' p { show -p } \
 | 
						||
    } \
 | 
						||
    '' \
 | 
						||
    'global hooks' h { show-hooks -g } \
 | 
						||
    'local hooks' H { show-hooks } \
 | 
						||
    '' \
 | 
						||
    'global environment' e { showenv -g } \
 | 
						||
    'local environment' E { showenv } \
 | 
						||
    '' \
 | 
						||
    'outer terminfo description' t { run 'infocmp -1x "#{client_termname}" | sort' } \
 | 
						||
    'inner terminfo description' T { run 'infocmp -1x "#{default-terminal}" | sort' } \
 | 
						||
    '' \
 | 
						||
    'default settings' d { display-menu -y 0 \
 | 
						||
        'key bindings' K { run 'tmux -Ldm -f/dev/null start \; lsk' } \
 | 
						||
        'aliases' a { run 'tmux -Ldm -f/dev/null start \; show -sv command-alias | column -t -s= | sed "s/^command-alias\\[[0-9]]\\s*//; s/^\"\|\"$//g"' } \
 | 
						||
        '' \
 | 
						||
        'server options' C-s { run 'tmux -Ldm -f/dev/null start \; show -s' } \
 | 
						||
        'window options' w { run 'tmux -Ldm -f/dev/null start \; show -gw' } \
 | 
						||
        'session options' s { run 'tmux -Ldm -f/dev/null start \; show -g' } \
 | 
						||
    }
 | 
						||
 | 
						||
# By default, `detach-session` is bound to `d`.
 | 
						||
# I find that too easy to press, so we move it to `@`.
 | 
						||
# Why `@`?
 | 
						||
# I didn't find anything better, and it seems hard to press by accident...
 | 
						||
bind @ detach
 | 
						||
 | 
						||
# resize pane
 | 
						||
bind -r C-h resizep -L 5
 | 
						||
bind -r C-j resizep -D 5
 | 
						||
bind -r C-k resizep -U 5
 | 
						||
bind -r C-l resizep -R 5
 | 
						||
 | 
						||
# focus neighboring panes
 | 
						||
# Do *not* make them repeatable.  It leads to a confusing user experience.{{{
 | 
						||
#
 | 
						||
# Example: Press `pfx k` to focus the pane above which is running Vim, then press `j`.
 | 
						||
# Expected: Vim scrolls downward.
 | 
						||
# Actual Result: tmux focuses back the pane below.
 | 
						||
#
 | 
						||
# If  you have  many  panes, and  you  need to  focus  one, try  `display-panes`
 | 
						||
# (currently bound to `pfx *`), then press the index of the desired pane.
 | 
						||
#}}}
 | 
						||
bind h selectp -L
 | 
						||
bind l selectp -R
 | 
						||
bind j selectp -D
 | 
						||
bind k selectp -U
 | 
						||
 | 
						||
# move pane to the far right/left/bottom/top
 | 
						||
bind H split-window -fhb \; swap-pane -t ! \; kill-pane -t !
 | 
						||
bind L split-window -fh  \; swap-pane -t ! \; kill-pane -t !
 | 
						||
bind J split-window -fv  \; swap-pane -t ! \; kill-pane -t !
 | 
						||
bind K split-window -fvb \; swap-pane -t ! \; kill-pane -t !
 | 
						||
 | 
						||
# Toggle mouse.
 | 
						||
# Temporarily preventing  tmux from  handling the  mouse can  be useful  in some
 | 
						||
# terminals to copy text in the clipboard.
 | 
						||
# Why `M` for the lhs?{{{
 | 
						||
#
 | 
						||
# It provides a good mnemonic for “mouse”.
 | 
						||
# I don't use `C-m` nor `M-m` because, atm, they're used to display some default menus.
 | 
						||
#
 | 
						||
# However, note that `pfx M` is used by default to clear the marked pane (`select-pane -M`).
 | 
						||
# It's not a big deal to lose it, because we can get the same result by focusing
 | 
						||
# the marked pane and then pressing `pfx m` (`select-pane -m`).
 | 
						||
# The latter marks the pane if it's not already, or clears the mark otherwise.
 | 
						||
#}}}
 | 
						||
bind M set -g mouse \; display 'mouse: #{?#{mouse},ON,OFF}'
 | 
						||
 | 
						||
# toggle 'monitor-activity' in current window
 | 
						||
bind C-a set -w monitor-activity \; display 'monitor-activity: #{?#{monitor-activity},ON,OFF}'
 | 
						||
 | 
						||
# kill all panes except the current one (similar to `:only` or `C-w o` in Vim)
 | 
						||
bind o kill-pane -a
 | 
						||
 | 
						||
# paste last tmux buffer
 | 
						||
# Do *not* choose a key too easy to type.{{{
 | 
						||
#
 | 
						||
# It's dangerous.
 | 
						||
# In Vim, the contents  of the buffer will be typed,  which will have unexpected
 | 
						||
# results, unless you're in insert mode.
 | 
						||
#}}}
 | 
						||
bind C-p paste-buffer -p
 | 
						||
 | 
						||
# choose and paste arbitrary tmux buffer
 | 
						||
# What's `-Z`?{{{
 | 
						||
#
 | 
						||
# It makes tmux zoom the pane so that it takes the whole window.
 | 
						||
#}}}
 | 
						||
#   `-F`?{{{
 | 
						||
#
 | 
						||
# It specifies the format with which each buffer should be displayed.
 | 
						||
# In it, you can use these replacement variables:
 | 
						||
#
 | 
						||
#    ┌────────────────┬─────────────────────────────┐
 | 
						||
#    │ buffer_created │ creation date of the buffer │
 | 
						||
#    ├────────────────┼─────────────────────────────┤
 | 
						||
#    │ buffer_name    │ name of the buffer          │
 | 
						||
#    ├────────────────┼─────────────────────────────┤
 | 
						||
#    │ buffer_sample  │ starting text of the buffer │
 | 
						||
#    ├────────────────┼─────────────────────────────┤
 | 
						||
#    │ buffer_size    │ size of the buffer          │
 | 
						||
#    └────────────────┴─────────────────────────────┘
 | 
						||
#
 | 
						||
# Note that  even with an empty  format, tmux will  still display the name  of a
 | 
						||
# buffer followed by a colon.
 | 
						||
# So, `buffer_name` is  not very useful (unless you want to print  the name of a
 | 
						||
# buffer twice).
 | 
						||
#}}}
 | 
						||
#   the `-p` argument passed to `paste-buffer`?{{{
 | 
						||
#
 | 
						||
# It prevents the shell from  automatically running a pasted text which contains
 | 
						||
# a newline.
 | 
						||
#
 | 
						||
# See `man tmux /^\s*paste-buffer`
 | 
						||
#}}}
 | 
						||
bind p choose-buffer -Z -F '#{buffer_sample}' "paste-buffer -p -b '%%'"
 | 
						||
 | 
						||
# similar to `C-w r` and `C-w R` in Vim
 | 
						||
bind -r r rotate-window -D \; selectp -t :.+
 | 
						||
bind -r R rotate-window -U \; selectp -t :.-
 | 
						||
 | 
						||
# reload tmux config
 | 
						||
bind C-r source "$HOME/.config/tmux/tmux.conf" \; display 'Configuration reloaded'
 | 
						||
 | 
						||
# You need to install the `urlscan(1)` utility for this key binding to work.
 | 
						||
# Why do you include `deleteb` inside the shell cmd run by `split-window`?{{{
 | 
						||
#
 | 
						||
# If you move it outside:
 | 
						||
#
 | 
						||
#     bind u capture-pane \; split-window -l 10 'urlscan =(tmux showb)' \; deleteb
 | 
						||
#
 | 
						||
# `urlscan(1)` can't find any link.
 | 
						||
#
 | 
						||
# This is because:
 | 
						||
#
 | 
						||
#    1. deleteb is run before `$ tmux showb`
 | 
						||
#    2. thus `$ tmux showb` outputs nothing
 | 
						||
#    3. urlscan finds no url
 | 
						||
#
 | 
						||
# You can get the same effect by running:
 | 
						||
#
 | 
						||
#     $ tmux split-window 'urlscan =(echo "")'
 | 
						||
#}}}
 | 
						||
# We name the tmux buffer so that we can remove it reliably at the end.{{{
 | 
						||
#
 | 
						||
# Indeed,  you might  copy  some text  while  the urlscan  pane  is opened  (not
 | 
						||
# necessarily  in the  latter; in  any session,  window, pane),  creating a  new
 | 
						||
# buffer at the top of the stack.
 | 
						||
# If you just run  `$ tmux deleteb`, it would remove that  buffer instead of the
 | 
						||
# buffer created by `capture-pane`.
 | 
						||
#}}}
 | 
						||
# Why `head -c -1`?{{{
 | 
						||
#
 | 
						||
# If there is no url in the tmux buffer, we want tmux to automatically close the
 | 
						||
# pane.  That's why  we use `ifne(1)` later; it runs  the second `urlscan(1)` on
 | 
						||
# the condition that  the output of the  previous one is empty.   The problem is
 | 
						||
# that even when the first `urlscan(1)` fails  to find any url, it still outputs
 | 
						||
# a single newline.  We need to remove it, so that `ifne(1)` works as expected.
 | 
						||
#}}}
 | 
						||
bind u capture-pane -b urlscan \; \
 | 
						||
       split-window -l 10 "
 | 
						||
              tmux showb -b urlscan | \
 | 
						||
              urlscan --no-browser | \
 | 
						||
              head -c -1 | \
 | 
						||
              ifne urlscan --compact \
 | 
						||
                      --dedupe \
 | 
						||
                      --nohelp \
 | 
						||
                      --regex \"(http|ftp)s?://[^ '\\\">)}\\\\]]+\" \
 | 
						||
            ; tmux deleteb -b urlscan
 | 
						||
        "
 | 
						||
 | 
						||
# focus next pane
 | 
						||
bind -r C-w selectp -t :.+
 | 
						||
 | 
						||
# similar to `C-w x` in Vim
 | 
						||
bind x swap-pane -U
 | 
						||
bind X swap-pane -D
 | 
						||
# }}}1
 | 
						||
# Hooks {{{1
 | 
						||
# Don't use this hook: `set-hook -g after-split-window 'selectl even-vertical'`{{{
 | 
						||
#
 | 
						||
# You wouldn't be able to split vertically anymore.
 | 
						||
# Splitting vertically would result in an horizontal split no matter what.
 | 
						||
#
 | 
						||
# The  hook is  given as  an example  in `man  tmux`; its  purpose is  to resize
 | 
						||
# equally all the panes whenever you split a pane horizontally.
 | 
						||
#}}}
 | 
						||
 | 
						||
set-hook -g pane-focus-out ''
 | 
						||
 | 
						||
# Plugins {{{1
 | 
						||
 | 
						||
# Why the guard?{{{
 | 
						||
#
 | 
						||
# To prevent  the plugins from  re-installing their  key bindings every  time we
 | 
						||
# resource `tmux.conf`.
 | 
						||
# Indeed, we only unbind the key bindings from the copy-mode table once.
 | 
						||
#
 | 
						||
# Besides, it's probably a bad idea to resource plugins.
 | 
						||
#}}}
 | 
						||
if '[ "$TERM" != "#{default-terminal}" ]' { source "$HOME/.config/tmux/plugins/run" }
 | 
						||
 | 
						||
# Rebind {{{1
 | 
						||
 | 
						||
# Purpose:{{{
 | 
						||
#
 | 
						||
# The tmux-yank plugin installs this key binding:
 | 
						||
#
 | 
						||
#     bind-key -T copy-mode-vi Y send-keys -X copy-pipe-and-cancel "tmux paste-buffer"
 | 
						||
#
 | 
						||
# It copies the selection, quit copy mode, then paste the buffer.
 | 
						||
#
 | 
						||
# However, it doesn't support the bracketed paste mode.
 | 
						||
# So we  redefine the key binding,  and pass `-p` to  `paste-buffer` to surround
 | 
						||
# the text with the sequences `Esc [ 200 ~` and `Esc [ 201 ~`.
 | 
						||
# This way, if we  select a text containing a newline, then  press `p`, it's not
 | 
						||
# automatically run by the shell.
 | 
						||
#
 | 
						||
# From `man tmux /^\s*paste-buffer`:
 | 
						||
#
 | 
						||
# >     If -p  is specified,  paste bracket  control codes  are inserted  around the
 | 
						||
# >     buffer if the application has requested bracketed paste mode.
 | 
						||
#
 | 
						||
# Note that this requires that the shell supports the bracketed paste mode.
 | 
						||
# I.e. if you're using  zsh, you need zsh version 5.1 or  greater, and if you're
 | 
						||
# using bash, you need bash 4.4 or greater.
 | 
						||
#
 | 
						||
# ---
 | 
						||
#
 | 
						||
# The `-p` option was added to tmux in the commit `f4fdddc`.
 | 
						||
# According to the changelog, this was somewhere between tmux 1.6 and 1.7.
 | 
						||
#
 | 
						||
# ---
 | 
						||
#
 | 
						||
# Note that  the original key binding used `copy-pipe-and-cancel`  which – while
 | 
						||
# working – doesn't make sense; you can't pipe anything to `$ tmux paste-buffer`,
 | 
						||
# since it doesn't read its input.
 | 
						||
#}}}
 | 
						||
bind -T copy-mode-vi p send -X copy-selection-and-cancel \; paste-buffer -p \; deleteb
 | 
						||
#                                                                        ^^
 | 
						||
 | 
						||
# Unbind {{{1
 | 
						||
 | 
						||
# How to find the default key bindings installed with no config?{{{
 | 
						||
#
 | 
						||
#     $ tmux -Lx -f/dev/null new
 | 
						||
#     C-b ?
 | 
						||
#     VG$
 | 
						||
#     Enter
 | 
						||
#     $ vim
 | 
						||
#     i
 | 
						||
#     C-b ]
 | 
						||
#
 | 
						||
# Make sure to release `Ctrl` before pressing `]`.
 | 
						||
#}}}
 | 
						||
# How to unbind `#`, `~`, `'`, `"`?{{{
 | 
						||
#
 | 
						||
# Quote the key (with single or double quotes).
 | 
						||
#
 | 
						||
# From `man tmux /^KEY BINDINGS`:
 | 
						||
#
 | 
						||
# >     Note that to bind the ‘"’ or ‘'’ keys, quotation marks are necessary.
 | 
						||
#}}}
 | 
						||
# How to unbind `;`?{{{
 | 
						||
#
 | 
						||
# Escape it.
 | 
						||
#
 | 
						||
# From `man tmux /^COMMANDS`:
 | 
						||
#
 | 
						||
# >     A literal  semicolon may be  included by escaping  it with a  backslash (for
 | 
						||
# >     example, when specifying a command sequence to bind-key).
 | 
						||
#}}}
 | 
						||
 | 
						||
# TODO:
 | 
						||
# Remove all default key bindings which you're not interested in.
 | 
						||
# Some of them could be hit by accident.
 | 
						||
# Keep only the ones you really use.
 | 
						||
# Besides, it will give us a smaller table of key bindings, which will be easier
 | 
						||
# to read when we have an issue with one of our key bindings.
 | 
						||
# Have a look at `~/Desktop/tmux.md`.
 | 
						||
 | 
						||
# prefix {{{2
 | 
						||
 | 
						||
# send-prefix
 | 
						||
unbind C-b
 | 
						||
# rotate-window
 | 
						||
unbind C-o
 | 
						||
# show-messages
 | 
						||
unbind '~'
 | 
						||
# split-window
 | 
						||
unbind '"'
 | 
						||
# choose-buffer -Z
 | 
						||
unbind =
 | 
						||
# detach-client
 | 
						||
unbind d
 | 
						||
# next-window
 | 
						||
unbind n
 | 
						||
# swap-pane -[UD]
 | 
						||
unbind '{'
 | 
						||
unbind '}'
 | 
						||
# select-pane -[UDLR]
 | 
						||
unbind Up
 | 
						||
unbind Down
 | 
						||
unbind Left
 | 
						||
unbind Right
 | 
						||
# tmux clear-history (tmux-logging)
 | 
						||
unbind M-c
 | 
						||
# rotate-window -D
 | 
						||
unbind M-o
 | 
						||
# resize-pane -U 5
 | 
						||
unbind M-up
 | 
						||
# resize-pane -D 5
 | 
						||
unbind M-down
 | 
						||
# resize-pane -L 5
 | 
						||
unbind M-left
 | 
						||
# resize-pane -R 5
 | 
						||
unbind M-right
 | 
						||
# resize-pane -[UDLR]
 | 
						||
unbind C-Up
 | 
						||
unbind C-Down
 | 
						||
unbind C-Left
 | 
						||
unbind C-Right
 | 
						||
# run ~/.config/tmux/plugins/tmux-logging/scripts/screen_capture.sh (tmux-logging)
 | 
						||
unbind M-p
 | 
						||
# run ~/.config/tmux/plugins/tmux-logging/scripts/save_complete_history.sh (tmux-logging)
 | 
						||
unbind M-P
 | 
						||
# resize-pane -Z
 | 
						||
unbind z
 | 
						||
# command-prompt -i -p / { send-keys -X search-forward-incremental "%%" }
 | 
						||
unbind /
 | 
						||
 | 
						||
# copy-mode-vi {{{2
 | 
						||
 | 
						||
# By default, it's bound to `send-keys -X copy-pipe-and-cancel`.{{{
 | 
						||
#
 | 
						||
# I don't like that, because I often select some text with the mouse by accident
 | 
						||
# (or when I'm bored); when that happens, obviously, tmux creates a buffer.
 | 
						||
#
 | 
						||
# This pollutes  our list of buffers,  and makes the interesting  ones harder to
 | 
						||
# find.  Besides, if when  I want to copy some text, I will  certainly not do it
 | 
						||
# with the mouse (not accurate enough).
 | 
						||
#}}}
 | 
						||
unbind -T copy-mode-vi MouseDragEnd1Pane
 | 
						||
# send-keys -X begin-selection
 | 
						||
unbind -T copy-mode-vi Space
 | 
						||
# send-keys -X copy-pipe-and-cancel
 | 
						||
unbind -T copy-mode-vi C-j
 | 
						||
# send -X copy-pipe-and-cancel 'xsel -i --clipboard; tmux paste-buffer' (tmux-yank)
 | 
						||
unbind -T copy-mode-vi M-y
 | 
						||
# (tmux-yank)
 | 
						||
unbind -T copy-mode-vi Y
 | 
						||
 | 
						||
# copy-mode {{{2
 | 
						||
 | 
						||
# We don't need the key bindings from the copy-mode table; we use the copy-mode-*vi* table.
 | 
						||
# Why the guard?{{{
 | 
						||
#
 | 
						||
# Once the table is empty, it's removed.
 | 
						||
# So, if you later try to unbind a key binding from it, an error will be raised:
 | 
						||
#
 | 
						||
#     Table copy-mode doesn't exist
 | 
						||
#
 | 
						||
# Which can be repeated for every key binding you try to remove:
 | 
						||
#
 | 
						||
#     Table copy-mode doesn't exist
 | 
						||
#     Table copy-mode doesn't exist
 | 
						||
#     ...
 | 
						||
#
 | 
						||
# Run `show-messages` to see them.
 | 
						||
#
 | 
						||
# This is annoying when you reload `tmux.conf`.
 | 
						||
#}}}
 | 
						||
if '[ "$TERM" != "#{default-terminal}" ]' { source "$HOME/.config/tmux/unbind-copy-mode.conf" }
 | 
						||
# }}}1
 |