(or emacs irrelevant)

A simple multiple-cursors extension to swiper

When using Emacs, it happens sometimes that I accumulate too many buffers. The usual next action is to close the buffers for the project that I'm not currently working on. Previously, I marked those buffers in *Buffer List* by hand with d and C-n. Today, I'll show a faster way.

It's very easy to select these buffers in *Buffer List* with swiper: just type a part the shared directory name. Another example is to select all dired buffers: a "dired by" input will usually match all of them, since they all have Dired by name in their line.

Afterwards, I want to open multiple-cursors for each matched line. I've bound this action to C-7. Here's the very simple code:

(defun swiper-mc ()
  (interactive)
  (unless (require 'multiple-cursors nil t)
    (error "multiple-cursors isn't installed"))
  (let ((cands (nreverse ivy--old-cands)))
    (unless (string= ivy-text "")
      (ivy-set-action
       (lambda (_)
         (let (cand)
           (while (setq cand (pop cands))
             (swiper--action cand)
             (when cands
               (mc/create-fake-cursor-at-point))))
         (mc/maybe-multiple-cursors-mode)))
      (setq ivy-exit 'done)
      (exit-minibuffer))))

After C-7, here's the sequence to delete the selected buffers:

  • d (Buffer-menu-delete) to mark each item for deletion.
  • C-g (keyboard-quit) to exit multiple-cursors.
  • x (Buffer-menu-execute) to execute the deletions.

And that's it: all selected buffers are now deleted. To summarize, C-s dired by C-7 d C-g x will close all dired buffers from your *Buffer List*.

Other interesting applications are also possible, like mass renames in wdired, or un-commenting everything in a function. For example, suppose that you have this code:

(progn
  ;; (check-1)
  (foo)
  ;; (check-2)
  (bar)
  ;; (check-3)
  (baz))

If it's a part of a larger buffer, you can narrow with C-x nd (narrow-to-defun) or C-x nn (narrow-to-region). Then C-s ;; C-7 DEL DEL C-d C-g to remove all comments.

I have to say that the functionality intersects a bit with mc/mark-all-like-this. Except you know the result ahead of time (number and position of matches), and you can use a regex instead of a literal string.