Vim Tips Wiki
No edit summary
Tags: Visual edit apiedit
 
(18 intermediate revisions by 3 users not shown)
Line 3: Line 3:
 
|previous=872
 
|previous=872
 
|next=874
 
|next=874
|created=February 10, 2005
+
|created=2005
 
|complexity=basic
 
|complexity=basic
|author=Anon
+
|author=
 
|version=6.0
 
|version=6.0
 
|rating=60/18
 
|rating=60/18
Line 11: Line 11:
 
|category2=
 
|category2=
 
}}
 
}}
 
This tip shows how to cycle through all of your buffers (including unlisted buffers such as directory listings).
   
  +
For suggestions on how to switch to ''any'' other buffer see [[Easier buffer switching]].
This tip provides a means to cycle through all of your buffers (including
 
{{help|unlisted-buffer}} buffers such as directory listings):
 
   
  +
==Cycling through listed buffers==
Most buffer navigation commands, such as :bnext and :bprevious, skip unlisted
 
  +
The commands <code>:bnext</code> and <code>:bprevious</code> will switch to the next or previous buffer in the buffer list. So a couple of useful maps for cycling through your buffers are:
buffers. Which can prove frustrating when there buffers have been opened to
 
  +
<pre>
view directory listings. Consider the below example.
 
  +
:nnoremap <C-n> :bnext<CR>
  +
:nnoremap <C-p> :bprevious<CR>
  +
</pre>
  +
  +
On gvim or if you use the NERDtree and/or Ctrlp Plugin, you may want to try using Tab and Shift-Tab instead:
  +
<pre>
  +
:nnoremap <Tab> :bnext<CR>
  +
:nnoremap &lt;S-Tab> :bprevious<CR>
  +
</pre>
  +
  +
A list of your buffers can be shown after switching by using the following maps:
  +
<pre>
  +
:nnoremap <A-n> :bnext<CR>:redraw<CR>:ls<CR>
  +
:nnoremap <A-p> :bprevious<CR>:redraw<CR>:ls<CR>
  +
</pre>
  +
  +
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.
   
  +
==Including unlisted buffers in the cycle==
  +
The <code>:bnext</code> and <code>:bprevious</code> commands skip unlisted buffers, which can prove frustrating when buffers have been opened to view directory listings, or when you want to view a buffer previously deleted with <code>:bdelete</code>. Consider the following example.
 
<pre>
 
<pre>
 
gvim ~ /etc/motd
 
gvim ~ /etc/motd
gvim goes to dir ~
+
gvim goes to directory ~
 
:bn
 
:bn
 
gvim goes to /etc/motd
 
gvim goes to /etc/motd
 
:bp
 
:bp
but will not go back to ~, because it is unlisted.
+
but will not go back to ~, because it is unlisted
 
:ls!
 
:ls!
~ is there in list of the buffers 1,2
+
~ is shown in the list of buffers 1,2
 
:buf 1
 
:buf 1
have to give it the buffer number to find it.
+
have to give it the buffer number to find it
 
</pre>
 
</pre>
   
The problem gets worse with several levels of directory navigation.
+
The problem gets worse with several levels of directory navigation. The simplest solution for this are the following two mappings:
 
The simplest solution for this is the following two mappings:
 
 
 
<pre>
 
<pre>
:map &lt;C-n&gt; :exe ":buf ".((bufnr("%") % bufnr("$"))+1)&lt;CR&gt;
+
:nnoremap <C-n> :execute ":buffer ".(bufnr("%") + 1)<CR>
:map &lt;C-p&gt; :exe ":buf ".((bufnr("%") % bufnr("$"))-1)&lt;CR&gt;
+
:nnoremap <C-p> :execute ":buffer ".(bufnr("%") - 1)<CR>
 
</pre>
 
</pre>
   
This maps <C-n> to switch to the buffer with the buffer number one higher than
+
This maps <C-n> to switch to the buffer which has a buffer number one higher than the buffer number of the current buffer. While <C-p> cycles in the opposite direction.
the buffer number of the active 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, the buffer list may contain 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 <code>:bnext</code> and <code>:bprevious</code>, the above maps will cycle from non-help buffers to help buffers and vice-versa.
However, this does not always work, because there might be holes in the buffer
 
numbers. E.g. right now my buffer list contains buffer numbers 1, 2, 6, 9, 10
 
and 14. Using the above map from buffer #6, would produce the error message
 
"E86: Buffer 7 does not exist".
 
 
A solution is to write a function searching for the next buffer with
 
bufexists().
 
   
 
A solution is to write a function searching for the next buffer with <code>bufexists()</code>, and checking its filetype with <code>getbufvar()</code>.
 
<pre>
 
<pre>
 
function! SwitchToNextBuffer(incr)
 
function! SwitchToNextBuffer(incr)
let s:last = bufnr("$")
+
let help_buffer = (&filetype == 'help')
let s:new = bufnr("%") + a:incr
+
let current = bufnr("%")
  +
