2

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?

  • The accepted answer shows that the question as posed is unclear. By mentioning 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.) – Drew Sep 23 '15 at 20:52
  • @Drew I didn't know about buffer-list until i saw below answer. But i should have mentioned that i am looking for lisp list, my bad. – ChillarAnand Sep 24 '15 at 4:57
9

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. – Emacs User Sep 23 '15 at 17:06
4

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. – gw0 Dec 11 '16 at 21:37
3

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:

  1. 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-buffer parameter if you don't care).
  2. Loop through the buffer list and assign each buffer name to the variable $buf.
  3. 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.
  4. when <some mode variable> is the correct way to check if a mode is enabled; you can also use if 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 say when whitespace-mode.
  5. 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!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.