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?

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.

  • 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 5 '15 at 4: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 <huge amount of stuff> -exec grep -i --color -nH -e . {} + to find <huge amount of stuff> -exec grep -i --color -nH -m 1 -e . {} +. – Greg Hendershott Oct 5 '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

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.