144

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?

Teun Zengerink
  • 4,277
  • 5
  • 30
  • 32
Thanh DK
  • 4,257
  • 3
  • 23
  • 18

8 Answers8

235

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.

Björn Steinbrink
  • 2,556
  • 1
  • 16
  • 8
  • 12
    @Florian `` only allows you to cycle through the matches, putting a single entry on the command line, `` adds all matches at once. – Björn Steinbrink Jul 18 '13 at 09:53
  • my god you're right! sorry. tab just works when there is only one possible result. – Florian Klein Jul 18 '13 at 11:55
  • How do you use with vim on tmux? – nabn May 25 '15 at 05:04
  • 5
    tmux doesn't bind by default, but if you configured it to e.g. use instead of to emulate screen, you should also configure it to map, for example, a to pass a through to the program running inside tmux. The screen-keys.conf that comes with tmux does that. – Björn Steinbrink May 26 '15 at 09:15
  • 12
    JFTR, in case you have [`vim-rsi`](https://github.com/tpope/vim-rsi) installed (I think, it's a must have for everyone on \*nix), to get the `` work the original way in the command line, you should use `` `` instead. – kostix Jul 10 '17 at 09:08
  • A way to pass the to vim from tmux is press :send-prefix. That way vim will receive the – Javi Sep 25 '18 at 22:51
  • Is there an undo version of ``? Say I've got `*/config*` and hit ``, is there a way to return to `*/config/*` instead of all the matches? Would help finding the right paths to use. `` is at least a preview, so that'll work in a pinch – TankorSmash May 13 '20 at 16:25
63
:3,5bd[elete]   

Will delete buffer range from 3 to 5 .

Fisherman
  • 5,949
  • 1
  • 29
  • 35
25

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
Cylian
  • 10,970
  • 4
  • 42
  • 55
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>)
Luc Hermitte
  • 31,979
  • 7
  • 69
  • 83
  • I know next to nothing about Vimscript, but how about glob() function? – Thanh DK Jul 01 '10 at 10:14
  • 1
    `glob()` will only give you existing files (on your hard drive), and not opened buffers. – Luc Hermitte Jul 01 '10 at 10:25
  • You forgot to `fnameescape()` buffer names. – ZyX Mar 02 '12 at 04:43
  • 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. – Luc Hermitte Mar 02 '12 at 08:28
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
Habi
  • 3,262
  • 25
  • 23
3

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
stucash
  • 1,078
  • 1
  • 12
  • 23
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, ' ')

Kent
  • 449
  • 2
  • 5
  • 1
    I sometimes wonder why vim doesn't support regular expressions everywhere (`:badd`, `:bdelete`, `:bufdo`, `:bn`...) – puk Jan 09 '12 at 23:51
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.

J0e3gan
  • 8,740
  • 10
  • 53
  • 80
Harry
  • 63
  • 1
  • 10