5

Is there a way to view a list of open buffers and close several buffers without leaving that list?

The best I know of for closing multiple buffers is using :ls to get a list of buffers, memorizing the numbers of the buffers you want to close, and then using :bdelete/:bd with a prefix to close those buffers, e.g. :3,5bd. Sometimes I'll have several buffers open and I want to close a buffer (or at least mark a buffer to be closed) while still looking for more buffers to close. With :ls and :bd, this is very inconvenient because I have to enter :ls again and again between closing buffers rather than closing several buffers and then signaling that I'm done.

2 Answers 2

7

There is a popular mapping that will show the :ls result above a prompt:

:nnoremap <leader>ls :ls<cr>:b<space>

Instead of showing :b, as in that mapping, we'll show :bd instead:

:nnoremap <leader>lsd :ls<cr>:bd<space>

(If you prefer a different mapping than lsd, heh, feel free to change it.)

Append whatever buffer numbers you want to delete, space separated, and hit Enter.

If you'd rather enter ranges of buffer numbers, like :2,5bd this variation will put the cursor at the beginning, before bd:

:nnoremap <leader>lsd :ls<cr>:bd<home>

But you have to pick one or the other or use two mappings. Personally I use the first mapping and hit Home if I want to enter a range.

Bonus Update: Wanted to stretch my vimscript muscles so came up with this...

" Displays buffer list, prompts for buffer numbers and ranges and deletes
" associated buffers. Example input: 2 5,9 12
" Hit Enter alone to exit. 
function! InteractiveBufDelete()
    let l:prompt = "Specify buffers to delete: "

    ls | let bufnums = input(l:prompt)
    while strlen(bufnums)
        echo "\n"
        let buflist = split(bufnums)
        for bufitem in buflist
            if match(bufitem, '^\d\+,\d\+$') >= 0
                exec ':' . bufitem . 'bd'
            elseif match(bufitem, '^\d\+$') >= 0
                exec ':bd ' . bufitem
            else
                echohl ErrorMsg | echo 'Not a number or range: ' . bufitem | echohl None
            endif 
        endfor
        ls | let bufnums = input(l:prompt)
    endwhile 

endfunction

Put in your vimrc file along with a mapping like this...

nnoremap <silent> <leader>bd :call InteractiveBufDelete()<CR>

Now if you hit \bd in Normal mode you'll see the buffer listing and a prompt. Enter space-separated numbers or ranges, such as 2 5,8 11, and hit Enter and all associated buffers will be deleted. The process will repeat until you hit Enter alone.

(I'll leave it to you to add any additional validation or error checking beyond what I have.)

8
  • Can this close multiple buffers? This doesn't work with the "3,5" style. Jan 17, 2018 at 7:33
  • As it says space separated.
    – B Layer
    Jan 17, 2018 at 7:34
  • Oops, so I can give multiple buffers, which is pretty good, but can I give a range? Jan 17, 2018 at 7:36
  • 1
    Hmm, that's unfortunate. This is a good answer so +1, but it doesn't fulfill all my hopes and dreams. I suspect this is the best there is in vim-land at the moment so I'll hold out hope for an answer with deeper enlightenment for a day or so but after that I'll accept this ;-P. Jan 17, 2018 at 7:43
  • 1
    Thus the last line of my answer, "I'll leave it to you...". It's usually beyond the scope of here to have full blown solutions with validation and what not...decreases the signal-to-noise ratio too much.
    – B Layer
    Jan 21, 2018 at 9:44
0

A really cool trick I picked up somewhere is to write Ex commands in a regular buffer and then use a keymap to execute those commands:

" Execute current line or current selection as Vim ex commands:
nnoremap <F2> :exe getline(".")<CR>
vnoremap <F2> :<C-w>exe join(getline("'<","'>"),'<Bar>')<CR>

I asked a question very similar to this question and part of one of the answers mentions using this command to output the buffer list into a regular buffer (i.e. the current one):

:put=execute('ls')

To me, it then seems very Vimmy to:

  1. Open a new (empty) buffer.
  2. Run :put=execute('ls') to list the buffers in the new buffer.
  3. Use regular Vim commands to create Ex command(s) to delete the buffers I want to delete, e.g. by first deleting the buffer info lines for buffers I want to keep, then using various visual selection/block commands to delete the buffer info other than the buffer numbers, and finally combining all of the buffer numbers into one (or maybe more) :bd ... commands.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.