24

Is there a way to search all the open buffers for a particular pattern?

C-s interactively searches current buffer. Similarly, is there something that searches all the open buffers?

I know I can use "occur", but "Occur" brings a new buffer and changes/messes with the buffer organization.

John D. Cook
  • 29,517
  • 10
  • 67
  • 94
iobelix
  • 1,143
  • 1
  • 10
  • 16

7 Answers7

33

The built-in multi-occur-in-matching-buffers hasn't been mentioned. I use a modified version of this (because I invariably want to search all buffers, and specifying a buffer name pattern each time is annoying).

(defun my-multi-occur-in-matching-buffers (regexp &optional allbufs)
  "Show lines matching REGEXP in all file-visiting buffers.

Given a prefix argument, search in ALL buffers."
  (interactive (occur-read-primary-args))
  (multi-occur-in-matching-buffers "." regexp allbufs))

(global-set-key (kbd "M-s /") 'my-multi-occur-in-matching-buffers)

To invert the behaviour of the prefix argument so that the default behaviour is to search all buffers, change the call to:

(multi-occur-in-matching-buffers "." regexp (not allbufs))

(and, of course, update the docstring accordingly.)

phils
  • 71,335
  • 11
  • 153
  • 198
  • 3
    Very nice. One can spend an infinite amount of time tweaking and customizing emacs... – Bogatyr Apr 20 '13 at 17:53
  • 1
    When I use this, it only says "Searched 1 buffer" even if I have 20 buffers open in emacs. Why would that be? – johnbakers Jan 21 '15 at 15:44
  • 1
    @johnbakers: Most likely because `multi-occur-in-matching-buffers` only searches file-visiting buffers by default. If you pass a prefix argument (the optional `allbufs` argument) then it searches all buffers (matching the buffer name rather than the file name), but I failed to pass that argument along in my function, so prefix arguments were being ignored. I've fixed that now. Change `(multi-occur-in-matching-buffers ".*" regexp allbufs)` to `(multi-occur-in-matching-buffers ".*" regexp (not allbufs))` if you would prefer to invert that behaviour. – phils Mar 08 '17 at 12:20
16

I've fixed the TODO:

;; I know that string is in my Emacs somewhere!
(require 'cl)
(defcustom search-all-buffers-ignored-files (list (rx-to-string '(and bos (or ".bash_history" "TAGS") eos)))
  "Files to ignore when searching buffers via \\[search-all-buffers]."
  :type 'editable-list)

(require 'grep)
(defun search-all-buffers (regexp prefix)
  "Searches file-visiting buffers for occurence of REGEXP.  With
prefix > 1 (i.e., if you type C-u \\[search-all-buffers]),
searches all buffers."
  (interactive (list (grep-read-regexp)
                     current-prefix-arg))
  (message "Regexp is %s; prefix is %s" regexp prefix)
  (multi-occur
   (if (member prefix '(4 (4)))
       (buffer-list)
     (remove-if
      (lambda (b) (some (lambda (rx) (string-match rx  (file-name-nondirectory (buffer-file-name b)))) search-all-buffers-ignored-files))
      (remove-if-not 'buffer-file-name (buffer-list))))

   regexp))

(global-set-key [f7] 'search-all-buffers)
offby1
  • 6,767
  • 30
  • 45
  • Should there be a `(require 'cl)` before this? I have no idea why, but that fixed an error I got. NB: I am a lisp noob. – cammil Jan 26 '13 at 17:26
  • cammil: I think you're right; "remove-if" and "remove-if-not" are in the "cl" library. – offby1 Jan 26 '13 at 23:27
11

ibuffer might help you. Have a look at this article. I imagine that this might be most interesting for you:

'O' - ibuffer-do-occur - Do an occur on the selected buffers. This does a regex search on all the selected buffers and displays the result in an occur window. It is unbelievably useful when browsing through code. It becomes truly awesome when you combine it with the ‘filter’ powers of ibuffer (coming up ahead). Eg: Do C-x C-b, mark all files using (say) Perl major-mode, do occur to find out all places where a certain function is mentioned in these files. Navigate to the point at will through the Occur window.

'M-s a C-s' - ibuffer-do-isearch - Do an incremental search in the marked buffers. This is so awesome that you have to try it right this instant. Select two or more buffers, hit the hotkey, search for something that occurs in all these buffers. These two features alone are enough to make me a lifelong fan of IBuffer. Go do it now!

Bozhidar Batsov
  • 55,802
  • 13
  • 100
  • 117
  • 4
    You don't need ibuffer for that -- the "standard" buffer menu acts the same way: mark some buffers and do M-s a C-s (or M-x Buffer-menu-isearch-buffers). It would be nice if this functionality were generalized so that one didn't have to mark buffers. It should be easy to implement -- there exists a multi-isearch-buffers function, one just needs to supply a list of open buffers as its argument. – Leo Alekseyev Apr 14 '10 at 23:27
  • Thank you, Bozhidar B. & Leo A. I have been wanting a way to search and also replace only in open buffers. I had no idea that *Buffer List* supported anything but listing, visiting, and killing: my very large oversight. – Zach Young Sep 24 '10 at 18:13
8

Taking a clue from Leo's comment to Bozhidar:

(defun my-isearch-buffers ()
  "isearch multiple buffers."
  (interactive)
  (multi-isearch-buffers
   (delq nil (mapcar (lambda (buf)
                       (set-buffer buf)
                       (and (not (equal major-mode 'dired-mode))
                            (not (string-match "^[ *]" (buffer-name buf)))
                            buf))
                     (buffer-list)))))

You might have to tweak the conditions inside the and to filter whatever other kinds of buffers you want to ignore.

scottfrazer
  • 17,079
  • 4
  • 51
  • 49
1

Although this is not exactly what you're asking for, I search multiple files using grep (M-X grep) and grep-find (M-X grep-find).

Paul Ellis
  • 106
  • 3
1

This sort of does what you want, in that when you've come to the end of matches for the string/regexp you're searching for, the next search command will start in a new buffer.

(setq isearch-wrap-function 'isearch-bury-buffer-instead-of-wrap)
(defun isearch-bury-buffer-instead-of-wrap ()
  "bury current buffer, try to search in next buffer"
  (bury-buffer))

It doesn't switch to a different buffer when the search fails, and when you "back up" the search results by pressing <backspace>, you won't pop back into the previous buffers searched.

Trey Jackson
  • 73,529
  • 11
  • 197
  • 229
1

In Icicles, C-c ' is command icicle-occur, which can search multiple buffers.

C-u C-c ' searches a set of buffers that you choose. You can choose by dynamically filtering the buffer names with your minibuffer input, then hit C-! to search all of those buffers whose names match. Similarly, C-99 C-c ' searches only the buffers that are visiting files.

Like occur and grep, icicle-occur searches line by line. More generally, instead of using lines as the search contexts you can use any buffer portions at all. C-c ` (backquote instead of quote) is command icicle-search. With a non-negative prefix arg it searches a set of buffers that you choose.

The first thing you do is give it a regexp that defines the search contexts. E.g., if you give it .* then it acts like icicle-occur: each search context is a line. If you give it a regexp that matches only function definitions then those are the search contexts, and so on.

http://www.emacswiki.org/emacs/Icicles_-_Search_Commands%2c_Overview

Drew
  • 29,895
  • 7
  • 74
  • 104