15 Mar 2015
Until recently, I didn't even know that apropos
was an actual word. I thought that it was just
some gibberish that Emacs hackers invented to name a command. Turns out, it actually has a very
appropriate meaning:
apropos
preposition
with reference to; concerning.
An apropos Hydra
I've just added this one to hydra-examples.el.
(defhydra hydra-apropos (:color blue
:hint nil)
"
_a_propos _c_ommand
_d_ocumentation _l_ibrary
_v_ariable _u_ser-option
^ ^ valu_e_"
("a" apropos)
("d" apropos-documentation)
("v" apropos-variable)
("c" apropos-command)
("l" apropos-library)
("u" apropos-user-option)
("e" apropos-value))
I recommend to bind it like this:
(global-set-key (kbd "C-c h") 'hydra-apropos/body)
Customary screenshot:

As you can see, there are a total of 7 apropos functions available. The most useful ones are
apropos
, apropos-command
and apropos-variable
. But apropos-value
is very interesting as
well: it will not match an object name with the input, but instead search for all objects whose
contents match input. So, for instance, if you see something like "error 42"
come up, and you
don't know where it's coming from, it's likely that some variable holds the value 42
. And that's
when you use apropos-variable
.
Apropos is like old-school googling, and I find it highly useful in finding the Emacs information
that I need. I hope that you will find it useful as well. Happy hacking!
14 Mar 2015
I'll describe two new things in swiper and ivy
that happened
within the day. Although you can install them separately from MELPA, they still live in a single git
repository.
swiper
/ ivy
faces now inherit the standard ones
It's a good idea by @purcell, and I tend to agree. So now, there are
six faces that inherit highlight
, isearch-lazy-highlight-face
, isearch
and match
faces
between them. The advantage is that most themes re-define the above four faces as they see fit, so
the swiper faces will fit in better without customization.
Still, I really enjoy the previous faces that were derived from the Swiper sprite. You can have them
as part of eclipse-theme. The theme creators can just
copy them verbatim to a light theme if they so choose.
By the way, it seems that not all Emacs users are aware that you can customize faces. You can do so
interactively for most popular packages. For example, after M-x customize-group
swiper
, you get a GUI for selecting most configurable things for swiper
, including the faces.
The GUI will generate the code that looks something like this:
(custom-set-faces
'(ivy-current-match ((t (:background "#e5b7c0")))))
Elisp completion with ivy
The code to complete Elisp code at point is very simple:
(defun counsel ()
"Elisp completion at point."
(interactive)
(let* ((bnd (bounds-of-thing-at-point 'symbol))
(str (buffer-substring-no-properties (car bnd) (cdr bnd)))
(candidates (all-completions str obarray))
(ivy-height 7)
(res (ivy-read (format "pattern (%s): " str)
candidates)))
(when (stringp res)
(delete-region (car bnd) (cdr bnd))
(insert res))))
The only function above that isn't one of the familiar primitives is ivy-read
. But even that one
has a similar interface to that of completing-read
or ido-completing-read
. I was using
helm-lisp-completion-at-point
before, but counsel
is much less obtrusive, while offering
comparable speed and convenience:

The default minibuffer height for ivy
is set to 10 via ivy-height
. It's quite reasonable all-around, but
for counsel
I've set it to 7 via a let binding.
13 Mar 2015
Intro
Just three days ago, I wrote swiper
and introduced it in
a post.
And while swiper
solved the problem of helm-swoop
being awkward for me to use, swiper
's code itself is pretty awkward, since even after using helm
a dozen times in my packages, I'm still not well-versed in its internals.
And, apparently, there are people who don't like helm
because it updates a lot. I don't know if
it counts as a viable complaint, but I do agree that the helm
update time is quite long. So I
wrote down an alternative completion back end for swiper
. It looks quite similar to
ido-vertical-mode
, although it is completely unrelated to ido
. In fact, the matching algorithm
currently is similar to helm-match-plugin
: "for example"
is transformed into
"\\(for\\).*\\(example\\)"
.

The Details
Currently, in the ivy
version of swiper
only the anchoring algorithm is missing. Anchoring is
what I call the process of selecting a close candidate when the number of candidates changes. It
seems that helm
doesn't implement an anchoring algorithm, so both helm-swoop
and swiper
implement their own. I don't know how easy it would be to write down the proper generic thing, my
current implementation for the helm
version of swiper
is quite hacky.
Just to explain to you what needs to be done. Suppose there's an input "ab" that matches 50
candidates, and the candidate number 42 is the current one. Now, if the user types one char to make
the input into "abc", the number of candidates has changed to 10, and the candidate that was current
previously doesn't match any more. It is up to the matcher code to decide which of the 10 candidates
has to be current now. Usually it doesn't matter much, but in the case of swiper
it matters since
the point will be moved to the current candidate in the original window.
In any case, there's still a lot of things that have to be done for ivy
, but I think that
it's quite usable now. Actually, I've already added it to my bindings:
(global-set-key "\C-s" 'swiper)
Here's how it looks like:

And here's an example of completion in dired
:

You need to have Emacs 24.4 in order to get a nicer highlight in the minibuffer that uses
add-face-text-property
instead of the old propertize
.
There's a custom variable that decides the height of the minibuffer window, you can set it as you
like:
(defcustom ivy-height 10
"Number of lines for the minibuffer window."
:type 'integer)
Outro
Give the new back end a go, see if you like it. It looks quite pretty and minimalist to me, but I'm
biased since I made it.
12 Mar 2015
Intro
Today, I'll describe a quite recent addition to ace-window,
which comes from the idea by @deftsp:
Why not show the ace-window
dispatch keys in the mode line all the time?
Certainly, there's no reason not to have this option, and it actually makes the whole interface
better, since it becomes less feedback-based:
- You glance at a window that you want.
- You know which key you have to press before you call
ace-window
- You make a single-step call instead of:
- press
ace-window
shortcut,
- read the dispatch char,
- press the dispatch char.
The feature is implemented as ace-window-display-mode
- a minor mode that you can toggle on or
off whenever you feel like it.
Here's how it looks like:

As you can see, I've made aw-keys
list short on purpose, just to show you that the full path
will be displayed. See, for instance, the *scratch*
window: its path is gf
.
Implementation
Since the implementation is quite short, I'll post it here and go over a few things that might
interest people who write Elisp (on some level, please don't mock me for being obvious).
As per request of a curious reader, I've updated the code with the comments from below. Don't try
this at home, excessive commenting is bad style.
;; Something that modifies the Emacs behavior should
;; preferrably be implemented as a minor mode.
;;;###autoload
(define-minor-mode ace-window-display-mode
"Minor mode for showing the ace window key in the mode line."
;; And since this minor mode isn't tied to a particular
;; buffer, I declare it as global.
;;
;; An interesting quirk is that I have to put *something*
;; between the docstring and the body, otherwise it won't
;; work.
:global t
;; Dispatch on the variable symbol of the mode -
;; `ace-window-display-mode`. `define-minor-mode' will
;; define both a variable and function symbol.
(if ace-window-display-mode
(progn
;; Update the window parameters
(aw-update)
;; Since `mode-line-format' is a buffer-local
;; variable, I set it with `set-default', in order
;; for the change to not just happen in the current
;; buffer.
(set-default
'mode-line-format
`((ace-window-display-mode
(:eval (window-parameter (selected-window)
'ace-window-path)))
,@(default-value 'mode-line-format)))
(force-mode-line-update t)
;; Each time a window is created or deleted, Emacs
;; will run the `window-configuration-change-hook' -
;; exactly what I need to update `mode-line-format'.
(add-hook 'window-configuration-change-hook 'aw-update))
(set-default
'mode-line-format
(assq-delete-all
'ace-window-display-mode
(default-value 'mode-line-format)))
(remove-hook 'window-configuration-change-hook 'aw-update)))
(defun aw-update ()
"Update ace-window-path window parameter for all windows."
(avy-traverse
(avy-tree (aw-window-list) aw-keys)
(lambda (path leaf)
;; Use `set-window-parameter' to store a variable for
;; each window. Buffer local variables would not work
;; here, since one buffer can be displayed in multiple
;; windows, and those would need a different key each.
(set-window-parameter
leaf 'ace-window-path
(propertize
(apply #'string (reverse path))
'face 'aw-mode-line-face)))))
Since I'm writing something that modifies Emacs behavior when it's enabled, I first try to implement
it as a minor mode. And since this minor mode isn't tied to a particular buffer, I declare it as
global.
An interesting quirk is that I have to put something between the docstring and the body, otherwise
it won't work. In this case, I put :global t
.
Next, follows that standard dispatch on the variable symbol of the mode - ace-window-display-mode
.
The define-minor-mode
macro will make both variable and function definition for the symbol it's
given:
- the variable is used to check if the mode is on.
- the function is used to turn the mode on / off.
Note the use of assq-delete-all
: this is for when some other package modifies the
mode-line-format
after ace-window
does. In that case, ace-window
's entry wouldn't be the first
one any more.
Since mode-line-format
is a buffer-local variable, I set it with set-default
, in order for the
change to not just happen in the current buffer.
Each time a window is created or deleted, Emacs will run the window-configuration-change-hook
-
exactly what I need to update mode-line-format
.
One final trick is to use set-window-parameter
to store a variable for each window. Buffer local
variables would not work here, since one buffer can be displayed in multiple windows, and those
would need a different key each.
I really like how the avy-tree
/ avy-traverse
interface ended up as: the same functions are used
for selecting window and setting mode-line-format
.
Outro
I hope that you enjoy the update, and keep those interesting ideas coming!
11 Mar 2015
Of course, I mean illusions not tricks.
Illusion 1: jump to a magit repository
This is just a copy-paste of the code from
this post by
Iqbal Ansari.
(setq magit-repo-dirs
(mapcar
(lambda (dir)
(substring dir 0 -1))
(cl-remove-if-not
(lambda (project)
(unless (file-remote-p project)
(file-directory-p (concat project "/.git/"))))
(projectile-relevant-known-projects))))
Basically it's just taking projectile
's record of known projects, and then filtering it by whether
that project has .git
in its root.
To get a selection of repositories, call with C-u M-x magit-status
.
And don't forget to choose ido
completion:
(setq magit-completing-read-function 'magit-ido-completing-read)
And here's how I use this in a dispatch:
(defhydra hydra-helm (:color blue)
"helm"
("f" projectile-find-file "file")
("w" helm-org-wiki "wiki")
("g" (let ((current-prefix-arg 4))
(call-interactively #'magit-status))
"git")
("l" helm-locate "locate")
("q" nil "quit"))
(global-set-key "κ" 'hydra-helm/body)
If you're wondering what the letter in global-set-key
is, it's the Greek letter kappa
(see the post on my Xmodmap setup).
Illusion 2: quickly get Github pull requests on your system
I learned this from some HN post that I can't find now. Basically, you have to open
your .git/config
file and find the following contents:
[remote "origin"]
url = [email protected]:abo-abo/hydra.git
fetch = +refs/heads/*:refs/remotes/origin/*
Then, modify it by adding one line (same for all repositories):
[remote "origin"]
url = [email protected]:abo-abo/hydra.git
fetch = +refs/heads/*:refs/remotes/origin/*
fetch = +refs/pull/*/head:refs/pull/origin/*
Now, if you issue:
You can operate on your pull requests like so:
git merge refs/pull/origin/20
Here, 20
is the issue number. And after merging I finally get access to magit
and ediff
and
all that jazz to see what the change is actually about. Before I learned this, I had to manually
add remotes with magit-add-remote
. And even before that, I was just clicking the merge button
after thoughtfully browsing the diff in Firefox. Trust me, ediff
is orders of magnitude better.
Illusion 3: edit a Github wiki in Emacs
Of course, I was always editing it in Emacs with
It's All Text Firefox plugin.
But when I wanted to add an image, I actually read the manual and found out that you can simply
clone the wiki:
git clone https://github.com/abo-abo/hydra.wiki.git
Or with the ssh style, in order to not type the user name and password on pushing:
By the way, today I've made a very large overhaul of hydra's
README.md. So if you wanted to start writing your own hydras, but were hesitant because of the lack
of documentation, now is the time to start.
If you figure out something that you think is worth documenting, you can immediately leave it on the
wiki.
By the way, here's the syntax for including an image, if you were wondering:

You upload a file simply by adding it to the repository. Look Ma, no Imgur!
This is actually an issue that I ran into, when I was less experienced. I included some one megabyte
gifs in the lispy
repository to refer to them in README.md
. Just a few of them resulted in a
very uncomfortable cloning time, which is an issue for Travis CI and, you know, humans. Finally, I
had to resort to bfg-repo-cleaner to remove the gifs
from the repo history. It could all be avoided if I just posted all images on the wiki and linked to
them in README.md
.
Outro
I hope that you find these illusions useful to make you a better Emacs magician. Happy hacking!