4

I would like to run a command and go to the first matching regex pattern that matches in any open buffer.

Kind of like search-forward-regex.

The requirements are:

  • not be limited to forward/backward. It should go to any direction.
  • be global and search through all buffers.
  • it should not be a list of matching options like (helm-swoop-all), but it should actually jump to what ever matches first
  • it should be a regex search, not a word search

Is this possible?

[EDIT] SOLVED

With a few tweaks of the answer below, it now works.

The reason for this was actually part of go-to-item-that-links-to-id-of-current-item

With the below, I can add an elisp link like [[elisp:(my/goto-parent)][parent]] to the heading of a task (via abbrevations), and then I can navigate to the parent if something links to it.

(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))

(defun my/search-all-buffers-first-result (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."

  ;Cache how many windows are open atm.
  (setq my-var/multi-window (one-window-p)) ;true if single frame.
  (interactive (list (grep-read-regexp)
                     current-prefix-arg))
  (search-all-buffers regexp prefix)
  (next-error)
  (kill-buffer "*Occur*")

  ;if there were more than one window open, kill the other once.
  (when my-var/multi-window (delete-other-windows))
) 

(defun my/goto-parent () 
  "Find the parent of this task by looking for what links to this task"
  (interactive)
  (my/search-all-buffers-first-result (concat "id:" (org-id-get)) nil)
)

2 Answers 2

2

The search-all-buffers function defined in this StackOverflow solution by @offby1 fits this bill.

I am pasting the same here for convenience.

;; 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))

Here is how to use it:

  • Copy that search-all-buffers solution to your init.el and evaluate.
  • Do M-x search-all-buffers
  • Hit M-g M-n (next-error) to go to the first search result.

Here is a wrapper function to always take you to the first result.

  • When creating a wrapper function wrapper-fn around a function fn, you need to insure that the fn function somehow gets all its needed arguments from wrapper-fn. The easiest way is to copy the interactive call from fn to wrapper-fn.
(defun my/search-all-buffers-first-result (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))
  (search-all-buffers regexp prefix)
  (next-error)
  (kill-buffer "*Occur*")) 
5
  • I have updated the solution with a wrapper function. Feb 19, 2015 at 21:03
  • Thank you very much for the wrapper. There is only one small quirk. If I only have a single window open, the code above will open a 2nd window (split view side by side). It works well if you have split windows already thou? Feb 19, 2015 at 21:12
  • If you like to always have only one window open, you can add (delete-other-windows) after the (kill-buffer "*Occur*") line. Feb 19, 2015 at 21:15
  • Thank you for all your help. We are getting there. I sometimes work in single window and sometimes in 2 windows. Can I somehow 'count' the number of open windows? so that if there is only 1 originally, I could run (delete-other-windows) after. Edit one-window-p might get the trick done.. Feb 19, 2015 at 21:23
  • With caching of one-window-p and (delete-other-window) I got it to work as desired. Thank you so much for your answer and the followup comments, highly highly appreciated. Feb 19, 2015 at 21:52
2

Take a look at misearch.el (yes, the m stands for multi). Basic example:

(defun isearch-all-buffer-regexp ()
  (interactive)
  (multi-isearch-buffers-regexp (buffer-list)))
7
  • This is somewhat close to what I need. Except I need a non 'i' search (non incremental search) but the multi-isearches only come in the 'i' flavour. The reason is that 'i' searches don't match things like text inside links. E.g an isearch of "id:b98" doesn't find [[id:b98...][name]], where as a regular regex search does find it. Feb 19, 2015 at 20:53
  • I guess it will, if you tell it to via isearch-toggle-invisible.
    – politza
    Feb 19, 2015 at 21:26
  • I tried that, unfortunatley it still doesn't find content inside a link.. Feb 19, 2015 at 21:27
  • I suppose this a link in org-mode and conclude that it has not setup the overlay appropriately.
    – politza
    Feb 19, 2015 at 21:29
  • It is an org-mode link yes. I don't know what it means to have the overlay set up appropriatley. In org mode, [[id:xyz][hello world]] is just shown as 'hello world' in blue font. But I want to find the 'id:xyz' part that is not visible. This can be found via search, but not isearch. Thoughts? Feb 19, 2015 at 21:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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