list-buffers
gives a list of all buffers. But, I want only buffers where a specific minor mode (say aggressive-indent-mode
) mode is enabled. How can I filter them?
3 Answers
You can do this easily in ibuffer
.
In an ibuffer
buffer, run M-x ibuffer-filter-by-predicate
and it will prompt you for a form. For minor modes, just enter the minor mode name variable as the predicate and it will only show you buffers with that minor mode activated.
By default ibuffer-filter-by-predicate
is bound to / e in ibuffer-mode
You can also define your own ibuffer filters using define-ibuffer-filter
For your use case this filter would work:
It allows you to specify any minor or major mode and filters the buffers accordingly.
(define-ibuffer-filter any-mode
"Toggle current view to buffers for which QUALIFIER is the active major mode or an active minor mode."
(:description "any-mode"
:reader (let ((modes))
(mapatoms
(lambda (sym)
(when (string-match-p "^[^:].+-mode$" (symbol-name sym))
(push (symbol-name sym) modes))))
(intern (completing-read "mode: " modes nil t))))
(with-current-buffer buf
(or (ignore-errors (symbol-value qualifier)) (equal major-mode qualifier))))
After evaluating the code above, the function ibuffer-filter-by-any-mode
will be available for your use.
-
Yes indeed, thanks for reminding about ibuffer-filter* predicates, which are available by default with no addl. packages or custom functions. Sep 23, 2015 at 17:06
The accepted answer is only the correct one in the case of simply wanting to see a user-viewable list of specific buffers in the list-buffers
display.
However, if you want to programmatically retrieve all buffers with a certain mode in your code, then both answers above are terrible.
The best, most minimalistic, cleanest, built-in solution is as follows:
(dolist ($buf (buffer-list (current-buffer)))
(with-current-buffer $buf
(when some-buffer-local-minor-or-major-mode-variable-you-want-to-find
(message "x %s" $buf))))
It does the following:
- Retrieve a list of all buffers via
buffer-list
, with the currently active buffer at the head of the list (so it's treated first, usually what you want, but leave out thecurrent-buffer
parameter if you don't care). - Loop through the buffer list and assign each buffer name to the variable
$buf
. - Use
with-current-buffer $buf
to tell Emacs that all code within the body should run as if it was running inside buffer$buf
instead of whatever buffer you're really displaying on screen. when <some mode variable>
is the correct way to check if a mode is enabled; you can also useif
and other such methods. Either way, the goal is to check if a minor or major-mode's main mode variable is set in the buffer. Almost all modes define a variable via "defining" a mode, which automatically causes them to create a buffer-local variable named after the mode, which is how this works. And if they don't have a standard variable, look at their own source code to see how their "toggle" code determines how to toggle them on and off. 99% of them use the existence of their modename's variable (and if they don't, I suggest reporting that as a bug to the mode's author). For example, to check if a buffer has whitespace-mode active, you would saywhen whitespace-mode
.- After that, it just outputs a message to the Messages buffer, with an "x" and the name of the buffer that had the mode active. That's where you'd put your own code, to do whatever you wanted to do with the discovered buffer.
Enjoy! Onwards to greater and cleaner lisp code!
To do it programatically you can use (get-buffers-with-minor-mode 'aggressive-indent-mode)
using the following code:
(defun get-buffers-with-minor-mode (minor-mode)
"Get a list of buffers in which minor-mode is active"
(interactive)
(let ((minor-mode-buffers))
(dolist (buf (buffer-list) minor-mode-buffers)
(with-current-buffer buf
(when (memq minor-mode (manage-minor-mode--active-list))
(push buf minor-mode-buffers))))))
;; Taken from https://github.com/ShingoFukuyama/manage-minor-mode
(defun manage-minor-mode--active-list ()
"Get a list of which minor modes are enabled in the current buffer."
(let ($list)
(mapc (lambda ($mode)
(condition-case nil
(if (and (symbolp $mode) (symbol-value $mode))
(setq $list (cons $mode $list)))
(error nil)))
minor-mode-list)
(sort $list 'string<)))
-
That is a very bad solution. Lots of wasteful variables. I'll post the cleanest, most minimal, built-in solution instead.– user14218Dec 11, 2016 at 21:37
list-buffers
(instead of, for example,buffer-list
), you gave the impression that you wanted a displayed list of buffer names, instead of a Lisp list of actual buffers. For that, @JordanBianco's answer is a good one. You did not ask for the kind of answer that you apparently wanted. (Too late to change my up vote to a down vote, unfortunately.)buffer-list
until i saw below answer. But i should have mentioned that i am looking for lisp list, my bad.