12 Feb 2015
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.
11 Feb 2015
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.
10 Feb 2015
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.
09 Feb 2015
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:

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.
08 Feb 2015
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.