How to delete multiple buffers in Vim?
Asked Answered
P

8

148

Assuming I have multiple files opened as buffers in Vim. The files have *.cpp, *.h and some are *.xml. I want to close all the XML files with :bd *.xml. However, Vim does not allow this (E93: More than one match...).

Is there any way to do this?

P.S. I know that :bd file1 file2 file3 works. So can I somehow evaluate *.xml to file1.xml file2.xml file3.xml?

Poree answered 1/7, 2010 at 6:16 Comment(0)
T
243

You can use <C-a> to complete all matches. So if you type :bd *.xml and then hit <C-a>, vim will complete the command to :bd file1.xml file2.xml file3.xml.

Tesler answered 29/2, 2012 at 12:31 Comment(7)
@Florian <tab> only allows you to cycle through the matches, putting a single entry on the command line, <C-a> adds all matches at once.Kudu
my god you're right! sorry. tab just works when there is only one possible result.Gender
How do you use <C-a> with vim on tmux?Herd
tmux doesn't bind <C-a> by default, but if you configured it to e.g. use <C-a> instead of <C-b> to emulate screen, you should also configure it to map, for example, <C-a>a to pass a <C-a> through to the program running inside tmux. The screen-keys.conf that comes with tmux does that.Kudu
JFTR, in case you have vim-rsi installed (I think, it's a must have for everyone on *nix), to get the <C-a> work the original way in the command line, you should use <C-x> <C-a> instead.Tetrafluoroethylene
A way to pass the <C-a> to vim from tmux is press <C-a>:send-prefix. That way vim will receive the <C-a>Epineurium
Is there an undo version of <C-A>? Say I've got */config* and hit <C-A>, is there a way to return to */config/* instead of all the matches? Would help finding the right paths to use. <C-d> is at least a preview, so that'll work in a pinchBlastula
B
67
:3,5bd[elete]   

Will delete buffer range from 3 to 5 .

Baptiste answered 4/1, 2017 at 7:24 Comment(1)
If you want to delete single buffers such as 3 and 5, use :bd 3 5.Longfaced
T
26

You also can use alternatively use:

    :.,$-bd[elete]    " to delete buffers from the current one to last but one
    :%bd[elete]       " to delete all buffers
Toddy answered 19/1, 2016 at 6:40 Comment(1)
This works nice. I do a :ls to see buffer numbers and them :a,bbd to delete buffers from number a to bMarcille
E
8

You can use this.

:exe 'bd '. join(filter(map(copy(range(1, bufnr('$'))), 'bufname(v:val)'), 'v:val =~ "\.xml$"'), ' ')

It should be quite easy to add it to a command.

function! s:BDExt(ext)
  let buffers = filter(range(1, bufnr('$')), 'buflisted(v:val) && bufname(v:val) =~ "\.'.a:ext.'$"')
  if empty(buffers) |throw "no *.".a:ext." buffer" | endif
  exe 'bd '.join(buffers, ' ')
endfunction

command! -nargs=1 BDExt :call s:BDExt(<f-args>)
Eleanor answered 1/7, 2010 at 9:30 Comment(4)
I know next to nothing about Vimscript, but how about glob() function?Poree
glob() will only give you existing files (on your hard drive), and not opened buffers.Eleanor
You forgot to fnameescape() buffer names.Significs
I've just checked with c:/Program files/foo.bar, and even foo.bar.foo and it worked perfectly. fnameescape() may have been required if I used the buffer names. But I'm only checking whether the buffer names match a given expression: \.{ext}$ -- I give buffer numbers to :bd`. I don't any reason to escape anything for regex matching.Eleanor
H
5

Try the script below. The example is for "txt", change it as needed, e.g. to "xml". Modified buffers are not deleted. Press \bd to delete the buffers.

map <Leader>bd :bufdo call <SID>DeleteBufferByExtension("txt")

function!  <SID>DeleteBufferByExtension(strExt)
   if (matchstr(bufname("%"), ".".a:strExt."$") == ".".a:strExt )
      if (! &modified)
         bd
      endif
   endif
endfunction

[Edit] Same without :bufdo (as requested by Luc Hermitte, see comment below)

map <Leader>bd :call <SID>DeleteBufferByExtension("txt")

function!  <SID>DeleteBufferByExtension(strExt)
   let s:bufNr = bufnr("$")
   while s:bufNr > 0
       if buflisted(s:bufNr)
           if (matchstr(bufname(s:bufNr), ".".a:strExt."$") == ".".a:strExt )
              if getbufvar(s:bufNr, '&modified') == 0
                 execute "bd ".s:bufNr
              endif
           endif
       endif
       let s:bufNr = s:bufNr-1
   endwhile
endfunction
Hedges answered 1/7, 2010 at 10:45 Comment(1)
I don't like :bufdo as it messes the current window.Eleanor
A
4

TAB will only autocomplete one file for you as of Vim 7.4.282
use <c-a> to autocomplete all files.

You can just use:

bd filetype

then just use <c-a> to facilitate the completion of all open files of specified filetype.

for example, you have 1.xml, 2.xml, 3.xml, and 4.xml, you can do:

bd xml

then press <c-a>

vim will autocomplete for you as follow:

bd 1.xml 2.xml 3.xml 4.xml

you can just press enter to complete the command.

if you have made changes in one of the files mentioned above, do remember to do:

bd! xml
Apprise answered 16/5, 2016 at 12:45 Comment(0)
R
3

I too had a need for this functionality all the time. This is the solution I have in my vimrc.

function! GetBufferList()
    return filter(range(1,bufnr('$')), 'buflisted(v:val)')
endfunction

function! GetMatchingBuffers(pattern)
    return filter(GetBufferList(), 'bufname(v:val) =~ a:pattern')
endfunction

function! WipeMatchingBuffers(pattern)
    let l:matchList = GetMatchingBuffers(a:pattern)

    let l:count = len(l:matchList)
    if l:count < 1
        echo 'No buffers found matching pattern ' . a:pattern
        return
    endif

    if l:count == 1
        let l:suffix = ''
    else
        let l:suffix = 's'
    endif

    exec 'bw ' . join(l:matchList, ' ')

    echo 'Wiped ' . l:count . ' buffer' . l:suffix . '.'
endfunction

command! -nargs=1 BW call WipeMatchingBuffers('<args>')

Now, I can just do :BW regex (e.g. :BW \.cpp$ and wipe all matching buffers that have match that pattern in their pathname.

If you want to delete rather than wipe, you can of course replace exec 'bw ' . join(l:matchList, ' ') with exec 'bd ' . join(l:matchList, ' ')

Rachealrachel answered 1/2, 2011 at 21:9 Comment(1)
I sometimes wonder why vim doesn't support regular expressions everywhere (:badd, :bdelete, :bufdo, :bn...)Tirza
C
2

Very simply: use the :bd[elete] command. For example, :bd[elete] buf#1 buf#5 buf#3 will delete the buffers 1, 3, and 5.

Curst answered 19/10, 2014 at 18:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.