Very often, after days and days of coding, opening vim -S session everytime, I end up with a fair long buffer list that I want to clean.

Therefore I use :ls to list all buffers, and then :bdelete several times, with a range of buffer numbers and or explicitly specifying buffer names.

The weak points in this approach are two:

  1. if I run :bdelete on a single buffer, the lines N buffers deleted and Press ENTER or type command to continue do not appear, and the buffer list closes, so I have to run :ls again, which is very annoying;
  2. I have to run :bdelete several times, which is less a pain but still annoying.

If there's a cleaner way to list non-contiguous buffer names to :bdelete, that would be great, as it would solve 1 and 2; if not, then a way to prevent the closure of the output of :ls would be good enough, as it'd solve 2.

Important edit

I don't want to delete any buffer which is opened on a window in any tab.


2 Answers 2


For my config I wrote this:


" Wipe all deleted (unloaded & unlisted) or all unloaded buffers
function! misc#bwipeout(listed) abort
    let l:buffers = filter(getbufinfo(), {_, v -> !v.loaded && (!v.listed || a:listed)})
    if !empty(l:buffers)
        execute 'bwipeout' join(map(l:buffers, {_, v -> v.bufnr}))


" :Bwipeout[!]
" wipe all deleted/unloaded buffers
command! -bar -bang Bwipeout call misc#bwipeout(<bang>0)

Now do :Bwipeout! to clean the whole mess.

Note: :bwipeout differs from :bdelete in that it actually deletes the buffer, while :bdelete keeps name/number/local bookmarks for later re-use. You can see all "deleted" buffers by the command :ls!.

If you still want to make use of :bdelete you can adapt the code easily:

function s:bdelete() abort
    let l:buffers = filter(getbufinfo(), {_, v -> !v.loaded && v.listed})
    if !empty(l:buffers)
        execute 'bdelete' join(map(l:buffers, {_, v -> v.bufnr}))
command! -bar Bdelete call s:bdelete()
  • :bwipeout's doc says Don't use this unless you know what you are doing. Any comments on this, with respect to your solution?
    – Enlico
    Sep 2, 2020 at 12:31
  • @EnricoMariaDeAngelis If you wonder what's a (minor) difference between :bdelete and :bwipeout you should read both :h :bd and :h :bw and compare. Personally I like :bw more and use it instead of :bd on those rare occasions I have to use one of them.
    – Matt
    Sep 2, 2020 at 13:08
  • 1
    @EnricoMariaDeAngelis You might be interested in this q&a about :bwipeout
    – Rich
    Sep 2, 2020 at 14:33

For my config I wrote this:

" kill-all but visible buffers
nnoremap <silent> <M-BS> :call Delete_buffers()<CR>:echo "Non-windowed buffers are deleted"<CR>

"" Delete all(saved) but visible buffers
func! Delete_buffers()
    " all visible buffers in all tabs
    let buflist = []
    for i in range(tabpagenr('$'))
        call extend(buflist, tabpagebuflist(i + 1))

    " all existing buffers
    for bnr in range(1, bufnr("$"))
        if index(buflist, bnr) == -1 && buflisted(bnr)
            exe 'bd ' . bnr

Then with Alt+Backspace all but buffers currently visible in split windows are deleted.

Very handy to save/update session without bunch of unneeded buffers.

PS, updated to not delete buffers in other tabs.

PPS, thx @matt, better version:

func! Delete_buffers()
    let l:buffers = filter(getbufinfo(), {_, v -> v.hidden})
    if !empty(l:buffers)
        execute 'bwipeout' join(map(l:buffers, {_, v -> v.bufnr}))

  • let l:buffers = filter(getbufinfo(), {_, v -> v.hidden}) will eventually fail for modified hidden buffers.
    – Matt
    Sep 2, 2020 at 13:31
  • 1
    @Matt, yes I know. I have set confirm and get confirmation requests to save those buffers.
    – Maxim Kim
    Sep 2, 2020 at 13:43

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.