20 Jul 2015
The new :columns
option
Today I'll introduce a pretty cool new option that you can use to
quickly create hydra docstrings arranged in a matrix. This, of
course, was already possible before, but you had to format the matrix
by-hand like this (I cite just bit instead of the
full code, it was
cut to fit into the Jekyll code column restriction):
(defhydra hydra-projectile (:color teal
:hint nil)
"
PROJECTILE:
Find File Search/Tags
-----------------------------------------
_s-f_: file _a_: ag
_ff_: file dwim _g_: update gtags
_fd_: file curr dir _o_: multi-occur
"
("s-f" projectile-find-file)
("a" projectile-ag)
("ff" projectile-find-file-dwim)
("fd" projectile-find-file-in-directory)
("g" ggtags-update-tags)
("o" projectile-multi-occur)
("q" nil "cancel"))
The syntax above is still very useful if you want to arrange every
detail perfectly or need Ruby-style quoting. But here's the new
syntax that allows to get almost the
same docstring
much easier:
(defhydra hydra-projectile (:color blue
:columns 4)
"Projectile"
("a" projectile-ag "ag")
("b" projectile-switch-to-buffer "switch to buffer")
("c" projectile-invalidate-cache "cache clear")
("d" projectile-find-dir "dir")
("s-f" projectile-find-file "file")
("ff" projectile-find-file-dwim "file dwim")
("fd" projectile-find-file-in-directory "file curr dir")
("g" ggtags-update-tags "update gtags")
("i" projectile-ibuffer "Ibuffer")
("K" projectile-kill-buffers "Kill all buffers")
("o" projectile-multi-occur "multi-occur")
("p" projectile-switch-project "switch")
("r" projectile-recentf "recent file")
("x" projectile-remove-known-project "remove known")
("X" projectile-cleanup-known-projects "cleanup non-existing")
("z" projectile-cache-current-file "cache current")
("q" nil "cancel"))
It still looks pretty good, in my opinion:
Note how all redundant information has been removed. Another advantage
is the you can easily:
- Add/remove heads.
- Update head hints.
- Change the number of columns.
A bit of customization
After each change, just re-eval the defhydra
and you're done - no
need to manually re-arrange the docstring. Since there already is an
interface that allows you to customize the docstring very precisely, I
tried to make the new interface as automatic as possible: just specify
the number of columns and you're done. But if you want just a little
bit more customization, look at this code:
(defvar hydra-key-doc-function 'hydra-key-doc-function-default
"The function for formatting key-doc pairs.")
(defun hydra-key-doc-function-default (key key-width doc doc-width)
(format (format "%%%ds: %%%ds" key-width (- -1 doc-width))
key doc))
So if you want to add a little space here and there, or e.g. wrap key
bindings in brackets, just clone hydra-key-doc-function-default
,
customize it a bit and set hydra-key-doc-function
to the new
function.
Outro
If you've been using just the plain style before and felt that you
can't fit your docstring on one line, try the new style: it's just one
line of change with respect to your old code. And if you've been
building the docstring by-hand, see if it's possible to transform it
to the new style: adding and removing new heads will become easier.
Thanks to @Fuco1 for the suggestion in
#140.
16 Jul 2015
Today I'd like to share an interesting bit of Elisp that comes up
every now and then for me. Imagine that you have this:
(defun useful-command ()
(interactive)
(do-thing-1)
(do-thing-2 (funcall callback-function))
(do-thing-3))
Sometimes, when you are in callback-function
, you might want to
abandon the function that called you, useful-command
in this case,
and call a different function, with the current context.
Here's what I've come up with to do just that:
(defmacro ivy-quit-and-run (&rest body)
"Quit the minibuffer and run BODY afterwards."
`(progn
(put 'quit 'error-message "")
(run-at-time nil nil
(lambda ()
(put 'quit 'error-message "Quit")
,@body))
(minibuffer-keyboard-quit)))
To break it up into parts:
minibuffer-keyboard-quit
will unwind the call stack all the way to
the command loop, preventing e.g. do-thing-3
from being
called. Note that the call stack can be as deep as you like, e.g.
useful-command
might be called by utility-command
etc.
run-at-time
with the argument nil
will run the code as soon as
possible, which is almost exactly after we're back into the command
loop.
The final trick is to prevent Quit
from being displayed in the minibuffer.
Sample application
Suppose that I've called find-file
when ivy-mode
is
active. Typically, I'd select a file and press C-m to open
it. However, sometimes I just want to see the selected file in dired
instead of opening it. This code is from before
ivy multi-action interface,
it plainly binds a command in ivy-minibuffer-map
:
(define-key ivy-minibuffer-map (kbd "C-:") 'ivy-dired)
(defun ivy-dired ()
(interactive)
(if ivy--directory
(ivy-quit-and-run
(dired ivy--directory)
(when (re-search-forward
(regexp-quote
(substring ivy--current 0 -1)) nil t)
(goto-char (match-beginning 0))))
(user-error
"Not completing files currently")))
So at the moment when C-: is pressed, the call stack is:
- C-x C-f called
find-file
.
find-file
called completion-read-function
which is set to ivy-completing-read
.
ivy-completing-read
called ivy-read
.
ivy-read
called read-from-minibuffer
.
Thanks to the new macro, I can unwind all of that stuff, making sure
nothing extra will be executed that was supposed to be executed after
read-from-minibuffer
had returned. In other words, the file will not
be opened. Instead, a dired
buffer will be opened, centered on the
selected candidate.
What I described above can actually be a pretty common scenario, you
could adapt it to helm
or avy
or projectile
. Basically to
anything that includes some form of completion (i.e. commands that
wait for input) and offers you a customizable keymap. Small
disclaimer: the above code falls into the quick-and-dirty category, I
don't recommend it if you can do something smarter instead. But if you
can't do anything smarter due to being constrained by an interface you
don't control, this macro could help you out.
09 Jul 2015
I might have mentioned before that I'm using GNU/Linux on all of my
computers. The particular flavor is Ubuntu, although it shouldn't
matter much, since I can count the graphical applications that I use
at all, besides Emacs, on one hand. They are: Firefox, Evince,
Rhythmbox and VLC. Of course, as most true Emacs-ers, I strive to
reduce this number to zero. So I got quite excited when I saw
helm-rhythmbox show up in
my package list. It works great: you can play and enqueue tracks with
completion without leaving Emacs. Big thanks to
@mrBliss, and, of course, the authors
for dbus.el
which makes interaction with D-Bus possible through
Elisp.
I'm not as big a fan of Helm as I used to be, so I quickly implemented an Ivy equivalent:
(defun counsel-rhythmbox-enqueue-song (song)
"Let Rhythmbox enqueue SONG."
(let ((service "org.gnome.Rhythmbox3")
(path "/org/gnome/Rhythmbox3/PlayQueue")
(interface "org.gnome.Rhythmbox3.PlayQueue"))
(dbus-call-method :session service path interface
"AddToQueue" (rhythmbox-song-uri song))))
;;;###autoload
(defun counsel-rhythmbox ()
"Choose a song from the Rhythmbox library to play or enqueue."
(interactive)
(unless (require 'helm-rhythmbox nil t)
(error "Please install `helm-rhythmbox'"))
(unless rhythmbox-library
(rhythmbox-load-library)
(while (null rhythmbox-library)
(sit-for 0.1)))
(ivy-read "Rhythmbox: "
(helm-rhythmbox-candidates)
:action
'(1
("Play song" helm-rhythmbox-play-song)
("Enqueue song" counsel-rhythmbox-enqueue-song))))
I listed the whole code just to show how easy it is to interact with
D-Bus, and also to show-off the shiny new multi-action interface of
ivy-read
. Besides being discoverable via C-o, the
multi-action interface is extensible as well. Here's how to add a
"Dequeue" action without touching the original code:
(defun counsel-rhythmbox-dequeue-song (song)
"Let Rhythmbox dequeue SONG."
(let ((service "org.gnome.Rhythmbox3")
(path "/org/gnome/Rhythmbox3/PlayQueue")
(interface "org.gnome.Rhythmbox3.PlayQueue"))
(dbus-call-method :session service path interface
"RemoveFromQueue" (rhythmbox-song-uri song))))
(ivy-set-actions
'counsel-rhythmbox
'(("Dequeue song" counsel-rhythmbox-dequeue-song)))
Very simple, counsel-rhythmbox-dequeue-song
is a clone of
counsel-rhythmbox-enqueue-song
with only the method change from
AddToQueue
to RemoveFromQueue
(I blind-guessed the name, but there
should be a reference somewhere). If you got tired of having a whole
three actions to choose from, you can revert to the initial two with:
(ivy-set-actions 'counsel-rhythmbox nil)
And here's how the updated C-o option panel now looks like:
A bit of descriptions:
- j moves to the next one of the 18 current candidates.
- k moves to the previous candidate.
- h moves to the first candidate.
- l moves to the last candidate.
- g calls the current action without exiting.
- d calls the current action and exits.
- s moves to the next action.
- w moves to the previous action.
- i and C-o close the options panel without exiting.
- o closes the panel and exits.
Similarly to hydra
, each action has a short docstring, like "Play
song"
that should describe what it does. Here are a few usage
scenarios:
- If I wanted to play the first song and enqueue the third and the
sixth and exit the minibuffer, I would press gsjjgjjjd.
- If I wanted to play the third and enqueue all the following, I would
press jjgsjcjjjjjjjjjjjo. The many j is just
me holding j until the selection reaches the end, then I
simply exit without doing anything else by pressing o.
The way c works is that it toggles the "calling" state -
a state where the current action is called whenever a different
candidate is selected.
Almost forgot, if this little intro got you excited, the packages that you should install from MELPA are: helm-rhythmbox
and counsel
.
07 Jul 2015
Today I'd like to highlight a generic command recently added to
hydra. It's kind of cute, and
maybe something that you didn't even know you wanted. Basically, the
hydra-pause-resume
command allows to pause and resume the current
hydra with one key. And it works for all hydras at once, without any
extra configuration. All you have to do is to bind it globally to
whatever you like, for example:
(global-set-key (kbd "C-M-k") 'hydra-pause-resume)
What it does:
- If a hydra is active, deactivate and push it on the stack.
- If no hydra is active, pop one from the stack and call it.
- If the stack is empty, call the last hydra.
Personally, I haven't found too much use from the stack - resuming the
last one is enough for me. But the stack comes at no extra cost, and
might be useful to someone.
If, for example, you have 2 hydras on the stack, how to resume the
older one?
The way stacks work, you simply have to go through all elements one by one. So that's:
- C-M-k to resume the newer one.
- Quit the current one with the appropriate shortcut, only not with C-M-k, since that would just put it back on the stack.
- C-M-k to resume the only one remaining on the stack - the older one.
Thanks to @QiangF for the suggestion in #135.
02 Jul 2015
locate
I'm sure many people know that Emacs comes with a locate
command. This command, if you're on a Linux system, will find all
files on your system that match a particular pattern. The advantage of
locate
over find
when searching the whole system, is that it is
much faster, since it uses a pre-computed database. This database is
updated periodically, you can force an update with:
Of course find
is faster if you need to search only a specific
directory instead of the whole system, but sometimes you just don't
know that directory.
counsel-locate
Dynamic
The way locate
works it that it asks you for a query, which is
glob-based instead of regex-based, and then prints the results to a
static buffer.
On the other hand, counsel-locate
is dynamic: each time you input a
new character a new locate
query is ran, and the old one is
terminated. On my system, it takes around 2 seconds for a query to
complete, so it requires a bit of patience.
Regex-based
I like regex way more than globs for some reason. Here's the command
called for the input mp3$
:
Of course, the standard ivy-mode
method is used to build the regex from a list of space separated
words. So the input fleet mp3$
will result in:
locate -i --regex \\(fleet\\).*?\\(mp3$\\)
You could go your own way and update the regex matcher to be
ivy--regex-fuzzy
, which results in:
locate -i --regex f.*l.*e.*e.*t.* .*m.*p.*3$
But I think less matches is usually better than more matches.
Multi-exit
This is just the coolest feature. Basically, for each file you locate, you can easily:
- Open it in Emacs (default).
- Open it with
xdg-open
, so that PDF files are forwarded to evince
and MP3 files are forwarded to rhythmbox
etc.
- Open it in
dired
.
Here's an example of how to do it. First I call counsel-locate
,
which I like to bind to C-x l. Then I enter emacs pdf$
and wait around 2 seconds for the 248 results to come up. Then I
scroll to the 18th result and press C-o to open up the
hydra-based option panel:
The last column (Action) is newer than others. As you can see, it has
3 exit points, which I can scroll with w and s.
And currently I'm on the default exit point, which would open the file
in Emacs.
For the next screenshot:
- I pressed s twice to change the action to
dired
.
- I pressed c to make the current action execute each time a new candidate is selected.
So now, I could just scroll through all my directories on my system
that contain PDF files related to Emacs by just holding j.
A similar thing can be done for music tracks:
- C-x l
dire mp3$
to get the list of all Dire Straits tracks on my system.
- C-o s to switch the action from "open in Emacs" to "xdg-open".
- From here, I could open one track after another by pressing C-M-n repeatedly. Or I can press c and then j repeatedly.
I've been experimenting with opening EPS and PDF files in quick
succession. It's still a work in progress, since I need to use a special
wmctrl
script to prevent the Emacs window from losing focus each
time a new Evince instance is opened.
Outro
You can check out the new feature by installing counsel
from
MELPA. It will automatically fetch ivy-mode
as well. When you enable
ivy-mode
, besides doing all your completion, it will also remap
switch-to-buffer
to ivy-switch-buffer
. That command also has a
multi-exit: pressing C-o sd instead of C-m will
kill the selected buffer instead of switching to it. It's a very
minor optimization: instead of C-m C-x k you press C-o
sd, however you could e.g. use C-o scjjjj to kill
five buffers at once.
While the idea of multi-exits is powerful, it's hard to find places to
use it efficiently. I think counsel-locate
is a nice place for it,
although it could work without it:
- Find file in Emacs with C-m in the completion interface.
- Call
dired-jump
with C-x C-j.
- Type ! and
xdg-open
RET.
- Select and kill the unneeded file with C-x k.
I hope you see now why I prefer C-o sd.