New feature in Ivy - ivy-occur
04 Nov 2015I'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:
- <f1> v (
counsel-describe-variable
) with inputfunction$
. - 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.
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:
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.