5

I often find myself in the situation of needing to open a bunch of files at the same time and run through them all and do something (search/replace, verify something or other, etc.). In vim, I'd do this by populating the arglist (blog post on VimCasts for people who aren't familiar).

It's essentially a subset of the buffer list that maintains its order. Vim provides commands for navigating through this list; once the list is populated, you can step through it with :next and do the edits. Vim tells you when you've hit the end of the list, and if you try to quit before you've edited them all it will gripe at you.

Is there any way to get Emacs to emulate this feature?

Michael M.
  • 195
  • 4
  • Related 1: [How do I search and replace over a set of files?](http://emacs.stackexchange.com/q/9495/115) – Kaushal Modi Sep 29 '15 at 02:22
  • Related 2: [How can I run a keyboard macro in selected buffers from Ibuffer or selected files from dired?](http://emacs.stackexchange.com/q/4150/115) – Kaushal Modi Sep 29 '15 at 02:23
  • I knew about searching/replacing in multiple files, but often I just want to run through a bunch of files for reading/editing, and don't want to forget any, which is why the arglist is so useful in vim. – Michael M. Sep 29 '15 at 13:33
  • I'm almost sure Icicles could do that. – mbork Oct 17 '15 at 18:00
  • Somewhat related : find-file accepts wildcards and opens all matching files. – YoungFrog Oct 17 '15 at 20:38

1 Answers1

2

Disclaimer: I didn't have time to learn all about the Vim arglist feature, so I don't know if this is really in the full spirit of what it does and what you want. But forging ahead anyway:

  1. Based on the assumption that people keep Emacs running (as opposed to frequently starting and exiting it) it would be nice to have an Emacs command that asks you for the pathnames (as opposed to supplying them as command-line arguments to Emacs).

  2. Emacs has a compilation mode that can find pathnames/positions in a buffer, and visit them using next-error and previous-error.

Given that, the question is how to get the "arglist" into some buffer, and enable the compilation "machinery" for it.

Below is one way to do it, which is closest to how you would supply command-line arguments, for example as a.txt b.txt *.c ../foo.*

(defun my/vim-arglist ()
  "Easily visit a group of files.

Prompts you to enter one or more pathnames, each of which can use
wildcards. Puts the actual, expanded pathnames one per line in a
*files* buffer with `compilation-minor-mode' enabled. Reminds you
to use `next-error' and `previous-error' to visit the files."
  (interactive)
  (let* ((prompt (format "Files (%s): " default-directory))
         (wildcards (split-string (read-from-minibuffer prompt)))
         (filess (mapcar (lambda (x) (file-expand-wildcards x t))
                         wildcards))
         (files (apply #'append filess))
         (buffer-name "*files*"))
    (when (get-buffer buffer-name)
      (kill-buffer buffer-name))
    (with-current-buffer (get-buffer-create buffer-name)
      (compilation-setup t)
      (insert "Files:\n")
      (dolist (file files) (insert file) (insert ":1:0\n")))
    (message "Use next-error and previous-error to move among the files")))

You may also want to check out the rgrep command. Its *grep* results buffer also supports the compilation mode style of navigating using next-error etc. The catch is what to supply as the search pattern -- because you really want just one "match" per file. If all the files have some unique line of boilerplate like a copyright or a language element, you could use that; otherwise I don't know.

Greg Hendershott
  • 1,483
  • 12
  • 17
  • With a prefix arguement, `rgrep` allows editing the shell command to run so you can add `--max--count=1` to only get one match per file. – npostavs Oct 05 '15 at 04:04
  • 1
    @npostavs Good point. As a tip for people trying this for the first time: The command is _extremely_ long. 1. You can't simply append this argument to the end where point is in the minibuffer. Instead it needs to go _before_ the `-e` near the end. 2. You can use `-m 1`. **Example** Edit `find -exec grep -i --color -nH -e . {} +` to `find -exec grep -i --color -nH -m 1 -e . {} +`. – Greg Hendershott Oct 05 '15 at 14:29
  • This is pretty good! It's not exactly the same, but it gives me something to start hacking from. – Michael M. Oct 11 '15 at 15:07