(or emacs irrelevant)

New video demo - counsel-load-theme

Without further ado, here's the video link.

The code

(defun counsel--load-theme-action (x)
  "Disable current themes and load theme X."
  (condition-case nil
      (progn
        (mapc #'disable-theme custom-enabled-themes)
        (load-theme (intern x))
        (when (fboundp 'powerline-reset)
          (powerline-reset)))
    (error "Problem loading theme %s" x)))

;;;###autoload
(defun counsel-load-theme ()
  "Forward to `load-theme'.
Usable with `ivy-resume', `ivy-next-line-and-call' and
`ivy-previous-line-and-call'."
  (interactive)
  (ivy-read "Load custom theme: "
            (mapcar 'symbol-name
                    (custom-available-themes))
            :action #'counsel--load-theme-action))

It looks almost trivial, the main idea is to disable all current themes and load the new one. Additionally, try to reset the powerline, since it has to match the mode-line face, which most themes customize.

The Interface

The interface of ivy-read is the same as the built-in completing-read in first two arguments. The difference is that it also accepts a callback through the :action argument. This callback will make the completion engine aware of what needs to be done with the completion result. The presence of the callback allows these completion engine features to work:

  • ivy-resume will resume the last completion. Very useful if you change your mind on the candidate, or want to examine a related candidate.
  • ivy-next-line-and-call selects the next matching candidate and executes the callback for it.
  • ivy-previous-line-and-call selects the previous matching candidate and executes the callback for it.

I like to think of ivy-resume as a DEL or <left> for completion. As you can erase or go back one character with the same DEL binding, regardless of the last character inputted (a or B etc), in the same way you can call the completion again with the same <f6> binding, regardless of the command that required completion (counsel-git-grep or counsel-load-theme or counsel-load-library etc). ivy-resume isn't bound by default, since it needs to be a global binding. I just use this in my config:

(global-set-key [f6] 'ivy-resume)

For the functions that execute the callback while changing the candidate, the idea is:

  • C-M-n (ivy-next-line-and-call) corresponds to C-n (ivy-next-line),
  • C-M-p (ivy-previous-line-and-call) corresponds to C-n (ivy-previous-line).

I've also showed off a generic ivy feature: M-j will yank the word at point into the minibuffer. Think of it as the mirror of C-w in isearch. It could not be C-w, since I like C-w being bound to kill-region.

The command/insert mode split

counsel-load-theme.png

Finally, I show off the equivalent hydra-based modal selection method. So instead of pressing C-M-n C-M-n C-M-n C-M-p C-M-p, you can press the equivalent C-o c jjjkk. Luckily, you don't need to remember a lot of bindings for this hydra mode: just press C-o and read the hints. I'll just list the exit points, since that's usually the more important stuff:

  • To exit the "command-mode" completely, press o or the standard C-g.
  • To exit the "command-mode" with the current candidate, press f or d.
  • To exit the "command-mode" and once again edit the minibuffer, press i.

You might ask why f and d do the same. They actually mirror C-j (ivy-alt-done) and C-m (ivy-done). And if you ask what the difference between those two is, the answer is that ivy-alt-done will not exit the completion when selecting directories during file name completion. It may be possible to extend this to other types of completion where it makes sense to select something but not to exit the minibuffer.

Outro

If you're using ivy-mode, make sure to try the new features: the action-using commands should work for any command that starts with counsel-. For other commands, like package-install, you can only select one candidate with C-m.

Also do try C-M-n with counsel-find-file: you'll be able to cycle through all files in a directory without exiting the completion. Same goes for ivy-switch-buffer, which should probably be renamed to counsel-switch-buffer for consistency.