Reload of tmux config not unbinding keys (bind-key is cumulative)
According to the tmux(1)
man page, unbind-key -a
is what you are looking for.
Note that tmux
runs a server that will only exit once all sessions are closed, and the key-bindings are per-server. Hence once you create a binding, it will be persistent over all client detaches.
That said, put unbind-key -a
at the very top of your configuration file, and on config reload it should do what you want - unbind everything and start binding from scratch. Or - if your modifications are smaller - unbind only what you want to change.
The correct solution (by Peter
So @peterph gave the correct answer which is unbind-key -a
which does the following: (man tmux)
If -a is present, all key bindings are removed.
A workable solution
The problem (for me) is that "all" actually means all. Including the keybindings tmux comes with. If you execute the unbind-key -a
command tmux instantly doesn't have any keybindings at all anymore so you can't even enter command mode or do anything basically.
My (rather ugly) fix for this is the following:
- create a
.tmux.reset.conf
that removes all keybindings and then rebinds all the ones tmux has by default - source that reset at the top of your
.tmux.conf
My .tmux.conf
:
# always load the reset file first
source-file ~/.tmux.reset.conf
My .tmux.reset.conf
:
# First remove *all* keybindings
unbind-key -a
# Now reinsert all the regular tmux keys
bind-key C-b send-prefix
bind-key C-o rotate-window
bind-key C-z suspend-client
bind-key Space next-layout
bind-key ! break-pane
bind-key " split-window
bind-key # list-buffers
bind-key $ command-prompt -I #S "rename-session '%%'"
bind-key % split-window -h
bind-key & confirm-before -p "kill-window #W? (y/n)" kill-window
bind-key ' command-prompt -p index "select-window -t ':%%'"
bind-key ( switch-client -p
bind-key ) switch-client -n
bind-key , command-prompt -I #W "rename-window '%%'"
bind-key - delete-buffer
bind-key . command-prompt "move-window -t '%%'"
bind-key 0 select-window -t :0
bind-key 1 select-window -t :1
bind-key 2 select-window -t :2
bind-key 3 select-window -t :3
bind-key 4 select-window -t :4
bind-key 5 select-window -t :5
bind-key 6 select-window -t :6
bind-key 7 select-window -t :7
bind-key 8 select-window -t :8
bind-key 9 select-window -t :9
bind-key : command-prompt
bind-key ; last-pane
bind-key = choose-buffer
bind-key ? list-keys
bind-key D choose-client
bind-key L switch-client -l
bind-key [ copy-mode
bind-key ] paste-buffer
bind-key c new-window
bind-key d detach-client
bind-key f command-prompt "find-window '%%'"
bind-key i display-message
bind-key l last-window
bind-key n next-window
bind-key o select-pane -t :.+
bind-key p previous-window
bind-key q display-panes
bind-key r refresh-client
bind-key s choose-session
bind-key t clock-mode
bind-key w choose-window
bind-key x confirm-before -p "kill-pane #P? (y/n)" kill-pane
bind-key { swap-pane -U
bind-key } swap-pane -D
bind-key ~ show-messages
bind-key PPage copy-mode -u
bind-key -r Up select-pane -U
bind-key -r Down select-pane -D
bind-key -r Left select-pane -L
bind-key -r Right select-pane -R
bind-key -r M-1 select-layout even-horizontal
bind-key -r M-2 select-layout even-vertical
bind-key -r M-3 select-layout main-horizontal
bind-key -r M-4 select-layout main-vertical
bind-key -r M-5 select-layout tiled
bind-key -r M-n next-window -a
bind-key -r M-o rotate-window -D
bind-key -r M-p previous-window -a
bind-key -r M-Up resize-pane -U 5
bind-key -r M-Down resize-pane -D 5
bind-key -r M-Left resize-pane -L 5
bind-key -r M-Right resize-pane -R 5
bind-key -r C-Up resize-pane -U
bind-key -r C-Down resize-pane -D
bind-key -r C-Left resize-pane -L
bind-key -r C-Right resize-pane -R
It kinda looked like this could have worked with tmux key-tables (as far as I can tell) but you can't add new key-tables.
There is currently no direct way to reset a key’s binding to its default; the initialization of the default bindings (in key_bindings_init()
) is done once when the tmux server first starts (in server_start()
), and there is no mechanism to reset a single key.
For your desired scenario where you want the act of sourcing your configuration file to reestablish a default binding that was previously overridden by a custom binding that has since been deleted from your configuration file, the method you devised is reasonable (though unfortunately verbose): unbind-key -a
, then reestablish all the “default” bindings, then establish your custom bindings (some of which might override a “default” binding).
A server’s current bindings can be extracted with the list-keys
command*; this can help generate/maintain your proposed .tmux.reset.conf
file, but you need a way to extract the default bindings, not the current bindings.
*
There are some situations where the output of list-keys
is not currently directly usable: the binding for semicolon needs its semicolon escaped with a backslash to prevent it from being interpreted as a tmux command separator, and any bindings that had arguments that used double quotes inside single quotes (none of the default bindings are like this) will come out as double quotes inside double qoutes.
To get the default bindings you need a temporary server with a minimal configuration (i.e. no custom bindings) so that you can capture its list-keys
output. There is no limit to the number of tmux servers you can run, but each one must use a different socket pathname; the -L
and -S
tmux options can be used to specify a socket name (in $TMPDIR/tmux-$UID
or full socket pathname. So, to talk to (or start) a new server on a socket named temp
, you would use this:
tmux -L temp …
To make sure it does not use your .tmux.conf
, you use -f
to tell it to read /dev/null
(a special file that is always empty):
tmux -f /dev/null -L temp …
Note: this does not prevent the processing of /etc/tmux.conf
, if such a file exists; the path to this “system configuration file” is hard-coded and there is no option to bypass it (short of patching the code).
Normally, you need a new-session
command to actually start the server, but we do not want any sessions, just an initialized server to query. The start-server
command does just that: starts a server without creating any sessions.
tmux -f /dev/null -L temp start-server …
Now, we just need to append our “query” command (list-keys
in this case):
tmux -f /dev/null -L temp start-server \; list-keys
Note: the semicolon needs to be escaped or quoted to prevent the shell from treating it as a shell command separator since we want it to be a tmux command separator.
Since there are no sessions to maintain, the server will exit automatically after it finishes running the list-keys
command.
So, you can use a command like this to generate the bulk of your .tmux.reset.conf
without having to worry about temporarily removing your .tmux.conf
file (to let you see just the default bindings) and without having to shut down any existing servers.
If the run-shell
command was synchronous you could embed a call like this in your configuration file (capturing to a temporary file that you would then process with source-file
) instead of having a static file (your .tmux.reset.conf
). That would let you always use the default bindings from your current version of tmux (the default bindings change occasionally). Alas, the completion of the run-shell
command is currently asynchronous with respect to subsequent commands (commands that come after a run-shell
command will usually run before the process spawned by run-shell
has had a chance to finish).