Interesting question. I had to think about how to do this as I wanted to avoid using :ls a
. (Parsing :ls
output isn't ideal in much the same way that parsing the output of the shell command ls
is non-ideal.) I've got it down to a single Ex command line, though one that could use a bit of explanation depending on your familiarity with Vim.
Per :h active-buffer
, an active buffer is one that is currently being displayed in a Vim window. I figured that if that is an easily obtainable piece of information then it's likely that it would be provided by the function that is a one-stop shop for all your buffer info needs: getbufinfo()
.
Specifically, I have in mind the windows
property that is included in getbufinfo()
output. This property contains a list of all the windows the associated buffer currently appears in. If it's in a window then it's active, right?
Cutting to the chase here's the command that displays the buffers appearing in windows, i.e. the active buffers:
:echo filter(getbufinfo({'bufloaded':1}), {v -> len(v:val['windows'])})
Breaking it down:
filter(list_or_dict, condition)
: takes a List or Dictionary and removes some subset of elements from it based on a condition. The condition is specified in the second param as an expression or function which is evaluated for each element. A non-zero result means the element is kept, otherwise it is dropped (filtered out). As for the specific parameters being used...
getbufinfo({'bufloaded':1})
: As mentioned above this function provides a bunch of info about a buffer or buffers. The Dictionary we're passing in as a param is telling the function to only return buffers that are loaded. By definition an active buffer is a loaded buffer so this allows us to narrow things down a bit. The returned value is a List of Dictionary objects, one for each loaded buffer.
{v -> len(v:val['windows'])}
: For each buffer-associated Dictionary retrieved from getbufinfo()
we want to determine how many elements are in the windows
property (which is itself a List) and drop buffers with none. We need to evaluate to zero for those elements we want dropped and this works out nicely as we just make a call to the length function len()
and return whatever it returns.
If you're not familiar with the ->
notation it's basically just a shorthand way of calling a function, in this case one that takes a single parameter. Explaining this "lambda expression" further is probably beyond the scope of this answer but I think it's otherwise pretty clear what's going on here.
Here's an example use of the command. You can replace the echo
call with whatever work you want to do against each buffer. The buffer number is available so you can address each buffer by that (among other possibilities). If you want me to get into that a bit further let me know.
for buf in filter(getbufinfo({'bufloaded':1}), {v -> len(v:val['windows'])})
echo buf.bufnr buf.name
endfor
:bufdo
with a function which uses:h :redir
to write the output of:ls
in a variable, turn it into a list, and switch to each buffer to execute your command? Or use:h :windo
or:h :tabdo
to execute only on buffer in the current window or in all tabs? Or put the output of:ls a
in the quickfix list and use:h :cfdo
?argdo
(and the myriad of ways to fill the arg list, including:args `git ls-files`
:argdo
, but could not find how to populate:args
with the output of:ls a
.