(or emacs irrelevant)

Occasionally ido

As I was refactoring my .emacs, I found a silly wrapper around describe-function that uses ido-completing-read. I think I was aware at the time that ido-ubiquitous could simply make describe-function use ido-completing-read. The problem was that it also affected the completing-read in functions that became headlong-bookmark-jump from headlong (see the corresponding post if you missed it).

A bit of code to make things right

(defun ido-occasional-completing-read
    (prompt collection
     &optional predicate require-match initial-input
       hist def inherit-input-method)
  "Use `ido-completing-read' if the collection isn't too large.
Fall back to `completing-read' otherwise."
  (let ((filtered-collection
         (all-completions "" collection predicate)))
    (if (<= (length filtered-collection) 30000)
        (ido-completing-read
         prompt filtered-collection nil
         require-match initial-input hist
         def nil)
      (completing-read
       prompt collection predicate
       require-match initial-input hist
       def inherit-input-method))))

;;;###autoload
(defmacro with-ido-completion (fun)
  "Wrap FUN in another interactive function with ido completion."
  `(defun ,(intern (concat (symbol-name fun) "/with-ido")) ()
     ,(format "Forward to `%S' with ido completion." fun)
     (interactive)
     (let ((completing-read-function
            'ido-occasional-completing-read))
       (call-interactively #',fun))))

The only thing that ido-occasional-completing-read does is to pre-filter collection with predicate and pass it on to ido-completing-read. And with-ido-completion is just a convenience wrapper.

Example

(global-set-key (kbd "<f1> f")
                (with-ido-completion describe-function))
(global-set-key (kbd "<f1> v")
                (with-ido-completion describe-variable))
(global-set-key (kbd "<f2> i")
                (with-ido-completion info-lookup-symbol))

Here, with-ido-completion will generate e.g. describe-function/with-ido, which will subsequently be bound to <f1> f. The good-old describe-function is left unaffected.

Note, that if I turn on helm-mode at this point, it will override describe-function with its own completion, but it will not touch describe-function/with-ido which I bound. This can be useful e.g. if I want to use helm-mode (or icy-mode or icomplete-mode) for some completion, but not all.

You can find the package at ido-occasional.

Elisp newbie-style

I've been cleaning up my .emacs lately, with the intention to put my whole config on Github. Today, I'll show you a useful function for describing the current buffer's key bindings. The function will generate something like this (with all letters, of course):

;; (global-set-key (kbd "a") 'self-insert-command)
;; ...
;; (global-set-key (kbd "C-b") 'backward-char)
;; ...
;; (global-set-key (kbd "M-c") 'subword-capitalize)
;; ...
;; (global-set-key (kbd "C-M-d") 'down-list)
;; ...
;; (global-set-key (kbd "η") 'save-and-switch-buffer)
;; ...
;; (global-set-key (kbd "C-θ") 'ins-single-quotes)
;; ...
;; (global-set-key (kbd "M-ι") 'nil)
;; ...
;; (global-set-key (kbd "C-M-κ") 'nil)

First, I'll show you how I wrote it down as a newbie, and then today's corrections with some remarks.

Old style

Please don't try this at home:

;;;###autoload
(defun keys-latin ()
  (loop for c from ?a to ?z
     collect (string c)))

;;;###autoload
(defun keys-greek ()
  (loop for c from  to 
     collect (string c)))

(require 'dash)
;;;###autoload
(defun keys-describe-prefix (letters prefix)
  (->> letters
    (mapcar (lambda (letter) (concat prefix letter)))
    (mapcar (lambda (key)
              (cons key
                    (prin1-to-string (key-binding (kbd key))))))
    (mapcar (lambda (binding)
              (concat
               ";; (global-set-key (kbd \""
               (car binding)
               "\") '"
               (cdr binding)
               ")\n")))
    (apply #'concat)))

;;;###autoload
(defun keys-describe-prefixes ()
  (interactive)
  (with-output-to-temp-buffer "*Bindings*"
    (mapcar
     (lambda (f-letters)
       (mapcar (lambda (prefix)
                 (princ (keys-describe-prefix f-letters prefix))
                 (princ "\n\n"))
               '("" "C-" "M-" "C-M-")))
     (list (keys-latin) (keys-greek)))))

Corrections

Redundant autoloads

Since the entry point of the whole thing is keys-describe-prefixes, only it needs to be autoloaded. Once an autoloaded function is called, it will load the whole buffer. So if e.g. keys-latin is not being used anywhere else outside this file, it doesn't need an autoload.

Redundant functions

keys-latin and keys-greek are actually very small and not used anywhere else. It might be better to just inline them into keys-describe-prefixes.

Redundant libraries

Here, dash is required just for the ->> macro, which can actually be obtained from a core library subr-x as thread-last.

But even then, it's just better to unwind the whole thing. After that, it becomes clear that the three consecutive mapcars could be folded into a single mapcar with the help of a let binding.

After the fold, it starts to look silly, since I'm consing just to take a car and cdr later:

(defun keys-describe-prefix (letters prefix)
  (apply #'concat
         (mapcar
          (lambda (letter)
            (let* ((key (concat prefix letter))
                   (binding
                    (cons key
                          (prin1-to-string
                           (key-binding (kbd key))))))
              (concat
               ";; (global-set-key (kbd \""
               (car binding)
               "\") '"
               (cdr binding)
               ")\n")))
          letters)))

Here's a simplification, removing binding:

(defun keys-describe-prefix (letters prefix)
  (apply #'concat
         (mapcar
          (lambda (letter)
            (let ((key (concat prefix letter)))
              (concat
               ";; (global-set-key (kbd \""
               key
               "\") '"
               (prin1-to-string
                (key-binding (kbd key)))
               ")\n")))
          letters)))

I guess that I didn't know about format function back then, and the fact that "%S" key is equivalent to prin1-to-string:

(defun keys-describe-prefix (letters prefix)
  (apply #'concat
         (mapcar
          (lambda (letter)
            (let ((key (concat prefix letter)))
              (format ";; (global-set-key (kbd \"%s\") '%S)\n"
                      key
                      (key-binding (kbd key)))))
          letters)))

Next, the combination (apply #'concat (mapcar ...)) is already implemented in C as mapconcat:

(defun keys-describe-prefix (letters prefix)
  (mapconcat
   (lambda (letter)
     (let ((key (concat prefix letter)))
       (format ";; (global-set-key (kbd \"%s\") '%S)"
               key
               (key-binding (kbd key)))))
   letters
   "\n"))

In the end, keys-describe-prefix turned out to be so small that I could just inline it into keys-describe-prefixes.

Final version

Note that here I also replaced mapcar with dolist:

;;;###autoload
(defun keys-describe-prefixes ()
  (interactive)
  (with-output-to-temp-buffer "*Bindings*"
    (dolist (letter-group (list
                           (cl-loop for c from ?a to ?z
                                    collect (string c))
                           (cl-loop for c from  to 
                                    collect (string c))))
      (dolist (prefix '("" "C-" "M-" "C-M-"))
        (princ (mapconcat
                (lambda (letter)
                  (let ((key (concat prefix letter)))
                    (format ";; (global-set-key (kbd \"%s\") '%S)"
                            key
                            (key-binding (kbd key)))))
                letter-group
                "\n"))
        (princ "\n\n")))))

I hope that this sort of analysis can be useful for people starting to learn Elisp. And if you have corrections for the final version, do let me know, I don't mind being schooled, as long as I get better in the end.

The output of keys-describe-prefixes can be used to learn some bindings that you didn't know about, and also as a template to redefine some bindings that you don't need.

Easy ido improvement

Heh, I guess I was so busy at work that I missed the opportunity to make an especially good post for the 50-post landmark. At least according to M-= (count-words-region) in my _posts' dired buffer, this is the 53rd post.

ido-backspace

This echoes to my very second post, easy helm improvement, which was about implementing a similar function for helm. So here it is:

(ido-mode)
(require 'delsel)
(defun ido-backspace ()
  "Forward to `backward-delete-char'.
On error (read-only), quit without selecting."
  (interactive)
  (condition-case nil
      (backward-delete-char 1)
    (error
     (minibuffer-keyboard-quit))))
(define-key ido-common-completion-map (kbd "DEL") 'ido-backspace)

With this setup, when e.g. calling ido-switch-buffer, you can cancel with DEL. This, of course, will also work for smex and some other packages that allow for ido completion:

(setq magit-completing-read-function #'magit-ido-completing-read)
(setq lispy-completion-method 'ido)

Note that the define-key part of the code takes an advantage of a recent patch to ido that's available in the trunk. You can find the old way of binding keys for ido in an earlier post, tilde in ido-find-file. That post actually played a small role in speeding up the patch, for which we should thank @tarsius.

Note that this behavior will not affect ido-find-file, since it has its own map.

ido-vertical - like ido, but vertical!

Intro

As I was releasing lispy 0.23.0, which added an option for methods of jumping to semantic tags other than helm, I've discovered ido-vertical-mode. I also made some changes to it, so now it looks like this:

lispy-ido-vertical

The changes are:

  • the current text is highlighted in all matches
  • the current number of total matches is displayed in the first line
  • I also customized the face for the first match and the only match (you can't see that one here)

Helm is still the big gun when it comes to completing lists with hundreds of candidates, but with the above changes, ido-vertical-mode comes close to what I need when jumping to tags. The only thing missing now is that the selected candidate is always on the first line, even when I press C-n, which isn't very intuitive.

Other completion methods available in lispy-goto

Depending on the modes you have enabled, you can complete with:

  • helm
  • ido
  • ido-vertical-mode
  • icomplete-mode
  • icy-mode
  • no mode, just plain completion

lispy-eval-other-window now uses ace-window

This function bound to p is very convenient for debugging Elisp: it allows you to eval the current sexp in the context of other window. This is very powerful: you can run and debug your function as you write it, statement by statement. Previously, this setup was viable only in a two-window split, because using other-window, it wasn't predictable in which window the eval would take place. Now, if there are more than two windows, aw-select will select the window for the eval. This selection will be remembered, so you don't have to select for the following evals, unless the window configuration changes.

Outro

There are more changes that you can find in the release notes if you're interested. You can find the new ido-vertical stuff in my fork, until it gets merged.

Hydra 0.9.0 is out

I'll just list the new features from the release notes here.

Keyboard quit

hydra-keyboard-quit set to "C-g" means that it's possible to quit an amaranth Hydra with C-g. You can customize this variable.

:pre and :post refinement

:post and :pre keys in the body PLIST can be either a single sexp or a function name. The function doesn't need to be interactive.

Support for local Hydra heads via :bind property

Example:

(defhydra hydra-next-error (global-map "C-x")
  "next-error"
  ("`" next-error "next")
  ("j" next-error "next" :bind nil)
  ("k" previous-error "previous" :bind nil))

What it does:

  • binds C-x ` to next-error.
  • does not bind C-x j and C-x k
  • you can still do C-x `jjkk

Thanks, @ffevotte.

Support for :bind property in Hydra body

The body, like the heads will recognize the :bind property in PLIST. The heads will inherit it, just like they do with :color. The :bind property can be nil or a lambda of global-set-key format.

Example:

(defhydra hydra-goto (global-map "M-g"
                      :bind
                      (lambda (key cmd)
                        (bind-key key cmd)))
  ("g" goto-line "goto-line" :bind global-set-key)
  ("c" goto-char "goto-char"))

Here, bind-key will be used to bind goto-char to M-g c, since c head has inherited body's :bind property. Note that since bind-key is a macro, it was necessary to wrap it in a lambda.

However, global-set-key will be used to bind goto-line to M-g g, this :bind property was overridden in the g head.

Since this commit, it's not possible to pass a lambda instead of the whole BODY argument, as was advertised before. Just put it on :bind now.

hydra/body will pass the initial current-prefix-arg along

Example:

(global-set-key
 (kbd "C-z")
 (defhydra hydra-vi ()
   "vi"
   ("l" forward-char)
   ("q" nil "quit")))

Now, C-u C-z l will result in (forward-char 4). All the other l will normally call (forward-char 1), unless an additional prefix is given. The previous behavior allowed only for C-z C-u l to get (forward-char 4).

Allow a sexp as head's CMD parameter

Example:

(defhydra hydra-launcher (:color blue)
   "Launch"
   ("h" man "man")
   ("r" (browse-url "http://www.reddit.com/r/emacs/") "reddit")
   ("w" (browse-url "http://www.emacswiki.org/") "emacswiki")
   ("s" shell "shell")
   ("q" nil "cancel"))
(global-set-key (kbd "C-c r") 'hydra-launcher/body)

Here, r and w heads are using this feature. Here's what will be generated, if you're interested:

(defun hydra-launcher/lambda-w nil
  "Create a hydra with no body and the heads:

\"h\":    `man',
\"r\":    `(browse-url \"http://www.reddit.com/r/emacs/\")',
\"w\":    `(browse-url \"http://www.emacswiki.org/\")',
\"s\":    `shell',
\"q\":    `nil'

The body can be accessed via `hydra-launcher/body'.

Call the head: `(browse-url \"http://www.emacswiki.org/\")'."
  (interactive)
  (hydra-disable)
  (catch (quote hydra-disable)
    (call-interactively
     (function
      (lambda nil
       (interactive)
       (browse-url "http://www.emacswiki.org/"))))))

Obsolete declarations

hydra-create and all old examples in hydra-examples.el are now obsolete. You can still use them for a short while, but they will be removed soon.

You should take the time to switch from hydra-create to defhydra. All the old examples are provided in the new style in hydra-examples.el. However, they will not be evaluated through (require 'hydra-examples) unless you (setq hydra-examples-verbatim t) beforehand. This is because I have no idea what kind of bindings will work for you, you should decide yourself. But I am providing you with a template. The number of examples has also grown to six.