1

:files is nice, but I want to delete a bunch of buffers at once. I know about :bd n1 n2 ... and :m,nbd, but it'd be nice to manipulate the list (e.g. to delete buffers) in a 'regular' window.

Is there any way to do this with vanilla Vim? Or are the :bd commands about as good as it gets?

This is definitely related to this question:

But I definitely want to have the buffers listed in a window (and not need to run :files over and over in the 'temporary' window in which :files is shown by default), and none of the answers on the above question cover this.

I was hoping an answer on this question would answer my own:

Alas, it (the lone answer as-of now) does not.

Kenny Evitt
  • 243
  • 1
  • 9
  • 1
    Why do you want to delete so many buffers? (I ask bc this rarely comes up for me, other than occasionally deleting one or two. It’s possible there are alternatives, though certainly some code could be written to do what youre asking.) – D. Ben Knoble Sep 02 '21 at 21:12
  • @D.BenKnoble I'm using Vim for programming and I often review a lot, e.g. dozens, of different files at various points, but then, after I finish a review, I don't need or want most of those files listed in my buffers list, mainly because I use the buffers list as a 'recently opened' files list, and it's useful for me to be able to open a new window for one of those files. (A fuzzy file/path search plugin might be helpful for this, but I don't have one installed.) – Kenny Evitt Sep 03 '21 at 15:28
  • 1
    Huh, I think my instinct at that point would be to quit vim—I probably have other things to do between reviews (git stuff, who knows), and would do that more comfortably from the shell or whatever. But i open and close vim all the time—that’s a big part of my workflow (sessions help with long-running context). Anyway, I’ll take a look this weekend at hacking something together: putting the buffers into a window is easy. Cleaning up when youre done is harder :) – D. Ben Knoble Sep 03 '21 at 15:38
  • @D.BenKnoble I do the same thing, i.e. quit Vim. I would think there's a plugin for this, and maybe I'll look for one. I just figured there was probably a way to do this in vanilla Vim – there usually is! – Kenny Evitt Sep 03 '21 at 19:43
  • 1
    If the buffers you want to get rid belong to different projects, there is a :Project prjname :bd command hidden in my library plugin. Another possibility if the buffers you want to remove share a globbing pattern, this Q/A may help. – Luc Hermitte Sep 04 '21 at 10:17

2 Answers2

2

Here is the proof of concept.

Create a function that deletes a buffer out of a line that has a buffer info:

func! DeleteBuffer() abort
    let bnr = matchstr(getline('.'), '^\s*\zs\d\+')
    exe "confirm bd" . bnr
endfunc
noremap <space>de :call DeleteBuffer()<CR>

Basically if you have a lines like:

  4  h   "templates\asciidoctor\options_ru" line 1
  5  h   "templates\asciidoctor\diagram" line 1

you can put your cursor on the line and press <space>de. Or select several lines and do the same.

To get list of buffers to some other buffer you might use:

:put=execute('ls')

So in the end it might look like this: enter image description here

Maxim Kim
  • 13,376
  • 2
  • 18
  • 46
  • The :put=execute('ls') goes a long way by itself to providing most of a 'manual' solution to what I want to be able to do. It'd be easy enough to use that output to create an Ex command to delete any number of buffers. I already have a keymap setup for myself to run the current line in a buffer as an Ex command. Thanks! – Kenny Evitt Oct 05 '21 at 15:13
1

Here's buffy, something I whipped up based on Martin's excellent batchy: Run :Buffy, edit the vimscript, and then run :Slay.

if exists('g:loaded_buffy')
  finish
endif
let g:loaded_buffy = 1

call prop_type_add('buffy', #{highlight: 'Special'})

function Buffy() abort const scriptfile = tempname() execute 'split' scriptfile setlocal nobuflisted bufhidden=wipe setfiletype buffy.vim command! -buffer Slay silent write | source % | close

const buffers = getbufinfo(#{buflisted: v:true}) \ ->filter({, v -> !empty(v.name)}) \ ->map({, v -> '" bdelete ' .. v.name}) const message = [ \ '" Buffy the buffer slayer', \ '" Uncomment the buffers you want to delete', \ '" Then run :Slay to delete the buffers and close this window', \ ] silent put =buffers silent 0put =message silent write

call prop_add(1, 1, #{end_lnum: 2, type: 'buffy'}) call prop_add(2, 1, #{end_lnum: 3, type: 'buffy'}) call prop_add(3, 1, #{end_lnum: 4, type: 'buffy'}) endfunction

command Buffy call Buffy()

Drop this in plugin/buffy.vim.

D. Ben Knoble
  • 26,070
  • 3
  • 29
  • 65
  • I'm actually running Neovim (via the VimR macOS app) and apparently Batchy doesn't work in Neovim. I'm getting some errors I imagine might be because of similar issue(s) with your script. (Apparently the -> Vimscript syntax has only maybe recently been implemented in Neovim.) – Kenny Evitt Oct 04 '21 at 20:58
  • 1
    @KennyEvitt yeah, I don't have time to port to NeoVim compatible, but it boils down to usually a->f(x) is like f(a, x). – D. Ben Knoble Oct 04 '21 at 21:00
  • No worries! I appreciate the plugin and might use it as an impetus to either upgrade 'Vim' on my computer, or learn me some Vimscript. – Kenny Evitt Oct 04 '21 at 21:06
  • 1
    @KennyEvitt if the const buffers is the issue, try const buffers = map(filter(getbufinfo(#{buflisted: v:true}), {_, v -> !empty(v.name)}), {_, v -> '" bdelete ' .. v.name}) (a lot less readable, but should semantically be the same). Adjust if your vim does not have #{} literals, too, or -> lambdas (seen in the filter and map arguments). Those take a bit more to rewrite. – D. Ben Knoble Oct 04 '21 at 23:11
  • Thanks! I'll try that when I get a chance. But I think the -> lambdas are what was maybe just implemented in Neovim. – Kenny Evitt Oct 05 '21 at 15:04
  • I just want to marvel at how cool Vim is that this kind of thing is possible, and seemingly straightforward for people like yourself that understand Vim (at least) pretty well! A trick in something like the same genre that I've been using is to include Vim Ex commands in, e.g. my notes files, and then use a keymap to execute those commands. That seems very much like what your plugin does! – Kenny Evitt Oct 05 '21 at 15:11
  • 1
    @KennyEvitt that patch is for method syntax, not lambdas. Yeah, this function does something similar: it generates a script, which you modify, and then executes it. Here's without lambdas but with method syntax (and then you could still get rid of method syntax if you wanted): const buffers = getbufinfo(#{buflisted: v:true})->filter('!empty(v:val.name)')->map("'\" bdelete ' .. v:val.name") – D. Ben Knoble Oct 05 '21 at 15:20
  • 1