33

I am trying to write a Vim function which should make the window go to the previous open buffer.

How can I do it from the command line? My first idea was to find out some Ctrl-O command line alternative.

1

8 Answers 8

48

The jumplist is not the best way to do buffer navigation. Vim has a great number of buffer navigation tools which are probably better used for this task.

  • <c-^>/<c-6> - jump to the alternative file or if providing a count to a certain buffer number. See :h CTRL-6
  • :b - jump to a specific buffer. Takes buffer number or partial filename. See :h :b
  • :sb - split variant of :b
  • :ls/:buffers - list opened buffers. See :h :ls
  • # used to represent the alternative file which is often the previous buffer. e.g. :b#. See :h c_#
  • Common mapping nnoremap <leader>b :ls<cr>:b<space>

If you really do want to use the jump list you may want to look at Ingo Karkat's EnhancedJumps plugin or see vim-buffer-history plugin which is sort of similar.

2
  • 4
    Thank you for expanded answer. So b# command is the best solution of my problem.
    – ephemerr
    Dec 5, 2017 at 7:21
  • 1
    Whoa, reading this answer has greatly improved my nvim buffer management! :D Thank you very much!
    – Isti115
    Nov 28, 2020 at 15:54
18

You can also use ctrl + o to go to the previous jump list, which might be buffer, going backwards. You can keep pressing the same command to go to the previous, previous buffer/jump list.

You can also use ctrl + i to go to the next buffer/jump list, going forward. I.e, if you had pressed ctrl + o to go to the previous buffer, you can use ctrl + i to go to the first/original buffer.

1
  • 7
    Note that Ctrl+o and Ctrl+i do not strictly move between buffers. They move between locations on the jump list (see :help jump), which may or may not point to buffers other than the one currently being edited. Apr 8, 2021 at 17:13
2

Recently someone asked a similar question on Reddit and I wrote a piece of code to answer it. Today I've found this question in a review queue so that is the opportunity to share my code in a late answer.

The idea is to create two new mappings <leader><c-o> and <leader><c-i> which will execute respectively <c-o> and <c-i> until the buffer has changed or until there is no more jumps available in the jumplist. It seems to be working fine but there might be some edge cases that are not handled well.

" In ~/.vim/autoload/jumps.vim

" Repeat <C-o> or <C-i> jump commands until the current buffer changes
" or no other jumps are available
function jumps#fileCO(up)
    let current_buffer = bufnr()

    " Get the jump list and parse the position of the first jump in the list
    " if the number is zero then we reached the top
    redir => jumps_output
    silent jumps
    redir END
    let lastjump = split(jumps_output, '\n')[1]
    let lastjumppos = str2nr(matchstr(lastjump, '\d\+'))

    " Execute the jump command until the buffer changes or there are no more jumps
    while bufnr() == current_buffer && lastjumppos > 0
        if a:up == v:true
            execute "normal! \<c-o>"
        else 
            " \<CR> is an ugly hack to do nothing but let the normal command
            " see that it has an argument
            execute "normal! \<CR>\<c-i>"
        endif
        let lastjumppos = lastjumppos - 1
    endwhile
endfunction

" In ~/.vimrc

nnoremap <silent> <leader><C-o> :call jumps#fileCO(v:true)<CR>
nnoremap <silent> <leader><C-i> :call jumps#fileCO(v:false)<CR>
1

This works for me, it takes me back to the alternate buffer. For me that is always the previous buffer:

function! MoveBack()
     edit #
endfunction
1
  • This is the right answer!
    – Punit Soni
    Sep 1, 2020 at 5:06
1

:bp goes to previous buffer. :bn goes to next buffer.

1
  • Thanks for writing an answer. It should be noted that :bn and :bp traverse buffers in the order they were opened so :bp may not go to the previously visited buffer. That may be close enough in many cases. BTW, they're not new features.
    – Friedrich
    Nov 30, 2023 at 12:16
0

I found the solution in use of normal command. There would be such a line in my function:

exe "normal \<C-O>"
3
  • 2
    That doesn't go to previous open buffer. It goes to the last position in your jump list which could be in the same buffer. What about Ctrl-^?
    – B Layer
    Dec 4, 2017 at 10:06
  • 1
    Also you shouldn't need exe. Try normal! ^O where ^O is inserted by hitting Ctrl-V followed by Ctrl-O.
    – B Layer
    Dec 4, 2017 at 10:10
  • good point. If i_Ctrl-v occupied, see :h i^v for alternative (usually Ctrl-q). Another approach is use digraph, in this case, in insert mode, first type Ctrl-k, then type Ctrl-o twice will insert Ctrl-o.
    – qeatzy
    Dec 5, 2017 at 2:52
0

Plug https://github.com/inkarkat/vim-EnhancedJumps defines <leader><c-o> as a jump to the previous position in previous buffer. Similarly <leader><c-i>. It works.

1
  • I didn't see that peter wrote about this plugin too, with less details.
    – eyal karni
    May 6, 2021 at 12:09
0

To switch to last visited buffer you can use <C-^> (or <C-6>) and :b#. (short for :buffer #). It's hard to use these two shortcuts, so I add a custom mapping for switching buffers:

nnoremap gb :b# <CR>

Add this in your .vimrc or type this in command mode (:nnoremap gb :b# <CR>).

Now you can simply use gb for switching between 2 buffers.

1
  • Prefer :nnoremap, and I would spell out the command (:nnoremap gb :buffer #<cr>). I don't know where I got the idea, but I use <leader>` for this
    – D. Ben Knoble
    Jul 6, 2022 at 14:39

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.