let last = bufnr("$")
while s:new &lt; 1 || !bufexists(s:new)
 
let s:new = s:new + a:incr
+
let new = current + a:incr
if s:new &lt; 1
+
while 1
  +
if new != 0 && bufexists(new) && ((getbufvar(new, "&filetype") == 'help') == help_buffer)
let s:new = s:last
 
elseif s:new &gt; s:last
+
execute ":buffer ".new
let s:new = 1
+
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
 
endif
 
endwhile
 
endwhile
exe ":buf ".s:new
 
 
endfunction
 
endfunction
 
nnoremap <silent> <C-n> :call SwitchToNextBuffer(1)<CR>
 
nnoremap &lt;silent&gt; &lt;C-N&gt; :call SwitchToNextBuffer(1)&lt;CR&gt;
+
nnoremap <silent> <C-p> :call SwitchToNextBuffer(-1)<CR>
nnoremap &lt;silent&gt; &lt;C-P&gt; :call SwitchToNextBuffer(-1)&lt;CR&gt;
 
 
</pre>
 
</pre>
   
  +
==Leaving modified buffers==
== References ==
 
  +
If Vim is running with its default settings, or in vi compatible mode, the commands <code>:bnext</code>, <code>:bprevious</code> and <code>:buffer</code> won't abandon the buffer until any changes have been written. There are a few ways this can be changed.
*{{help|:unlisted-buffer}}
 
  +
*The commands can be called with a trailing !, for example, <code>:bnext!</code>, which will discard any changes made to the buffer.
  +
*Setting the ''hidden'' option (<code>:set hidden</code>) 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 (<code>:set autowrite</code> or <code>:set autowriteall</code>) will automatically save the changes made to the buffer.
  +
 
==References==
 
*{{help|:bnext}}
 
*{{help|:bnext}}
 
*{{help|:bprevious}}
 
*{{help|:bprevious}}
  +
*{{help|:bdelete}}
  +
*{{help|abandon}}
 
*{{help|unlisted-buffer}}
  +
*{{help|'hidden'}}
  +
*{{help|'autowrite'}}
  +
*{{help|'autowriteall'}}
  +
 
==Comments==
  +
The following is a tweaked version of code from a [[Vim Tips Wiki:New tips/200910#Easier buffer switching with buffer listing|proposed new tip]] (the author's original code is in the previous version of this page):
  +
<pre>
  +
function! GoBuf()
  +
bnext
  +
echon ' '
  +
for buf in range(1, bufnr('$'))
  +
echon '['
  +
if bufloaded(buf)
  +
echohl WarningMsg | echon bufname(buf) | echohl None
  +
else
  +
echon bufname(buf)
  +
endif
  +
echon '] '
  +
endfor
  +
endfunction
  +
map <F8> :call GoBuf()<CR>
  +
</pre>
   
  +
Press the mapped keys to switch to the next buffer ''and'' display a list of all buffers to indicate where you are. Problems: The list of buffers is often not visible (it is overwritten by the <code>:bnext</code> message); if have many buffers, the display is not helpful; after closing several buffers, the display includes unhelpful blank entries. [[User:JohnBeckett|JohnBeckett]] 07:03, April 27, 2010 (UTC)
== Comments ==
 

Latest revision as of 16:28, 24 June 2016

Tip 873 Printable Monobook Previous Next

created 2005 · complexity basic · version 6.0


This tip shows how to cycle through all of your buffers (including unlisted buffers such as directory listings).

For suggestions on how to switch to any other buffer see Easier buffer switching.

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>

On gvim or if you use the NERDtree and/or Ctrlp Plugin, you may want to try using Tab and Shift-Tab instead:

:nnoremap <Tab> :bnext<CR>
:nnoremap <S-Tab> :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.

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 when you want to view a buffer previously deleted with :bdelete. Consider the following example.

gvim ~ /etc/motd
    gvim goes to directory ~
  :bn
    gvim goes to /etc/motd
  :bp
    but will not go back to ~, because it is unlisted
  :ls!
    ~ is shown in the list of 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. While <C-p> cycles in the opposite direction.

However, this does not always work, because there might be holes in the buffer numbers. For example, the buffer list may contain 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>

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 !, for example, :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.

References[]

Comments[]

The following is a tweaked version of code from a proposed new tip (the author's original code is in the previous version of this page):

function! GoBuf()
  bnext
  echon '    '
  for buf in range(1, bufnr('$'))
    echon '['
    if bufloaded(buf)
      echohl WarningMsg | echon bufname(buf) | echohl None
    else
      echon bufname(buf)
    endif
    echon ']  '
  endfor
endfunction
map <F8> :call GoBuf()<CR>

Press the mapped keys to switch to the next buffer and display a list of all buffers to indicate where you are. Problems: The list of buffers is often not visible (it is overwritten by the :bnext message); if have many buffers, the display is not helpful; after closing several buffers, the display includes unhelpful blank entries. JohnBeckett 07:03, April 27, 2010 (UTC)