tpope / vim-unimpaired

unimpaired.vim: Pairs of handy bracket mappings
https://www.vim.org/scripts/script.php?script_id=1590
3.33k stars 203 forks source link

Avoiding timeoutlen for shortcuts #212

Closed protist closed 3 years ago

protist commented 3 years ago

Vanilla vim keybindings involving multiple keys (e.g. dd) don't seem to time out. I can press the first key d, wait several seconds, then press the second d.

However, it seems like the vim-unimpaired shortcuts (e.g. yow) respect timeoutlen. That is, I can't wait indefinitely between keys, but instead have to press each subsequent key within timeoutlen. Is that the expected behaviour? Is there or should there a way to avoid this timeout?

systemmonkey42 commented 3 years ago

Commands like 'dd' are operators where the first 'd' represents a command and the second 'd' is the parameter. Timeoutlen does not apply between and operator and it's parameters.

'yow' on the other hand is a key binding, so timeoutlen applies. You can use set notimeout if you don't want the timeout to apply at all.

protist commented 3 years ago

Thanks @systemmonkey42. I actually ran into this issue because my timeoutlen was too low. So apart from turning it off completely, it sounds like there's no real workaround then?

systemmonkey42 commented 3 years ago

Not really no. A complete rewrite of vim unimpaired where [ and ] were operators might get you there, along with yo and many others but it wouldn't really solve anything

Incidentally I have timeout turn off permanently. Why do you find you need it?

protist commented 3 years ago

Fair enough. Thanks again for that information. I'll just increase timeoutlen then.

I use this setting in combination with inoremap jk <Esc>, so I don't need to move my hands from the home row to press <Esc>. Instead, I just type jk quickly (within timeoutlen) to do the same thing. I keep timeoutlen relatively low "just in case" I need to type a literal jk… although I can't actually ever recall having to do so.

protist commented 3 years ago

Ahhh… I remember now why I like timeoutlen low. If I start typing :command, then change my mind and hit <Esc> to cancel, it's disconcerting to wait timeoutlen before it actually cancels. (I can actually continue with another command, but it's just a bit odd to see it sitting there still.)

systemmonkey42 commented 3 years ago

Ah, the old jk for Esc. I've used that in the past but could never get used to it.

The problem with Esc hanging around when leaving insert mode, or while typing a command is the old "mappings starting with escape" (newbie?) mistake.

Eg,

The command:

map ^[[P [somefunction]

causes vim to treat "escape" as the beginning of a key mapping (which it is). Any time you press escape, it must wait timeoutlen to determine if you are going to complete the mapping...

On the other hand; set <F35>=^[[P Followed by map <F35> [somefunction] causes vim to treat the sequence <escape>[P as a "terminal code" and thus ttimeoutlen is used.

Essentially, If you, (or a plugin you've installed) has created a mapping starting with an escape it creates this problem.

If you create a Terminal code (I use unused function keys because vim understands up to <F35>), it treats it as a terminal code.

Once you have NO mappings starting with Esc, pressing Esc on its own is no longer subject to timeoutlen.

Try :set termcap To see all the existing terminal codes, and how many are free to be redefined as needed.

EDIT: A bunch of < and > disappeared due to bad juju

tpope commented 3 years ago

For posterity, this is what I use:

setglobal timeoutlen=1200
setglobal ttimeoutlen=50

One second is a tad too tight for me. Bump to 1.2 seconds is adequate. Your mileage may vary.

The timeout for escape can be set separately with 'ttimeoutlen'.

protist commented 3 years ago

The problem with Esc hanging around when leaving insert mode, or while typing a command is the old "mappings starting with escape" (newbie?) mistake.

Huh, I had never heard of that before. Thanks @systemmonkey42! I had a look at :map and :imap and couldn't find any reference to \[ in there however, so does this mean there aren't any key mappings starting with Esc?

systemmonkey42 commented 3 years ago

Huh, I had never heard of that before. Thanks @systemmonkey42! I had a look at :map and :imap and couldn't find any reference to \[ in there however, so does this mean there aren't any key mappings starting with Esc?

You will need to check the ttimeout and ttimeoutlen settings.

:set timeout?
timeout
:set timeoutlen?
timeoutlen=1000
:set ttimeout?
nottimeout
:set ttimeoutlen?
ttimeoutlen=-1

With this default configuration, pressing escape at any time triggers the 1000ms timeoutlen pause before accepting escape.

As @tpope mentioned, consider using

setglobal timeout timeoutlen=1200
setglobal ttimeout ttimeoutlen=50

With ttimeoutlen=50, pressing escape will only wait 50ms for additional characters, unless vim has been told to expect a MAPPING starting with escape.

Eg, press : and type something, pressing Esc should exit command mode in 50ms

Create a mapping starting with Esc...

:exe "cmap \<Esc>p mycmd"

(The "exe" wrapper allows vim to expand \<x> codes before executing commands. Less messy than typing Ctrl-V and littering your config with escape codes.)

Now press : and type something, then press Esc. Vim now goes back to waiting 1000ms before accepting the escape because the escape could be the beginning of a terminal code OR a mapping.

protist commented 3 years ago

@systemmonkey42 sorry I should have been clearer. I indeed do have those settings you recommend.

:set timeout?
  timeout
:set timeoutlen?
  timeoutlen=1000
:set ttimeout?
  timeout
:set ttimeoutlen?
  ttimeoutlen=50

But I still experience the 1000 ms delay when pressing Esc in command/insert mode. I don't think I have any mappings starting with Esc though, at least according to :map and :imap, which don't contain \[.