243

How can I change the position / order of my current tab in Vim? For example, if I want to reposition my current tab to be the first tab?

mtk
  • 13,221
  • 16
  • 72
  • 112
Gavin
  • 4,273
  • 3
  • 27
  • 39

8 Answers8

331

You can relocate a tab with :tabm using either relative or zero-index absolute arguments.

absolute:

  • Move tab to position i: :tabm i

relative:

  • Move tab i positions to the right: :tabm +i
  • Move tab i positions to the left: :tabm -i

It's a relatively new feature. So if it doesn't work try updating your vim.

Elliot Foster
  • 1,664
  • 1
  • 12
  • 11
maybeshewill
  • 3,824
  • 1
  • 15
  • 8
  • 2
    This doesn't work. :tabm doesn't accept relative arguments, although it really should. – Gavin Aug 10 '13 at 18:31
  • 6
    You should update your vim if it doesn't, because `:tabm` accepts relative arguments in vim 7.3. – maybeshewill Aug 13 '13 at 12:49
  • I have VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Apr 2 2013 09:17:34) Included patches: 1-547 and +- not supported there, documentation said I should specify zero or positive value – Volodymyr Sep 10 '13 at 13:41
  • @Vladimir I have the same version as you but with patch 1-929, and this works for me. – ming_codes Sep 19 '13 at 18:16
  • @maybeshewill I upgraded Vim and now it works. (Btw, I downvoted your answer and can't upvote unless it's edited. If you edit, I'll upvote.) – Gavin Oct 27 '13 at 20:43
  • @Gavin Thanks. :) I wanted to edit it anyway as it didn't fit the question perfectly. – maybeshewill Nov 01 '13 at 16:15
  • 6
    Note that the absolute position is zero-index, which is a little odd since vim displays tabs 1-indexed (or it might just be my vim config) – Elliot Foster Apr 21 '14 at 17:21
  • 2
    This doesn't handle the wrapping case – Andy Ray Jun 13 '15 at 23:37
  • also `:tabm` with no argument moves the tab last – Ygg Feb 17 '20 at 07:41
  • 1
    For the record, `:tabm +/-` was introduced in Vim 7.3.591 (published 2012-07-06), which has [made its way into almost all maintained distributions by now](https://repology.org/project/vim/versions). :) – n.st Aug 09 '20 at 13:44
45

Do you mean moving the current tab? This works using tabmove.

:tabm[ove] [N]                                          *:tabm* *:tabmove*
            Move the current tab page to after tab page N.  Use zero to
            make the current tab page the first one.  Without N the tab
            page is made the last one.

I have two key bindings that move my current tab one left or one right. Very handy!

EDIT: Here is my VIM macro. I'm not a big ViM coder, so maybe it could be done better, but that's how it works for me:

" Move current tab into the specified direction.
"
" @param direction -1 for left, 1 for right.
function! TabMove(direction)
    " get number of tab pages.
    let ntp=tabpagenr("$")
    " move tab, if necessary.
    if ntp > 1
        " get number of current tab page.
        let ctpn=tabpagenr()
        " move left.
        if a:direction < 0
            let index=((ctpn-1+ntp-1)%ntp)
        else
            let index=(ctpn%ntp)
        endif

        " move tab page.
        execute "tabmove ".index
    endif
endfunction

After this you can bind keys, for example like this in your .vimrc:

map <F9> :call TabMove(-1)<CR>
map <F10> :call TabMove(1)<CR>

Now you can move your current tab by pressing F9 or F10.

hochl
  • 12,524
  • 10
  • 53
  • 87
26

I was looking for the same and after some posts I found a simpler way than a function:

:execute "tabmove" tabpagenr() # Move the tab to the right
:execute "tabmove" tabpagenr() - 2 # Move the tab to the left

The tabpagenr() returns the actual tab position, and tabmove uses indexes.

I mapped the right to Ctrl+L and the left to Ctrl+H:

map <C-H> :execute "tabmove" tabpagenr() - 2 <CR>
map <C-J> :execute "tabmove" tabpagenr() <CR>
Pablo Díaz Ogni
  • 1,033
  • 8
  • 12
10

Move Current Tab to the nth Position

:tabm n

Where n is a number denoting the position (starting from zero)


Move Tabs to the Left / Right

I think a better solution is to move the tab to the left or right to its current position instead of figuring out the numerical value of the new position you want it at.

noremap <A-Left>  :-tabmove<cr>
noremap <A-Right> :+tabmove<cr>

With the above keymaps, you'll be able to move the current tab:

  • To the left using: Alt + Left
  • To the right using: Alt + Right
Sheharyar
  • 73,588
  • 21
  • 168
  • 215
5

In addition to the fine suggestions in other answers, you can also simply drag tabs with the mouse to move them, if you have mouse support enabled.

This is on by default in MacVim and other GUI vim implementations, whether using the GUI widget tabs or the terminal style tabs in GUI mode.

It also works in pure tty mode Vim, if you have set mouse=a and have a suitable terminal (xterm and most emulators of it, such as gnome-terminal, Terminal.app, iTerm2, and PuTTY/KiTTY, to name a view). Note that mouse clicks beyond column 222 also require set ttymouse=sgr; see In Vim, why doesn't my mouse work past the 220th column? for background on that.

I've written a plugin called vim-tabber that provides some additional functionality for swapping tabs around, shifting them, and adding to the capabilities of the built-in tab manipulation commands, while remaining largely compatible with the builtins. Even if you choose not to use the plugin, there's some general tab usage information in the README.

Jim Stewart
  • 16,964
  • 5
  • 69
  • 89
  • after re-arranging the tab using mouse, I can no longer resize the pane using mouse. Instead, every time I click and drag mouse cursor, the tabs rearrange again, as if the mouse click "stuck". Do you have any idea what might be going on here? – oldhomemovie May 02 '17 at 09:26
  • Jim, I've posted the question separately: http://stackoverflow.com/questions/43734501/cannot-resize-pane-with-mouse – oldhomemovie May 02 '17 at 09:31
4

This is a great question, Gavin, because there is a subtlety to it.

The answers from maybeshewill and hochl mostly answer the question -- use ":tabm" with an index or a relative (+/-) index.

Note, though, that there is the potential for confusion here and some of the other answers might have missed this. Take a look at the help text below that was included by hochl:

   :tabm[ove] [N]                                          *:tabm* *:tabmove*
            Move the current tab page to after tab page N.  Use zero to
            make the current tab page the first one.  Without N the tab
            page is made the last one.

The key word is after. I suspect this confuses people at times. Why? Because if a tab is moved out of the first position using ":tabm3", subsequently typing ":tabm2" does not move the tab again. The file that occupied tab#3 now occupies tab#2 and ":tabm2" does not change the order.

Here's a diagram. The selected tab is [file_c] in each row.

file_a file_b [file_c] file_d
:tabm0
[file_c] file_a file_b file_d
:tabm3
file_a file_b [file_c] file_d
:tabm2
file_a file_b [file_c] file_d

The ":tabm" command can be thought of as moving the current tab to after the tab that currently occupies a position when counting from 0, where tab 0 is the left-most tab and is imaginary. ":tabmi" does not move to the ith position -- if it did, ":tabm3" and ":tabm2" would produce different results.

In the end, the relative move +/- syntax is simpler if you have a good keymap.

1

For some reason, the function answer stopped working for me. I suspect a conflict with vim-ctrlspace. Regardless, the math in the function answer is unnecessary, as Vim can move tabs left and right with built in functions. We just have to handle the wrapping case, because Vim is not user friendly.

" Move current tab into the specified direction.
"
" @param direction -1 for left, 1 for right.
function! TabMove(direction)
    let s:current_tab=tabpagenr()
    let s:total_tabs = tabpagenr("$")

    " Wrap to end
    if s:current_tab == 1 && a:direction == -1
        tabmove
    " Wrap to start
    elseif s:current_tab == s:total_tabs && a:direction == 1
        tabmove 0
    " Normal move
    else
        execute (a:direction > 0 ? "+" : "-") . "tabmove"
    endif
    echo "Moved to tab " . tabpagenr() . " (previosuly " . s:current_tab . ")"
endfunction

" Move tab left or right using Command-Shift-H or L
map <D-H> :call TabMove(-1)<CR>
map <D-L> :call TabMove(1)<CR>
Andy Ray
  • 30,372
  • 14
  • 101
  • 138
  • The `-tabm` and `+tabm` in my vim 7.4 do not correctly move tabs. Also my `:help tabm` does not list this as a valid syntax. So I replaced the last `else execute ...endif` with `elseif a:direction == 1 execute "tabmove" s:current_tab else execute "tabmove" s:current_tab - 2 endif ` using [Pablo's answer](http://stackoverflow.com/a/17300525/923794) – cfi Sep 22 '15 at 09:42
  • For wrapping to start/end, I'm using this solution now over my own because I used two functions and his code cleaner to read & maintain. Just reversed the order of `tabmove` and the `-`/`+` sign in the `execute` line. – rld. Sep 14 '17 at 13:00
1

Here's my macro, using relative arguments from @maybeshewill's answer:

" Shortcuts to move between tabs with Ctrl+Shift+Left/Right
function TabLeft()
   if tabpagenr() == 1
      execute "tabm"
   else
      execute "tabm -1"
   endif
endfunction

function TabRight()
   if tabpagenr() == tabpagenr('$')
      execute "tabm" 0
   else
      execute "tabm +1"
   endif
endfunction

map <silent><C-S-Right> :execute TabRight()<CR>
map <silent><C-S-Left> :execute TabLeft()<CR>

It handles the wrapping case.

Jérôme
  • 13,328
  • 7
  • 56
  • 106