Cycle through buffers including hidden buffers
From Vim Tips Wiki
Tip 873 • Previous Tip • Next Tip
Created: February 10, 2005 Complexity: basic Author: Anon Minimum version: 6.0 Karma: 60/18 Imported from: Tip#873
This tip provides a means to cycle through all of your buffers (including unlisted buffers such as directory listings):
Contents |
[edit] Cycling through listed buffers
The commands :bnext and :bprevious will switch to the next or previous buffer in the buffer list. So a couple of useful maps for cycling through your buffers are:
nnoremap <C-n> :bnext<CR> nnoremap <C-p> :bprevious<CR>
A list of your buffers can be shown after switching by using the following maps:
nnoremap <A-n> :bnext<CR>:redraw<CR>:ls<CR> nnoremap <A-p> :bprevious<CR>:redraw<CR>:ls<CR>
The buffer you are currently editing will be shown with a '#'. From there you should be able to get an idea of how far you have to go to the desired buffer and then use the first set of maps to quickly navigate to it.
[edit] Including unlisted buffers in the cycle
The :bnext and :bprevious commands skip unlisted buffers, which can prove frustrating when buffers have been opened to view directory listings, or you want to view a buffer previously deleted with :bdelete. Consider the following example.
gvim ~ /etc/motd
gvim goes to dir ~
:bn
gvim goes to /etc/motd
:bp
but will not go back to ~, because it is unlisted.
:ls!
~ is there in list of the buffers 1,2
:buf 1
have to give it the buffer number to find it.
The problem gets worse with several levels of directory navigation. The simplest solution for this are the following two mappings:
:nnoremap <C-n> :execute ":buffer ".(bufnr("%") + 1)<CR>
:nnoremap <C-p> :execute ":buffer ".(bufnr("%") - 1)<CR>
This maps <C-n> to switch to the buffer which has a buffer number one higher than the buffer number of the current buffer. Whilst <C-p> cycles in the opposite direction.
However, this does not always work, because there might be holes in the buffer numbers. For example, right now my buffer list contains buffer numbers 1, 2, 6, 9, 10 and 14. Using the above map for <C-n> from buffer #6, would produce the error message "E86: Buffer 7 does not exist". Also, unlike :bnext and :bprevious the above maps will cycle from non-help buffers to help buffers and vice-versa.
A solution is to write a function searching for the next buffer with bufexists() and checking its filetype with getbufvar().
function! SwitchToNextBuffer(incr)
let help_buffer = (&filetype == 'help')
let current = bufnr("%")
let last = bufnr("$")
let new = current + a:incr
while 1
if new != 0 && bufexists(new) && ((getbufvar(new, "&filetype") == 'help') == help_buffer)
execute ":buffer ".new
break
else
let new = new + a:incr
if new < 1
let new = last
elseif new > last
let new = 1
endif
if new == current
break
endif
endif
endwhile
endfunction
nnoremap <silent> <C-n> :call SwitchToNextBuffer(1)<CR>
nnoremap <silent> <C-p> :call SwitchToNextBuffer(-1)<CR>
[edit] Leaving modified buffers
If Vim is running with its default settings, or in Vi compatible mode, the commands :bnext, :bprevious and :buffer won't abandon the buffer until any changes have been written. There are a few ways this can be changed.
- The commands can be called with a trailing !, eg. :bnext!, which will discard any changes made to the buffer.
- Setting the hidden option (:set hidden) will keep the changes to the buffer without writing them to the file. This affects all commands and all buffers.
- Setting either the autowrite or the autowriteall options (:set autowrite or :set autowriteall) will automatically save the changes made to the buffer.
[edit] References
- :help :unlisted-buffer
- :help :bnext
- :help :bprevious
- :help :bdelete
- :help :bufnr
- :help :bufexists
- :help :getbufvar
- :help 'hidden'
- :help 'autowrite'
- :help 'autowriteall'
- :help abandon
