And, to get back again: how do I make the l key go to next tab, if at end of file?

I'd also like to make hh go to previous buffer, and ll go to next buffer. I know that'll add a delay to recognising the h/l keys, and slow down navigation, and I wonder is there a way to tell vim to

Only check for "hh" at start of file, and only check for "ll" at end of file

  • 5
    This is doable, but I'd recommend getting used to gt and gT. If you're looking to cycle buffers, tpope's unimpaired uses ]b and [b for :bnext and :bprev, respectively, which I find quite nice. :ls followed by :buffer is also quite nice
    – D. Ben Knoble
    Commented Feb 5, 2020 at 20:07
  • @jalanb I'm not sure whether you also had intended to award the bounty that ended up expiring to my answer: if so, I appreciate it. Thanks for the accept, either way!
    – Rich
    Commented Feb 18, 2020 at 9:35

2 Answers 2


Like Ben and statox, I wouldn't necessarily recommend this, but it is possible:

function FirstPress(c1) abort
  let now = reltime()
  while reltimefloat(reltime(now)) < &timeoutlen / 1000.0
    " See if the user has typed another character
    let c2 = getchar(0)

    if c2 != 0
      " The user typed something. Was it another h?
      if c2 == char2nr(a:c1)
        " The user typed a double h, switch buffers
        if a:c1 == 'h'
        " The user typed something else. Switch tabs and replay what they typed
        call feedkeys((a:c1 == 'h' ? 'gT' : 'gt') . nr2char(c2), 't')

  " The user didn't press anything. Switch Tabs
  if a:c1 == 'h'

nnoremap <expr> h (getpos('.')[1] == 1 && getpos('.')[2] == 1) ? ':call FirstPress("h")<CR>' : 'h'
nnoremap <expr> l (getpos('.')[1] == line('$') && (getpos('.')[2] == col('$') - 1 \|\| col('$') == 1)) ? ':call FirstPress("l")<CR>' : 'l'

It works by mapping the single h and l keypresses only, and then in that mapping, checking if the user presses the given key a second time, and acting accordingly.

See also my answer to this recent similar, but slightly different question where the OP wanted to do the first mapping immediately and then perform the second as well if performed within timeoutlen.

  • 1
    You got me at "wouldn't necessarily recommend this", but just reading yours brought my vim code up a level. Yesterday I kinda knew those things were possible, today I have feedkeys()! All I do all day is feed keys to vim! This is could be a life-changer...
    – jalanb
    Commented Feb 8, 2020 at 4:18
  • &timeout is an "option" vimdoc.sourceforge.net/htmldoc/usr_41.html#41.3
    – jalanb
    Commented Feb 8, 2020 at 4:38
  • Which defaults to 1000 vimdoc.sourceforge.net/htmldoc/options.html#'timeoutlen', but easily changed with tm
    – jalanb
    Commented Feb 8, 2020 at 4:41
  • @jalanb Glad I could help! :D
    – Rich
    Commented Feb 8, 2020 at 10:59
  • @jalanb I went a bit overboard with the feedkeys use in my original answer. I've updated it to only use it where necessary (for replaying the keypress that the user typed).
    – Rich
    Commented Feb 13, 2020 at 14:10

how do I make the l key go to next tab, if at end of file

For this part make a function which checks that the following two conditions are satisfied:

  1. The value of line("."), which is the current line number, and line("$"), which is the number of all lines in a file, match
  2. The current column value, obtained with col("."), and the length of the current line, obtained with strlen(getline(".")), match.

This means that you're on the last line, on the last column (i.e. the last character in the file).

I hope this pushes you in the right direction.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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