(or emacs irrelevant)

Set an Emacs variable with double completion

I'd like to show off a certain Elisp productivity booster that I've had in an unfinished state for a while and finished just today.

A large part of tweaking Elisp is simply setting variables. The new command, counsel-set-variable, allows to set them quite a bit faster.

Completion stage 1:

First of all, you get completion for all variables that you have defined:

counsel-set-variable-1.png

Completion stage 2:

Once a symbol is selected, the code checks whether the symbol is a defcustom with type 'boolean or 'radio. Since then it is possible to offer all values that the symbol is allowed to become for completion.

For example, here's a typical 'radio-type definition:

(defcustom avy-style 'at-full
  "The default method of displaying the overlays.
Use `avy-styles-alist' to customize this per-command."
  :type '(choice
          (const :tag "Pre" pre)
          (const :tag "At" at)
          (const :tag "At Full" at-full)
          (const :tag "Post" post)
          (const :tag "De Bruijn" de-bruijn)))

And here's a completion screen offered for this variable:

counsel-set-variable-2.png

It is worth noting that the current value of the variable is pre-selected, to give a nice reference point for the new setting.

In case the symbol isn't a boolean or a radio

Then you get a completion session similar to M-x read-expression, but with the initial contents already filled in. For example:

counsel-set-variable-3.png

The read-expression part combines well with this setting in my config:

(defun conditionally-enable-lispy ()
  (when (eq this-command 'eval-expression)
    (lispy-mode 1)))

(add-hook
 'minibuffer-setup-hook
 'conditionally-enable-lispy)

Here's a series of commands using lispy-mode that I would typically use for the screenshot above, to set ivy-re-builders-alist to a new value:

  1. C-f (forward-char) to get into special.
  2. -e (lispy-ace-subword) to mark the plus part of the code.
  3. C-d (lispy-delete) to delete the active region.

After the C-f -e C-d chain of bindings, the minibuffer contents become:

(setq ivy-re-builders-alist '((t . ivy--regex-|)))

I press C-M-i (completion-at-point) to get completion for all symbols that start with ivy--regex-. Since I have ivy-mode on, C-M-i starts a recursive completion session. I highly recommend adding these settings to your config:

;; Allow to read from minibuffer while in minibuffer.
(setq enable-recursive-minibuffers t)

;; Show the minibuffer depth (when larger than 1)
(minibuffer-depth-indicate-mode 1)

Finally, I would e.g. select e.g. ivy--regex-fuzzy and RET RET to finalize the eval. The first RET exits from completion-at-point and the second RET exits from counsel-set-variable.

Outro

I think this command, especially the newly added read-expression part, is quite a bit faster than what I did before. That is switching to *scratch* and typing in the setq manually and evaluating with C-j. Here's my binding for the new command:

(global-set-key (kbd "<f2> j") 'counsel-set-variable)

It's not very mnemonic, but it's really fast. Just a suggestion, in case you don't know where to bind it. Happy hacking!