31

I've been experimenting with different tmux keybinding settings and I've noticed the following:

If I reload my tmux config (from within tmux) the keybindings I once had loaded will remain loaded. The only way (I know of) to clean this up is to quit all tmux sessions and restart. So it looks like tmux remembers all previously loaded keybindings and will only remove them on a fresh start or by explicitly unbinding them.

To recreate this:

  • open a terminal (A)
  • start tmux
  • check whether the keybinding shows a clock (press PREFIX C-t)
  • press PREFIX ? to see the keybinding in the list
  • edit ~/.tmux.conf
  • add a keybinding (bind C-t display "Keybinding C-t")
  • reload tmux config (PREFIX : source-file ~/.tmux.conf)
  • check whether the keybinding works (press PREFIX C-t)
  • press PREFIX ? to see the new keybinding in the list
  • edit ~/.tmux.conf again
  • remove the keybinding (so remove bind C-t display "Keybinding C-t")
  • reload tmux config (PREFIX : source-file ~/.tmux.conf)
  • check whether the keybinding works (press PREFIX C-t), it still displays "Keybinding C-t"
  • press PREFIX ? to see that the new keybinding is still in the list
  • exit tmux
  • enter tmux
  • check whether the original keybinding works again (press PREFIX C-t), it should now display a clock again
  • press PREFIX ? to see that the new keybinding has been removed from the list

My question: is there a way to instruct tmux to "forget" all loaded configs and then load .tmux.conf ?

18

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.

  • Yes and I've stated that in my question already. But instead of "resetting" all possibly binded keys manually I'd like tmux to restart with a "clean slate" and then reload the config file. – Niels Bom Dec 5 '12 at 14:26
  • @NielsBom check updated answer please – peterph Dec 5 '12 at 15:01
  • You are correct, the unbind-key -a removes all the keybindings. I'll mark your answer as correct, but for other viewers' sake I'll also add the "hack" I've applied to fix a problem with unbind-key -a. – Niels Bom Dec 5 '12 at 15:42
  • See my answer for my solution. – Niels Bom Dec 5 '12 at 15:58
15

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.

  • 1
    It's likely that you can quickly generate the equivalent of your .tmux.reset.conf by running tmux list-keys in a "clean" session. – jw013 Dec 5 '12 at 23:31
  • 2
    tmux -f /dev/null -L temp start-server \; list-keys will effectively generate the defaults (though you need to add a backslash before the semicolon in its binding). – Chris Johnsen Dec 6 '12 at 5:40
  • @ChrisJohnsen Could you pls elaborate on start-server in a separate answer? – Niels Bom Dec 6 '12 at 8:57
7

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).

5

Here's a rollup of all of the other answers into a bash script that will automatically generate .tmux.reset.conf from the default key bindings:

#!/bin/bash
tmux -f /dev/null -L temp start-server \; list-keys | \
  sed -r \
  -e "s/bind-key(\s+)([\"#~\$])(\s+)/bind-key\1\'\2\'\3/g" \
  -e "s/bind-key(\s+)([\'])(\s+)/bind-key\1\"\2\"\3/g" \
  -e "s/bind-key(\s+)([;])(\s+)/bind-key\1\\\\\2\3/g" \
  -e "s/command-prompt -I #([SW])/command-prompt -I \"#\1\"/g" \
  > ~/.tmux.reset.conf

The embedded sed command line takes care of escaping various parts of the output from list-keys. This may need some tweaking for the specifics of your system.

In your .tmux.conf file simply unbind all keys and source this file before defining your own key bindings:

unbind-key -a
source-file ~/.tmux.reset.conf
4

Please also refer to the other answers here, as they do a good job of explaining the situation. I have here my tmux 1.8 compatible tmux.reset.conf, which I had to make several modifications after copying out the tmux -f /dev/null -L temp start-server \; list-keys output. In particular, several things had to be quoted.

# 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-tree
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 z resize-pane -Z
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 M-1 select-layout even-horizontal
bind-key M-2 select-layout even-vertical
bind-key M-3 select-layout main-horizontal
bind-key M-4 select-layout main-vertical
bind-key M-5 select-layout tiled
bind-key M-n next-window -a
bind-key M-o rotate-window -D
bind-key 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
4

I asked upstream they seem unwilling to fix it (unless someone submits a PR).

Here's my manually escaped tmux list-keys, obtained via a new server instance with

tmux -f /dev/null -L temp start-server \; list-keys

(thanks to previous answers)

## See https://github.com/tmux/tmux/issues/729: How to reset key bindings to default? #729

