77

Switching to and from insert mode in Vim is no longer instantaneous since I use tmux. After pressing Esc in insert mode, it takes a noticeable amount of time to actually get out of insert mode. After pressing Esc and any other key afterwards the switch is immediate, and the command for the key pressed after Esc is executed. Any idea what might cause this?

The Vim configuration is not the problem as the delay does not occur when I run Vim outside tmux, so this is probably related to tmux somehow. I use gnome-terminal btw.

Also worth noting, it seems I can not define key bindings in tmux for Esc, my plan was to bind Esc to:

bind Escape send-keys ^[

Alas, it seems binding anything to Esc for tmux does not work. The same problem occurs in screen as well.

5 Answers 5

141

After plowing through the man pages it turns out tmux has an option for this. The following in ~/.tmux.conf fixes the delay problem:

 set -sg escape-time 5

You have to restart your tmux server or reload your config for this to take effect. To do this, issue source-file ~/.tmux.conf from the tmux prompt.

As pointed out by @Jonathan Wheeler (https://superuser.com/a/1809494), setting an escape time of zero is a bad idea but rather, set it to a low enough value such that you are not bothered by the delay.

17
  • 3
    Where did you find this? I can't find escape-time anywhere in man tmux, and the command doesn't work for me.
    – djeikyb
    Apr 5, 2011 at 15:41
  • 1
    I suspect is is only available in the development version. You can get it here: github.com/ThomasAdam/tmux Apr 5, 2011 at 16:15
  • 7
    I had to use tmux kill-server before this setting worked for me. Thanks!
    – Sam
    Sep 8, 2013 at 15:46
  • 2
    This makes me wish I could give you 10 upvotes. Found this after an hour of battling timeouts in vim. Thank you!
    – malvim
    Jul 11, 2014 at 14:30
  • 2
    @MichaelBrown, I do as well, and still hit this problem. It should not matter actually, because the same key code is sent to the terminal emulator regardless of whether you press escape or ^[. Aug 29, 2019 at 9:17
9

I had a different but similar issue that I was trying to solve when I found this page, so I'll post that here in case it's helpful to anyone else who is in search of this answer and finds this page in the same way.

Problem: vi mode in bash has a delay when switching from insert mode to command mode

Solution: In your ~/.inputrc file, add set keyseq-timeout n where n is some low value greater than 0. n defaults to 500ms, which is what causes the delay. See documentation here.

Also, if you want to be able to tell which mode you're in, check out Dylan Cali's fork of bash.

3
  • that is very helpful, i set it to 0.01 and now its pleasingly much more faster. thanks!
    – user373230
    May 17, 2017 at 7:28
  • It could also be appended into /etc/inputrc to make it available for all users.
    – user373230
    May 17, 2017 at 8:27
  • 1
    zsh has an additional delay setting: KEYTIMEOUT -- johnhawthorn.com/2012/09/vi-escape-delays May 21, 2020 at 21:11
6

TL;DR:

DO NOT use escape-time 0, but rather set it to a low value.

In ~/.tmux.conf:

set -s escape-time 50  # ~5-100. https://superuser.com/a/1809494/224906

Finish by either reloading your tmux config or restarting your tmux server. (In your CLI, run either tmux source-file ~/.tmux.conf or tmux kill-server; tmux.)

Detailed Explanation:

After spending several days over the last couple of months tracking down a very annoying (non-deterministic and seemingly random) issue while remotely connected to a tmux server (via iTerm2 3.4.20 -> zsh 5.8.1 -> ssh 8.9p1 -> zsh 5.8.1 -> tmux 3.3a), I would highly recommend NOT setting escape-time to 0 (as suggested by others here, and even by tmux-sensible, which links to this very question at the time of my post), but rather setting escape-time to a lower value of something like 10 or 50 (from the default of 500).

Why? I finally discovered the solution in the GitHub issue "tmux 3.3 leaks text into shell":

escape-time 0 prevents tmux from recognizing escape sequences that are fragmented across read/packet boundaries. You should raise that to a more reasonable value such as 100ms which should be enough time for most cases while still being quick enough that it shouldn't cause human-scale interaction issues.

He is using a completely different terminal than me (wezterm vs iTerm2), yet is experiencing a very similar issue of a combined CSI (Control Sequence Introducer) and DCS (Device Control String) escape sequence—specifically \033[>0;95;0c\033P>|iTerm2 3.4.20\033\\—leaking into the shell in response to the CSI escape sequences CSI > c (aka \033 [ > c) and CSI > q (aka \033 [ > q). (Which, at least for me, seem to always occur in sequence immediately after one another.)

After some time, this would cause a random paste to occur in my vim buffer, followed by Term2 3.4.20 [sic] being prepended to the pasted text.

Further detail to help others searching for this solution:

The combined CSI and DCS sequence \033[>0;95;0c\033P>|iTerm2 3.4.20\033\\ causes the following in vim: \033[>0;95;0c\033 doesn't do much, P pastes whatever is in vim's unnamed/default register, >| tabs the line to the right, i enters insert mode, Term2 3.4.20 is inserted into the buffer, \033 escapes back out of insert mode, and the final \\ basically does nothing.

I've observed that this happens more often when I'm on the road, and especially when using an unreliable and slow mobile connection. This now makes perfect sense, since packet latency is greater under these conditions, and since I was using a escape-time 0.

TL;DR: Don't use escape-time 0; it exists for a good reason. Give it a low reasonable value (like 5, 50, or 100) that will still work well when connected remotely. Adjust as needed to find the right balance. If the value is too high, it'll interfere with human-scale interactions. If the value is too low, you may experience escape sequence artifacts and bugs.

Edit: This problem and solution is also cited in this Microsoft WSL issue on GitHub, which similarly links back to this question.

Edit #2: I've also learned that the issues I described above can (and perhaps more likely) be due to TTY_QUERY_TIMEOUT in tmux/tty.c not being set high enough, but this is beyond the scope of this question. It remains true that you shouldn't use escape-time 0 for the reasons mentioned above.

3

As the title mentions Screen, here is the solution to fix the behaviour of Escape key within GNU Screen. (Taken from here.)

Add

maptimeout 5

to .screenrc config file.

1

It sounds like you are using a mapping that starts with ESC. When you press the ESC, vim has to wait to see if the next key is the one in the mapping. If it is not, it can immediately continue.

The vim configuration can be terminal dependent, so the fact that it does not happen outside of tmux does not mean much. Vim can query the $TERM environment variable and choose different configuration depending on its value.

Since gnome-terminal uses, AFAIK, xterm as the value of the $TERM variable, and tmux uses screen, I would look through all your vim configuration files for settings that are only used is the $TERM variable is equal to screen. My guess is that some vim config file on your system sets mappings for handling of arrow keys (those start with the ESC character) when the terminal is screen.

You can test it by temporarily changing the $TERM variable in tmux before starting vim. If your shell is bash, call vim as

TERM=xterm vim

in tmux and see if the problem persists. You sould not use that as a fix, though, since there may be differences between the terminal capabilities of tmux and xterm, and you may run into some problems.

1
  • Some good pointers here. I do use bash, but unfortunately TERM=xterm vim did not fix the problem. I'll have to dig a little deeper. Mar 2, 2011 at 21:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .