(or emacs irrelevant)

New feature in Ivy - ivy-occur

I've had an idea with this feature for quite some time, and only recently got to finally implement it. So here it goes: with ivy-occur, bound to C-c C-o while in the minibuffer, you can store almost Ivy any completion session in progress, and you can have as many of them as you like.

Example 1

This is where the command name originates from: swiper + ivy-occur = occur. You can store all of swiper's matching lines into a separate buffer. This doesn't give too much advantage over the good-old occur, the only thing is that you can use ivy-style regexps with wild spaces, and have an interactive preview beforehand. Having said that, it actually sounds pretty good!

Example 2

I press C-S-o, bound to counsel-rhythmbox, and enter u2. After pressing C-c C-o, bound to ivy-occur, the completion session is closed (effectively C-g), and a new buffer *ivy-occur counsel-rhythmbox "u2"* is generated with all songs that match u2.

As a reminder, counsel-rhythmbox has two actions: play (the default) and enqueue. In this new buffer, pressing RET or mouse-1 will call the play action (since it was active at the moment ivy-occur was called) for the current candidate. So I've effectively added a playlist functionality to counsel-rhythmbox through a generic command.

Note that it's very easy to identify a completion session by the command name and input. So I can distinguish e.g. *ivy-occur counsel-rhythmbox "u2"* and *ivy-occur counsel-rhythmbox "ัะบั€ั"*, and quickly select them with ivy-switch-buffer: just input rhy, usually only these two and similar buffers will match.

Example 3

Suppose I want to go through the documentation of all variables that end in -function. Easy:

  1. <f1> v (counsel-describe-variable) with input function$.
  2. C-c C-o (ivy-occur).

I get a new buffer named *ivy-occur cousnel-describe-variable "function$*" with 346 candidates. I can go through them at my own pace, possibly doing other completion stuff in between without disturbing my process. It's also convenient to navigate these buffers with swiper.

Example 4

Let's tweak the previous one. After inputting function$ I can press C-M-a (ivy-read-action) followed by d to select the definition action. Then again C-c C-o (ivy-occur). Pressing RET in the resulting buffer will take me to that variable's definition, instead of describing it as before. A similar thing could be done for counsel-rhythmbox to get the enqueue action in *ivy-occur* buffer, instead of play.

Example 5

This is an improvement to my workflow for quickly looking at a new package's features. This can be done with oge (lispy-goto-elisp-commands) from lispy, which scans the source for (interactive) tags and allows to jump to their definition.

It's a pretty cool optimization, compared to looking at all tags. For example, projectile currently has 375 top-level tags (functions and variables). But with lispy-goto-elisp-commands I only get 48 tags. And now I can have them in a convenient permanent list too.

ivy-occur-1.png

Alternatively, if projectile is already loaded, I can use counsel-M-x with input projectile-, followed by C-M-a d to select the definition action, followed by C-c C-o.

As a reminder of how it works, counsel-M-x is defined with a single action that calls the selected command. But then, I've also added this statement at top-level of counsel.el:

(ivy-set-actions
 'counsel-M-x
 '(("d" counsel--find-symbol "definition")))

This means that you can add as many actions as you like to ivy-read commands. And of course customize the binding and the hint, which are in this case d and definition respectively.

Limitations

Unfortunately, since the *ivy-occur* buffer needs to know the action to execute, it only works for commands that explicitly pass :action to ivy-read. For instance, it won't work for package-install with ivy-mode on: the buffer will be properly generated, but pressing RET won't install a package.

Fortunately, it's not hard to write a version that works:

(defun counsel-package-install ()
  (interactive)
  (ivy-read "Install package: "
            (delq nil
                  (mapcar (lambda (elt)
                            (unless (package-installed-p (car elt))
                              (symbol-name (car elt))))
                          package-archive-contents))
            :action (lambda (x)
                      (package-install (intern x)))
            :caller 'counsel-package-install))

Here's a buffer with a list of packages matching "ga"; pressing RET will install the selected package:

ivy-occur-2.png

Small note on key bindings

In the initial post, I wanted to bind ivy-occur to C-c o instead of C-c C-o. But I was reminded that C-c LETTER are reserved. I still think it's a better binding. If you agree, you can add it to your config:

(define-key ivy-minibuffer-map (kbd "C-c o") 'ivy-occur)

Additionally, ivy-occur is also available on C-o u, through the C-o hydra.

Outro

I think ivy-occur is a very powerful command that shouldn't be overlooked. Just as ivy-resume implements a sort of DEL or C-u key for completion, ivy-occur implements a convenient way to switch and store the completion context, a sort of C-x o or C-x b for completion.