4

I know it's not a bug, since the help page explains it cleary, but is there any reason why gt is still kept different from the majority of commands that accept a {count} prepended? I mean, isn't it in contrast with vi(m) phylosophy?

What annoys me the most is that gt and gT are not the opposite of each other when a {count} is prepended (unlike many others, e.g. n and N, w and W, and so on), so, for instance, I can't "undo" a 2gT by typing 2gt.

3 Answers 3

4

I can't really explain why it works like this, my best guess is that you more often need to go a tab by its index rather than going 3 tabs forwards.

However, if you really don't like how Vim works and want to be able to "undo" a 2gT with 2gt you can add the following to your vimrc:

function! Mygt(forward, count)
    let loop = a:count
    while loop > 0
        if a:forward
            normal! gt
        else
            normal! gT
        endif
        let loop = loop -1
    endwhile
endfunction

nnoremap <silent> gt :<C-U>execute "call Mygt(1, " . v:count1 . ")"<CR>
nnoremap <silent> gT :<C-U>execute "call Mygt(0, " . v:count1 . ")"<CR>

The function Mygt() is pretty straightforward: it takes 2 arguments, the first one is used to define if you want to go forward or backward in the list of tabs and the second one is how many tabs you want to skip. So it loops on the given count and repeats gt or gT according to the first parameter.

You can try it with :call Mygt(1, 2) or :call Mygt(0, 4)

To make it easier to use, we also remap gt and gT:

  • <silent> is used to avoid prompting the function called by the mapping. (see :h :map-<silent>)
  • <C-u> is used to remove characters on the command line, it is used to allow a count to the mapping (see :h c_CTRL-U)
  • We build the string which will contain the command to execute (e.g. call Mygt(1, 3) and execute it with execute (see :h execute())
  • And finally, we use the count given to the mapping with v:count1 which will default to 1 if no count is given. (see :h v:count and :h v:count1)

All of this allows us to use gt, gT, 3gt and 5gT and get a "consistent" behavior.

12
  • 2
    It has been discussed previously. It is probably an oversight. Now Bram does not feel like changing it to not break compatibility. So we would need a new command. It never bothered me to create a new command. Commented Jul 25, 2018 at 20:08
  • 1
    I don't think this extreme and no-matter-what care about backward compatibility will take us to the promised keyboard... Anyway, accepted answer, @statox!
    – Enlico
    Commented Jul 26, 2018 at 6:30
  • 1
    that is your opinion. Other people might feel differently, if we change the semantics of a well-known command now. So he certainly has a point there. Commented Jul 26, 2018 at 8:54
  • 1
    I would certainly hate it. I use a customized tab string that displays the tab number in the tab title and it's much easier to glance up and see the tab number than it is to look up and count how many tabs I want to jump forwards or backwards. To my mind, this works very similar to {count}G jumping to a specific line number. tabline is here: vim.wikia.com/wiki/Show_tab_number_in_your_tab_line
    – Dan J.
    Commented Jul 26, 2018 at 11:46
  • 1
    @Enlico Ah! I was having trouble understanding the "change has been made in 8.2", but now I figured out what happened... Yeah, it's mostly the same. One change that was made is that :tabnext now takes a +n and -n argument, so when using the Ex command you can get an easier shortcut to repeat it twice.
    – filbranden
    Commented Feb 2, 2022 at 22:50
2

There is no need to write a function. You can take advantage of the fact that a macro prefixed by a count will be repeated as many times as the count says. And if you use the expression register for the macro you don't even waste a precious register or have a conflict with another use of the same register:

nnoremap gt @='gt'<cr>
2

Deviating from the behaviour for gT, the above answers won't handle g<Tab> nicely, as it will appear to vim as if one separately asked to go to the next tab page multiple times. Calculating the jump destination directly solves the problem.

One more subtlety is to prepend the mapping with @_. Execution of a black hole macro does nothing, but consumes the count passed to the mapping, so that we may pass another count from our mapping, in our case, giving the calculated destination tab page as a count to gt.

nnoremap <expr> gt '@_' . (1 + ((tabpagenr () - 1 + v:count1) % tabpagenr ('$'))) . 'gt'

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.