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?
You can do this easily in
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.
ibuffer-filter-by-predicate is bound to / e in
You can also define your own ibuffer filters using
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.
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
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 the
current-bufferparameter if you don't care).
- Loop through the buffer list and assign each buffer name to the variable
with-current-buffer $bufto tell Emacs that all code within the body should run as if it was running inside buffer
$bufinstead 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 use
ifand 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 say
- 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<)))