bind-key    -T prefix C-b              send-prefix
bind-key    -T prefix C-o              rotate-window
bind-key    -T prefix C-z              suspend-client
bind-key    -T prefix Space            next-layout
bind-key    -T prefix !                break-pane
bind-key    -T prefix '"'                split-window
bind-key    -T prefix '#'                list-buffers
bind-key    -T prefix '$'                command-prompt -I '#'S "rename-session '%%'"
bind-key    -T prefix %                split-window -h
bind-key    -T prefix &                confirm-before -p "kill-window #W? (y/n)" kill-window
bind-key    -T prefix "'"                command-prompt -p index "select-window -t ':%%'"
bind-key    -T prefix (                switch-client -p
bind-key    -T prefix )                switch-client -n
bind-key    -T prefix ,                command-prompt -I '#W' "rename-window '%%'"
bind-key    -T prefix -                delete-buffer
bind-key    -T prefix .                command-prompt "move-window -t '%%'"
bind-key    -T prefix 0                select-window -t :=0
bind-key    -T prefix 1                select-window -t :=1
bind-key    -T prefix 2                select-window -t :=2
bind-key    -T prefix 3                select-window -t :=3
bind-key    -T prefix 4                select-window -t :=4
bind-key    -T prefix 5                select-window -t :=5
bind-key    -T prefix 6                select-window -t :=6
bind-key    -T prefix 7                select-window -t :=7
bind-key    -T prefix 8                select-window -t :=8
bind-key    -T prefix 9                select-window -t :=9
bind-key    -T prefix ':'                command-prompt
bind-key    -T prefix \;                last-pane
bind-key    -T prefix =                choose-buffer
bind-key    -T prefix ?                list-keys
bind-key    -T prefix D                choose-client
bind-key    -T prefix L                switch-client -l
bind-key    -T prefix M                select-pane -M
bind-key    -T prefix [                copy-mode
bind-key    -T prefix ]                paste-buffer
bind-key    -T prefix c                new-window
bind-key    -T prefix d                detach-client
bind-key    -T prefix f                command-prompt "find-window '%%'"
bind-key    -T prefix i                display-message
bind-key    -T prefix l                last-window
bind-key    -T prefix m                select-pane -m
bind-key    -T prefix n                next-window
bind-key    -T prefix o                select-pane -t :.+
bind-key    -T prefix p                previous-window
bind-key    -T prefix q                display-panes
bind-key    -T prefix r                refresh-client
bind-key    -T prefix s                choose-tree
bind-key    -T prefix t                clock-mode
bind-key    -T prefix w                choose-window
bind-key    -T prefix x                confirm-before -p "kill-pane #P? (y/n)" kill-pane
bind-key    -T prefix z                resize-pane -Z
bind-key    -T prefix {                swap-pane -U
bind-key    -T prefix }                swap-pane -D
bind-key    -T prefix '~'                show-messages
bind-key    -T prefix PPage            copy-mode -u
bind-key -r -T prefix Up               select-pane -U
bind-key -r -T prefix Down             select-pane -D
bind-key -r -T prefix Left             select-pane -L
bind-key -r -T prefix Right            select-pane -R
bind-key    -T prefix M-1              select-layout even-horizontal
bind-key    -T prefix M-2              select-layout even-vertical
bind-key    -T prefix M-3              select-layout main-horizontal
bind-key    -T prefix M-4              select-layout main-vertical
bind-key    -T prefix M-5              select-layout tiled
bind-key    -T prefix M-n              next-window -a
bind-key    -T prefix M-o              rotate-window -D
bind-key    -T prefix M-p              previous-window -a
bind-key -r -T prefix M-Up             resize-pane -U 5
bind-key -r -T prefix M-Down           resize-pane -D 5
bind-key -r -T prefix M-Left           resize-pane -L 5
bind-key -r -T prefix M-Right          resize-pane -R 5
bind-key -r -T prefix C-Up             resize-pane -U
bind-key -r -T prefix C-Down           resize-pane -D
bind-key -r -T prefix C-Left           resize-pane -L
bind-key -r -T prefix C-Right          resize-pane -R
bind-key    -T root   MouseDown1Pane   select-pane -t = \; send-keys -M
bind-key    -T root   MouseDown1Status select-window -t =
bind-key    -T root   MouseDown3Pane   if-shell -F -t = '#{mouse_any_flag}' "select-pane -t=; send-keys -M" "select-pane -mt="
# Someone also was wondering how to fix here: http://tmux-users.narkive.com/dTFVvLMh/is-it-possible-to-have-a-binding-that-brings-back-mouse-behavior
bind-key    -T root   MouseDrag1Pane   if-shell -F -t = '#{mouse_any_flag}' "if -Ft= '#{pane_in_mode}' 'copy-mode -M' 'send-keys -M' " "copy-mode -M"

bind-key    -T root   MouseDrag1Border resize-pane -M
bind-key    -T root   WheelUpPane      if-shell -F -t = '#{mouse_any_flag}' "send-keys -M" "if -Ft= '#{pane_in_mode}' 'send-keys -M' 'copy-mode -et=' "
bind-key    -T root   WheelUpStatus    previous-window
bind-key    -T root   WheelDownStatus  next-window

The above is on github so you can do:

curl -L https://raw.githubusercontent.com/timotheecour/dinocode/master/tmux_list_keys_escaped.txt > ~/.tmux.reset.conf
unbind-key -a
source-file ~/.tmux.reset.conf

NOTE: Somehow Richard Cook's answer still produced escaping issues.

  • Welcome to unix.SE! We are often Wary of plain links so i pasted it directly in here (but kept the link for reference). That's the preferred way around here. Links do die (I know, it is github! But still it may die at some point). Anyhow it is a good answer (+1). Maybe could be better if you managed to fix the issue with Richard's sed code. That is a year old and tmux has th bad habit of not being 100% backward compatible. – grochmal Jan 20 '17 at 22:25
1

Here's a tweaked version of Richard Cook's answer to fix escaping issues on tmux 2.1

#!/bin/bash
tmux -f /dev/null -L temp start-server \; list-keys | \
    sed -r \
    -e "s/(bind-key.*\s+)([\"#~\$])(\s+)/\1\'\2\'\3/g" \
    -e "s/(bind-key.*\s+)([\'])(\s+)/\1\"\2\"\3/g" \
    -e "s/(bind-key.*\s+)([;])(\s+)/\1\\\\\2\3/g" \
    -e "s/(command-prompt -I )#([SW])/\1\"#\2\"/g" \
    -e "s/(if-shell -F -t = )#([^ ]+)/\1\"#\2\"/g" \
    > ~/.tmux.reset.conf                              

Add following lines to beginning of .tmux.conf

unbind-key -a
source-file ~/.tmux.reset.conf

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.