Emacs: Is it possible to list all matching lines for a certain query string for marked files in dired? - search

I found out M-x occur the other day.
(How to achieve code folding effects in Emacs?)
I wonder if I could list all matching lines in multiple files(or buffers) preferably marked in dired mode.

Files
This can be done using package noccur which can be installed from MELPA.
It provides two functions:
noccur-dired that will perform multi-occur on dired marked files
noccur-project that will perform multi-occur on all files in current project. This is recursive.
From documentation a typical usage is: M-x noccur-project RET foo RET
The occur buffer's content can then be edited with occur-edit-mode (bound to e). To save changes in all modified buffer and go back to occur-mode press C-c C-c.
Buffers
This can be done using the built-in ibuffer. Mark buffers with m key, then key O to launch ibuffer-do-occur on marked buffers. I personally activate ibuffer using (defalias 'list-buffers 'ibuffer) in my .emacs.
You can also use the built-in multi-occur-in-matching-buffers that will perform multi-occur on buffers matching a regexp. Typical usage is M-x multi-occur-in-matching-buffers RET ext$ RET regexp RET where ext$ is regexp for buffers already opened in Emacs, and regexp is what to match.

M-x multi-occur
M-x multi-occur-in-matching-buffers
and also:
M-x multi-occur-in-this-mode
(defun get-buffers-matching-mode (mode)
"Returns a list of buffers where their major-mode is equal to MODE"
(let ((buffer-mode-matches '()))
(dolist (buf (buffer-list))
(with-current-buffer buf
(if (eq mode major-mode)
(add-to-list 'buffer-mode-matches buf))))
buffer-mode-matches))
(defun multi-occur-in-this-mode ()
"Show all lines matching REGEXP in buffers with this major mode."
(interactive)
(multi-occur
(get-buffers-matching-mode major-mode)
(car (occur-read-primary-args))))

You may try
(defun dired-do-multi-occur (regexp)
"Run `multi-occur' with REGEXP on all marked files."
(interactive (list (read-regexp "Regexp: ")))
(multi-occur (mapcar 'find-file-noselect (dired-get-marked-files)) regexp))
Run it in a dired buffer with M-x dired-do-multi-occur or bind it to a key of your liking.
Warning: all marked files will be opened by emacs.

In Icicles, use M-s M-s m (command icicle-search-dired-marked-recursive) to search the marked files in the current Dired buffer and in all marked subdirs, recursively.
Similarly, in your bookmark-list display the same key, M-s M-s m, searches the targets of all marked bookmarks. And similarly for Ibuffer and Buffer Menu: M-s M-s m searches the marked buffers.
This is Icicles search, which is a different kind of incremental search (and on-demand replace). You can confine searching within particular contexts (defined by a regexp). The search hits are updated incrementally as you change your search pattern. You can combine multiple search patterns, to refine your search progressively. You can cycle through any set of search hits or access them directly. You can change cycle orders --- you are not limited to buffer-occurrence order.
http://www.emacswiki.org/emacs/Icicles_-_Search_Commands%2c_Overview

Let me improve on the answer of mk1 since I think it is the best one so far. This keeps the same history of previous searches of occur and allows for the optional argument for displaying more lines after or before the match (using C-u followed by a number before calling the function), just as in standard occur.
(defun dired-do-multi-occur (regexp &optional nlines)
"Run `multi-occur' with REGEXP on all dired marked files."
(interactive (occur-read-primary-args))
(multi-occur (mapcar 'find-file-noselect (dired-get-marked-files)) regexp nlines))

Wrt Dired:
Not sure whether you are asking (a) to regexp-search the files marked in Dired or (b) to mark files (in Dired) whose contents match a regexp. - or (c) something else.
You can do the former (search marked files) using A (or M-S a C-M-s for incremental regexp search). And this answer lets you search all files marked here and in marked subdirs (recursively).
You can do the latter (mark the files whose contents match) using %q (dired-mark-files-containing-regexp).

Related

emacs run shell command against current buffer's file name [duplicate]

I can run a shell command quickly by hitting M-!. One thing I'd like to do is perform shell quick operations on the current file. An example would be checking the file out through perforce:
M-! p4 edit buffer-file-name RET
(Yes there are perforce integrations, but I'm more interested in the minishell/variable problem rather than a specific workflow)
Of course, the buffer-file-name variable is not evaluated before the command is sent to the shell.
Is there an easy on-the-fly way to do this? Or will I have to roll a custom elisp function?
It seems current Emacs has something built-in to achieve the desired result, after M-! (shell-command) press <down>, you will get the file name you are currently visiting on the prompt. Now you can edit it to add the command you want to run on it.
In dired-mode it will give you the file your cursor is currently on.
Indeed using C-u M-: is almost right. I'm not so sure about using shell-quote-argument in eval-to-shell-argument since it only works on strings making it impossible to use eval-to-shell-argument to insert a number or a symbol. You could try something like:
(defun sm-minibuffer-insert-val (exp)
(interactive
(list (let ((enable-recursive-minibuffers t))
(read-from-minibuffer "Insert: "
nil read-expression-map t
'read-expression-history))))
(let ((val (with-selected-window (minibuffer-selected-window)
(eval exp)))
(standard-output (current-buffer)))
(prin1 val)))
and then bind this function in your minibuffer with (define-key minibuffer-local-map [?\M-:] 'sm-minibuffer-insert-val).
Of course, if the only thing you ever want to insert is the buffer-file-name, then your execute-shell-command-on-buffer is simpler.
I did roll my own elisp function, and it looks like this:
(defun execute-shell-command-on-buffer (shell-command-text)
(interactive "MShell command:")
(shell-command (format shell-command-text (shell-quote-argument buffer-file-name)))
)
https://gist.github.com/2367513
I bound it to M-", so now my example can be completed with:
M-"p4 edit %sRET
I won't accept this as the answer, because I did ask for solutions that don't require a function.
You can use C-u M-: (eval-expression with a universal prefix argument) to evaluate any Lisp expression and insert its value at point in the current buffer (including minibuffers, as long as you have enable-recursive-minibuffers set to a non-nil value).
In your example: C-u M-: buffer-file-name RET.
Note that the result of the expression is printed in Lisp form: that is, quoted in such a way that a subsequent call to read would construct an equal Lisp value. For strings, this means enclosing in double quotes, which will probably be interpreted as you expect by the inferior shell. However, you may run into problems with strings that contain special characters, which need different escaping by Elisp and the shell.
The more correct way uses shell-quote-argument, as in phils' solution. Here's a quick defun that reads a Lisp expression and inserts its value at point as a properly quoted shell word:
(defun eval-to-shell-argument (form)
(interactive "XEval: ")
(insert (shell-quote-argument form)))
The read-and-evaluate step happens automatically by using an "X" as the argument to interactive.
Edited to add: As #tenpn notes, the above solution doesn't work for inserting buffer-local variables like buffer-file-name in a minibuffer like the one M-! pops up (more precisely, it inserts the buffer-local value of the minibuffer, which is unlikely to be useful). Here is a revised version which seems to work. If the minibuffer is active, it makes the buffer of the previously-selected window temporarily active while reading and evaluating an expression.
Final edit: From #Stefan's answer I see that I should have used (minibuffer-selected-window) to find the previously-selected window. I've also added a (format "%s" ..) to allow inserting non-string values, while still quoting special characters in strings. Here's the final version:
(defun eval-to-shell-argument ()
(interactive)
(let* ((buffer
(if (minibufferp)
(window-buffer (minibuffer-selected-window))
(current-buffer)))
(result
(with-current-buffer buffer
(eval-minibuffer "Eval: "))))
(insert (shell-quote-argument (format "%s" result)))))
You can't do that with M-!, but you can evaluate arbitrary elisp from the minibuffer, so writing a function isn't strictly necessary:
M-: (shell-command (format "p4 edit %s" (shell-quote-argument buffer-file-name))) RET
In this case however, I think eshell is what you want to use:
M-x eshell-command RET p4 edit (eval buffer-file-name) RET
Edit: Except unfortunately that doesn't work, as the *eshell cmd* buffer is selected when that is evaluated. One solution would be:
M-x eshell-command RET p4 edit (eval buffer-file-name (other-buffer nil t)) RET
(Not quite as elegant, sorry.)
Everyone seems to be rolling their own version, so here's mine -- it will substitue the current filename or marked dired-files or current dired file wherever a % is in the shell command. It follows the same conventions as M-! so I bind it to that.
(defun my-shell-command (command &optional output-buffer error-buffer)
"Run a shell command with the current file (or marked dired files).
In the shell command, the file(s) will be substituted wherever a '%' is."
(interactive (list (read-from-minibuffer "Shell command: "
nil nil nil 'shell-command-history)
current-prefix-arg
shell-command-default-error-buffer))
(cond ((buffer-file-name)
(setq command (replace-regexp-in-string "%" (buffer-file-name) command nil t)))
((and (equal major-mode 'dired-mode) (save-excursion (dired-move-to-filename)))
(setq command (replace-regexp-in-string "%" (mapconcat 'identity (dired-get-marked-files) " ") command nil t))))
(shell-command command output-buffer error-buffer))

Is there a way to get emacs tag-search command to output all results to a buffer?

Is there a way to get Emacs tags-search command to collect all search results in a buffer? Something like the way results from 'grep' and 'tags-apropos' are collected in a compilation buffer?
Using M-, to iterate over the results isn't very effective if there are a large number of hits, so it'd be great if there was a way to browse and search through the results in a buffer.
Thanks,
Benj
Try etags-select
I misinterpreted your question in my first answer. Here's something that works, but is kind of bad in that it uses synchronous calls to grep so everything blocks while it's working. Improvements are left as an exercise to the reader:
(require 'etags)
(require 'grep)
(defun tags-search-sel (regexp)
"Search through all files listed in tags table for match for REGEXP.
Show all matches at once."
(interactive "sTags search (regexp): ")
;; Get all unique filenames in TAGS files.
(let ((keep-going t) files)
(when (visit-tags-table-buffer)
(while keep-going
(save-excursion
(goto-char (point-min))
(while (re-search-forward "\f\n\\([^\n]+\\),[0-9]*\n" nil t)
(add-to-list 'files
(expand-file-name
(buffer-substring (match-beginning 1) (match-end 1))
(file-truename default-directory)))))
(setq keep-going (visit-tags-table-buffer t))))
;; grep through every file for regexp
(when files
(grep-compute-defaults)
(let ((outbuf (get-buffer-create "*tags-search-sel*")))
(with-current-buffer outbuf
(setq buffer-read-only nil)
(erase-buffer)
(insert "Searching for '" regexp "' in tags files ...\n\n")
(dolist (file files)
(call-process-shell-command (concat grep-command regexp " " file) nil t))
(grep-mode)
(setq overlay-arrow-position nil)
(set-buffer-modified-p nil)
(setq buffer-read-only t)
(goto-char (point-min)))
(pop-to-buffer outbuf)))))
See icicle-tags-search. It lets you search all source files listed in tags tables for matches for a given regexp.
You see all matches of the regexp in the source-code files, as search hits to visit. All tags in a given tags file are used, including duplicate tags from the same or different source files.
By default, all tags files are used, but if you provide a prefix
argument then only the current tag table is used.
Search for matches, with completion, cycling, and search-hit replacement.
After specifying the regexp that defines the search contexts, type
input (e.g. regexp or other pattern) to match within the contexts.
The contexts that match your input are available as completion
candidates. You can use S-SPC to further narrow the candidates,
typing additional patterns to match.
By default, candidates are in order of buffer occurrence, but you can
sort them in various ways using C-,.
You can alternatively choose to search, not the search contexts as
defined by the context regexp you provide, but the non-contexts, that
is, the text in the files that does not match the regexp. To do this,
use C-M-~ during completion. (This is a toggle, and it affects only
future search commands, not the current one.)
See the doc for command icicle-search for more information.

Unable to search effectively in Emacs

I want to have a similar tool in Emacs as the following in Vim
:g/search/
to get a list of matches.
How can you get a list of matches in Emacs?
M-x occur?
From the manual:
M-x occur
Prompt for a regexp, and display a list showing each line in the buffer that contains a match for it. The text that matched is highlighted using the match face. To limit the search to part of the buffer, narrow to that part (see Narrowing). A numeric argument n specifies that n lines of context are to be displayed before and after each matching line. The default number of context lines is specified by the variable list-matching-lines-default-context-lines.
In the *Occur* buffer, you can click on each entry, or move point there and type RET, to visit the corresponding position in the buffer that was searched. o and C-o display the match in another window; C-o does not select it. Alternatively, you can use the C-x ` (next-error) command to visit the occurrences one by one (see Compilation Mode).
Typing e in the *Occur* buffer switches to Occur Edit mode, in which edits made to the entries are also applied to the text in the originating buffer. Type C-c C-c to return to Occur mode.
The command M-x list-matching-lines is a synonym for M-x occur.
In addition to M-x occurr check also M-x grep. This works in several files at once.
My usual workflow is not to get a list and choose (don't know how to do that), but to use the incremental search:
C-s <search target>
gets the fist match after the point. If you don't like it another C-s gets the next one. Continue until you're happy (you'll need an extra C-s to wrap around from the and of the buffer). New enough emacsen can also highlight all the matches that are visible.
As noted in the comments by Török Gábor, this is the typical keybinding of isearch-forward. In the event that your bindings are different, you need to modify the prescribed procedure.

How can I operate on more Emacs buffers at the same time?

I am looking for an equivalent of the :bufdo Vim command in Emacs. :bufdo takes an argument - another command - and executes the command on all open buffers. I have not yet found a similar feature in Emacs.
Depending on what your command is, you can do:
M-: (mapc (lambda (b) (set-buffer b) (*command*)) (buffer-list))
But, I have a feeling you want something not so lispy. Take a look at keyboard macros. Namely, decide what you want to do:
C-x ( <do-your-command> C-x )
M-: (mapc (lambda (b) (set-buffer b) (kmacro-end-and-call-macro)) (buffer-list))
You'd probably want to define that last part as a function if you use it much:
(defun bufdo ()
"execute last macro on all buffers, ala bufdo from vi"
(interactive)
(mapc (lambda (b)
(with-current-buffer b
(kmacro-end-and-call-macro)))
(buffer-list)))
Note: code is untested
You can also checkout ibuffer, it allows you to mark buffers you like to operate on with m and then you can execute something on it with E. Other common operations are also available, e.g. query-replace on Q. Just check out the menu or the mode description (C-h m).
BTW, similar things are also possible from dired, although it doesn't seem to give you an eval command.
Take a look at buffer-list (function). It returns a list of all the open buffers (BUFFER objects). See the manual for a simple example of using it with mapcar (which operates on every element of the list, and accumulates the results). You would probably also find set-buffer, which programatically sets the current buffer from Emacs Lisp, useful.

Searching for marked (selected) text in Emacs

I use emacs for viewing and editing code and other text files. I wanted to know if there is a way to search forward or backward for text which is marked in the current buffer. Similar to what I can do in notepad or wordpad. As in can I mark some text in the buffer and do a C-s or C-r and be able to search with the marked text without actually typing in the whole search text?
Thank you,
Rohit
#Alex nails it.
Another option I use quite often is C-s C-w to search for the word after the current mark. Hitting C-w repeatedly increases the search with additional words (e.g., C-s C-w C-w C-w searches for the 3 words after the current mark).
Similarly, C-s M-s C-e searches for the rest of the line after the current mark and C-s C-M-y searches for the character after the mark. These are both repeatable in the same way (the former by somewhat-awkwardly repeating M-s C-e after C-s).
Yes. M-W (to get a copy of the selected text) C-s <RET> C-y <RET>. Then repeat C-s as needed. Similarly for C-r.
I am using the following which does not have the problem of having to type more then one successive C-s to find later occurences:
(defun search-selection (beg end)
"search for selected text"
(interactive "r")
(kill-ring-save beg end)
(isearch-mode t nil nil nil)
(isearch-yank-pop)
)
(define-key global-map (kbd "<C-f3>") 'search-selection)
The disadvantage of the previous code is that the selected text is copied to the stretch. The following code does not have this problem:
(defun search-selection (beg end)
"search for selected text"
(interactive "r")
(let (
(selection (buffer-substring-no-properties beg end))
)
(deactivate-mark)
(isearch-mode t nil nil nil)
(isearch-yank-string selection)
)
)
(define-key global-map (kbd "<C-f3>") 'search-selection)
Other answers describe how to search for copied text, or how to search for the word at point. But none of them actually describe how to "search with the marked text."
Adding the following hook will make it so that the currently-selected text is the text used for an isearch:
(defun jrh-isearch-with-region ()
"Use region as the isearch text."
(when mark-active
(let ((region (funcall region-extract-function nil)))
(deactivate-mark)
(isearch-push-state)
(isearch-yank-string region))))
(add-hook 'isearch-mode-hook #'jrh-isearch-with-region)
Tip: This pairs nicely with expand-region.
The shortest key sequence to do this is M-w C-s M-y.
There is a great function for this: isearch-forward-symbol-at-point. It highlights all occurrences of the word where your point is located - no need to place the point at the beginning of the word. Then you can move to next or previous with C-s or C-r.
Note that it is an exact match: if you use it on hi it won't match chill for instance.
I mapped if to command-f (mac OSX): (global-set-key (kbd "s-f") 'isearch-forward-symbol-at-point) in the init file.
The answers above (including the accepted one) are too cumbersome IMHO. I found the following info and like it well better:
“Ctrl+s Ctrl+w”. This will search the current word, but you must move
your cursor to the beginning of the word first.
http://xah-forum.blogspot.com/2009/08/search-word-under-cursor-in-emacs.html
You can find C-s help by doing C-h k C-s, and it says:
Type DEL to cancel last input item from end of search string. Type RET
to exit, leaving point at location found. Type LFD (C-j) to match end
of line. Type C-s to search again forward, C-r to search again
backward. Type C-w to yank next word or character in buffer onto the
end of the search string, and search for it. Type C-M-w to delete
character from end of search string. Type C-M-y to yank char from
buffer onto end of search string and search for it. Type M-s C-e to
yank rest of line onto end of search string and search for it. Type
C-y to yank the last string of killed text. Type M-y to replace string
just yanked into search prompt with string killed before it. Type C-q
to quote control character to search for it. Type C-x 8 RET to add a
character to search by Unicode name, with completion. C-g while
searching or when search has failed cancels input back to what has
been found successfully. C-g when search is successful aborts and
moves point to starting point.
If you try to exit with the search string still empty, it invokes
nonincremental search.
Type M-c to toggle search case-sensitivity. Type M-s i to toggle
search in invisible text. Type M-r to toggle regular-expression mode.
Type M-s w to toggle word mode. Type M-s _ to toggle symbol mode. Type
M-s ' to toggle character folding.
Type M-s SPC to toggle whitespace matching. In incremental searches, a
space or spaces normally matches any whitespace defined by the
variable ‘search-whitespace-regexp’; see also the variables
‘isearch-lax-whitespace’ and ‘isearch-regexp-lax-whitespace’.
Type M-s e to edit the search string in the minibuffer.
Also supported is a search ring of the previous 16 search strings.
Type M-n to search for the next item in the search ring. Type M-p to
search for the previous item in the search ring. Type C-M-i to
complete the search string using the search ring.
Type M-% to run ‘query-replace’ with string to replace from last
search string. Type C-M-% to run ‘query-replace-regexp’ with the last
search string. Type M-s o to run ‘occur’ that shows the last search
string. Type M-s h r to run ‘highlight-regexp’ that highlights the
last search string.
Type C-h b to display all Isearch key bindings. Type C-h k to display
documentation of Isearch key. Type C-h m to display documentation of
Isearch mode.
Adopted Jackson's Answer for Swiper:
(defun swiper-isearch-selected ()
"Use region as the isearch text."
(interactive)
(if mark-active
(swiper-isearch (funcall region-extract-function nil))
(swiper-isearch)))
Additionally, if there is no selected region, it just falls back to the regular swiper-isearch.

Resources