31

I'm aware of find-grep-dired, marking the corresponding files and then pressing Q to run dired-do-query-replace-regexp on the marked files. Unfortunately that requires restarting the grep and no longer using git-grep, ack, or ag and switching to use find-grep which has a different syntax for searching.

I'm also aware of multi-occur and occur-edit-mode, but that requires restarting the search using occur. Finally, ag-dired appears to match on the filename, not on the contents of the file.

My current approach is to generate grep output, and then run a macro that starts in the grep buffer, and visits each match and changes it. I would prefer to use query-replace directly over the set of matches found.

What I would like to do is to either quickly build a dired buffer from existing grep output so that I can mark the appropriate files and call query-regexp on them, or transform grep output into a list of buffers for multi-occur so that I can use occur-edit-mode to edit it in place and run query-replace on that buffer.

Does this functionality exist, or is there another workflow that solves this problem?

28

@Malabarba mentioned the use of wgrep package for editing grep/ack/ag results.

I would like to write a detailed walk-through of how I use the ag package and wgrep-ag packages to achieve editing of 'ag'ged results using multiple-cursors package.

These packages are available through Melpa. You also need to have ag aka the_silver_searcher installed on your system.

This walk-through applies to cases where you are looking for a way to do single line edits at all/selected locations that ag found.

  • Install ag on your system and the above mentioned emacs packages.

  • ag supports searching files with contents that match your specified regex. The simplest way to tell ag where the project root is to put an empty .git folder there. Then do the search using M-x ag-project-regexp.

  • The results buffer of ag search is not editable by default. To make it editable, do M-x wgrep-change-to-wgrep-mode or use the wgrep-default binding C-c C-p.

  • Now if you needed to change 'abcdef' to 'ghijkl' in all your files, you'd search for 'abcdef' and the ag results buffer will display all lines containing that string. Then you make that buffer editable and change those strings manually and those changes will reflect in the actual file buffers on doing M-x wgrep-finish-edit or using the default binding C-c C-e. You can also use query-replace-regexp to do that search replace.

  • I prefer using multiple-cursors for fast refactoring so that I can see a real time feedback of where my multiple edits are happening simultaneously. Highlight the string you want to replace in that ag results buffer and call M-x mc/mark-all-like-this and then edit away in awe as you see stuff getting edited at multiple points at the same time.

  • Once you are happy with the edits, as I mentioned above, do C-c C-e to "reflect" the changes in the actual buffers. The buffers are not saved yet.

  • To save all the buffers, I usually do that in one go, using the emacs default C-x s ! binding.

Here is an example use case with screenshots:

It shows the process of replacing all the instances of bind-to-modi-map to bind-to-my-map in my ~/.emacs.d/.

When I search for bind-to-modi-map in my emacs setup folder, I get the below 'ag'ged result: ag results, unmodified

This buffer is read-only.

After M-x wgrep-change-to-wgrep-mode, I highlight, -modi-map, select all instances of that selection using M-x mc/mark-all-like-this and after editing those selections to -my-map, it looks as below: ag results, modified using multiple-cursors

The blue highlight shows which lines will be modified when I press C-c C-e.

On hitting C-c C-e, you can see the change reflected in the actual file in this screenshot: ag results, after finishing the edits

I would then save all the modified files using C-x s !.

  • This is really the best way to do string replace. Contained to a project, minding ag-exclude, easy to do batch, still being able to verify you're replacing the correct thing. – PascalVKooten Nov 23 '16 at 8:29
13

What I would like to do is to either quickly build a dired buffer from existing grep output [...], or transform grep output into a list of buffers for multi-occur [...].

You don't need to convert the grep results buffer into anything, there's already a mode specifically for editing grep output (and reflecting the changes on the files, of course).

  1. Install the wgrep package from Melpa.
  2. (require 'wgrep) in your init file.
  3. After doing a grep search, hit C-c C-p and edit away!
  4. Save your edits with C-c C-e

It even works with ack and ag as well.

  • 2
    That's what I do (with ag.el). Together with magnars multicursor editing simple refactorings are really easy. – Tom Regner Sep 25 '14 at 7:21
4

This functionality exists within projectile (projectile-replace). It will use ag/ack/git grep/grep if available (in that order) to find occurrences, and tags-query-replace to execute the query-replace.

  • That suffers from the same issues as find-grep-dired. It's not using the existing grep output. There are similar problems with projectile-multi-occur. I would prefer to start the query replace after looking at the list of matches and not change the method of the underlying search. It is an alternate workflow though. – dgtized Sep 24 '14 at 20:53
  • What you're describing sounds like it can easily be accomplished by making a very quick macro to replace the text and repeatedly calling M-g n C-x e (i.e., use next-error to scroll through occurrences). – shosti Sep 24 '14 at 20:55
1

Here is another approach, using Icicles.

In your Emacs *grep* output buffer, hit C-c ` (that's C-c backquote), which in Icicle mode is bound in buffer *grep* to command icicle-compilation-search. This lets you quickly navigate among any of the search hits (the grep hits) you choose, in any order.

Input you type in the minibuffer dynamically filters (narrows) the set of search hits, and you can use progressive completion to narrow by successively matching multiple patterns (e.g. substrings, regexps).

When navigating among search hits you can replace any of them on demand - either the entire hit (line) or just the part matching your current minibuffer input.

See Icicles Search - Compile or Grep. An intro to Icicles search is here, and info about replacing matches during Icicles search is here.

0

I use this util I wrote xah_find.el

I wrote it because:

  • Pure elisp. No more worry about grep on Windows or Unicode transmission between emacs to Operating System. emacs grep problem
  • If you are heavy unicode user, the unix tools has some semi-bugs. linux uniq problem
  • I do find/replace every week on 5k files. I was using dired-do-query-replace-regexp for years. I find the interactive nature really zapped my time, yet I do need to check results of the changes. So, my solution is now run batch but have a nice report that I can scan at all find/replace results, with option to write to file.

This elisp util is perhaps 5 to 10 times slower than calling unix grep in emacs, but worked ok for me.

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.