16 Apr 2015
Today I'd like to introduce a function that has completely replaced
ido-mode
for me: ivy-mode
. It comes with the
swiper package, available both in
MELPA and
GNU ELPA.
The latter is a bit slower to update, so the version there can be a bit outdated sometimes.
The quick video demo
If you prefer listening and watching to reading, check out the video
demo here.
It repeats most of the stuff written down below.
Generic completion
ivy-mode
is simply a minor mode that changes
completing-read-function
to ivy-completing-read
while it's active.
This function is used in most of the places where Emacs requires
completion, like:
- M-x
execute-extended-command
- C-h f
describe-function
- C-h v
describe-variable
package-install
- C-x b
switch-to-buffer
- C-x C-f
find-file
So, while ivy-mode
is on, all these functions and more will use ivy completion.
Package-specific completion
org-mode
With the most recent master version, org-mode
will obey
completing-read-function
, so it should work by default. If you try
it for refiling to headings with similar names, you'll really notice
how much better ivy-mode
is at it. helm-mode
also does well, if
you don't mind the large window.
magit
This setting is needed to use ivy completion:
(setq magit-completing-read-function 'ivy-completing-read)
find-file-in-project
find-file-in-project
will use ivy by default if it's available.
projectile
You can set this to make it work:
(setq projectile-completion-system 'ivy)
smex
Yes, it's also possible, since today. Although you'll have to use my
fork of smex if you want to try it.
I've sent a pull request, it's all backwards-compatible, so hopefully
it'll get merged.
The nice thing is that smex
can take care of the sorting all by
itself, since ivy
doesn't do that yet.
my packages
lispy and
function-args use ivy
by
default. You can also enable it for
helm-make, for which the
default is obviously helm
.
File name completion
When ivy-mode
is on, find-file
will also use it. The completion
is considerably different from all other cases, since it's done in
stages, just like ido-find-file
does it.
The key bindings are:
- RET will select the current candidate and finish.
- C-j will try to continue the completion, i.e. if the
current candidate is a directory, move to that directory. But if the
current candidate is a file or
./
, then finish.
- / will switch to completing the sub-directories of
/
,
but if the candidate is a perfect match, it will act like
C-j.
- ~ will switch to completing the sub-directories of
~/
.
- C-n and C-p naturally select the next and the previous candidate.
What's it all for?
Well, for me the advantage is obvious: I get my completion just the
way I like it. You can use it as well if you find that you like it
more than ido. I'll just list a list of features that I like:
- The current number of candidates is robustly displayed and updated after each key stroke.
- The minibuffer is an actual editing area, where the bindings like
C-a, M-DEL and C-k etc. work just as
you expect. Once you internalize the way that the regex is built, you
can get your match very quickly and intuitively.
- The actual regular expressions constructs like
\\b
or $
and ^
work. The only thing that works differently
is the space: you can't match a single space because any amount of spaces translates into the .*
wild card.
But you can use it to your advantage and use the space instead of all the various symbol joining constructs out there, like
snake_case
, or kebab-case
(yeah, it's totally called that, check the wiki), or whatever/this/is/case
.
- The familiar M-< and M-> key bindings also work as expected, navigating you to the first and last candidate respectively.
When you press C-p on the first match or C-n on the last match, the match will not change, unlike the behavior
of
ido
that has annoyed me a lot.
- The minibuffer key bindings can actually be properly customized:
just set
ivy-minibuffer-map
to whatever you like, it won't be
changed. Even in Emacs 24.5, if you customize ido-completion-map
,
the change will be reset. That was fixed only in the current master.
- You don't have to rely on
flx
or flx-ido
to save you from the overwhelming number of matches.
Instead, you type maybe a bit more, but in return you get a very consistent and predictable result.
No black boxes or hidden variables that dramatically change the order of candidates from time to time.
Outro
Check it out, I hope you like it. And a big thanks to all who
contributed code or bug reports.
15 Apr 2015
More hydra goodness incoming, this time thanks to @joedicastro.
Firstly, he contributed this awesome-looking twittering-mode
hydra to the wiki:
And a similarly nice one for helm:
You can look up the code for both hydras by following the above two links.
Secondly, he gave me a nice idea in #108:
A nice thing that guide-key has is that you can set an idle time to
wait until you press a key to activate any head before show the
hydra hints buffer (explained in hydra terms). This is very helpful
when you know the key bindings by memory and you do not need to see
the hints buffer, but if you forget how to activate any head, you
simple press the hydra binding and wait the "idle time" and the
hints buffer is shown to help you to choose the right next binding.
So this option is now also possible. Here's an example, using hydra-toggle
from hydra-examples.el:
(defhydra hydra-toggle (:color blue
:idle 1.0)
"toggle"
("a" abbrev-mode "abbrev")
("d" toggle-debug-on-error "debug")
("f" auto-fill-mode "fill")
("t" toggle-truncate-lines "truncate")
("q" nil "cancel"))
(global-set-key (kbd "C-c C-v") 'hydra-toggle/body)
So the single change from the old code is :idle 1.0
, which means:
After a call to hydra-toggle/body
, instead of displaying the hint
as usual, start a timer for 1.0 seconds. Once the timer runs out,
display the hint. But if the hydra has exited before that time,
cancel the timer.
Typically, I'm not a huge fan of timers, but it's nice to have the
option. And indeed, I've been noticing that I could do without a hint
for some simple and more often used hydras. But a command can go from
often to barely used quickly, and disabling the hint altogether seems
too harsh. A timer could be a nice middle ground, especially since I
can decide whether to use it or not and the interval for each specific
hydra.
Anyway, thanks for the contributions. Enjoy the new feature, and keep
those good ideas coming!
14 Apr 2015
A hydra for org-mode time/clock/capture
This is a categorized version of the hydra that @WorldsEndless contributed
today to the wiki.
(defhydra hydra-global-org (:color blue
:hint nil)
"
Timer^^ ^Clock^ ^Capture^
--------------------------------------------------
s_t_art _w_ clock in _c_apture
_s_top _o_ clock out _l_ast capture
_r_eset _j_ clock goto
_p_rint
"
("t" org-timer-start)
("s" org-timer-stop)
;; Need to be at timer
("r" org-timer-set-timer)
;; Print timer value to buffer
("p" org-timer)
("w" (org-clock-in '(4)))
("o" org-clock-out)
;; Visit the clocked task from any buffer
("j" org-clock-goto)
("c" org-capture)
("l" org-capture-goto-last-stored))
I've bound it like this:
(global-set-key [f11] 'hydra-global-org/body)
Previously, I had f11 bound to org-clock-goto
, thanks to
the Org Mode - Organize Your Life In Plain Text!
post. I kind of recommend that post, as it has a tonne of useful
stuff. At the same time, it resulted in me copying too much stuff that I didn't understand into my config,
ultimately discouraging me from using org-mode
. YMMV.
Screenshot:
A hydra for refile/archive
Inspired by the previous one, I wanted to write a hydra of my own. As
it happened, I was just about to clean up my git notes. So I wanted a
nice refile hydra to speed up the process.
Here's the hydra's code, which is now part of
worf. Worf is a package for
quickly navigating around an org-mode
buffer, you can get it from
MELPA.
(defhydra hydra-refile (:hint nil
:color teal)
"
Refile:^^ _k_eep: %`org-refile-keep
----------------------------------
_l_ast _a_rchive
_o_ther
_t_his
"
("t" worf-refile-this)
("o" worf-refile-other)
("l" worf-refile-last)
("k" (setq org-refile-keep (not org-refile-keep))
:exit nil)
("a" (org-archive-subtree))
("q" nil "quit"))
Some explanations:
worf-refile-this
will give you a choice of this file's headings for refiling.
worf-refile-other
will give you a choice of your org-refile-targets
except the current file.
worf-refile-last
will refile to the last refile location without prompting.
- k will toggle
org-refile-keep
, which decides if refiling moves or copies the text.
And here's how it looks like:
Outro
Thanks for the contribution, enjoy the new stuff.
Also, if you ever want to dig around someone's git notes, you can read mine,
courtesy of org-mode
export.
13 Apr 2015
A lot of the changes for this release aren't very user-visible, although they
are important in improving the usability. The main change is the move from the
standard set-transient-map
to my own hydra-set-transient-map
.
This change has allowed to remove the part where the amaranth and pink hydras
intercept a binding which doesn't belong to them and then try to forward it back
to Emacs. It was done in this way, which might be interesting for people who
write Elisp:
(define-key hydra-keymap t 'hydra-intercept)
Binding t
means that when the keymap is active, any binding which doesn't
belong to the keymap will be interpreted as t
. Then, I would use lookup-key
and this-command-keys
and try to call the result. That method was quite
fragile:
- It didn't work for prefix keys while a pink hydra was active.
- It didn't work for some keys in the terminal because of
input-decode-map
.
The new method solves the mentioned issues by not using t
and instead running
this function in the pre-command-hook
:
(defun hydra--clearfun ()
"Disable the current Hydra unless `this-command' is a head."
(if (memq this-command '(handle-switch-frame
keyboard-quit))
(hydra-disable)
(unless (eq this-command
(lookup-key hydra-curr-map
(this-single-command-keys)))
(unless (cl-case hydra-curr-foreign-keys
(warn
(setq this-command 'hydra-amaranth-warn))
(run
t)
(t nil))
(hydra-disable)))))
This approach is actually very similar to what the built-in set-transient-map
does from Emacs 24.4 onward. Of course, changing the a large cog in the Hydra
mechanism can lead to some new bugs, or even old bugs to re-surface. So I really
appreciate the help from @jhonnyseven in testing the new code.
As always, if you find something very broken, you can roll back to the GNU ELPA version
and raise an issue.
Fixes
single command red/blue issue
Fix the uniqueness issue, when a single command is assigned to both a
red and a blue head.
Here's an example:
(defhydra hydra-zoom (global-map "<f2>")
"zoom"
("g" text-scale-increase "in")
("l" text-scale-decrease "out")
("r" (text-scale-set 0) "reset")
("0" (text-scale-set 0) :bind nil :exit t)
("1" (text-scale-set 0) nil :bind nil :exit t))
Here, three heads are assigned (text-scale-set 0)
, however their behavior is different:
- r doesn't exit and has a string hint.
- 0 exits and has an empty hint (so only the key is in the docstring).
- 1 exits and has a nil hint (will not be displayed in the docstring).
The latter two call hydra-zoom/lambda-0-and-exit
, while r
calls hydra-zoom/lambda-r
.
Don't default hydra-repeast--prefix-arg
to 1
See #61 for more info.
Allow hydra-repeat
to take a numeric arg
For hydra-vi
, it's now possible to do this 4j.2...
The line will be forwarded:
- 4 times by 4j
- 4 times by .
- 2 times by 2.
- 2 times by .
See #92 for more info.
Key chord will be disabled for the duration of a hydra
This means that hydras have become much more easy to use with key chords. For
instance, if dj key chord calls a hydra or is part of the hydra, you
won't call the jj key chord by accident with djj.
See #97 for more info.
New Features
Variable as a string docstring spec
You can now use this form in your hydras:
(defvar foo "a b c")
(defhydra bar ()
"
bar %s`foo
"
("a" 't)
("q" nil))
Previously, it would only work for %s(foo)
forms.
:bind
property can also be a keymap
If you remember, you can set :bind
in the body to define in which way the
heads should be bound outside the Hydra. You also assign/override :bind
for
each head. This is especially useful to set :bind
to nil for a few heads that
you don't want to bind outside.
Previously, :bind
could be either a lambda or nil. Now a keymap is also accepted.
Integration tests
In addition to the abundant macro-expansion tests, integration tests are now
also running, both for emacs24
and for emacs-snapshot
. This means that hydra
should be a lot more stable now.
Here's an example test:
(defhydra hydra-simple-1 (global-map "C-c")
("a" (insert "j"))
("b" (insert "k"))
("q" nil))
(ert-deftest hydra-integration-1 ()
(should (string= (hydra-with "|"
(execute-kbd-macro
(kbd "C-c aabbaaqaabbaa")))
"jjkkjjaabbaa|"))
(should (string= (hydra-with "|"
(condition-case nil
(execute-kbd-macro
(kbd "C-c aabb C-g"))
(quit nil))
(execute-kbd-macro "aaqaabbaa"))
"jjkkaaqaabbaa|")))
In the tests above, hydra-simple
is a defined and bound hydra. "|"
represents the buffer text (empty), where |
is the point position.
And (kbd "C-c aabbaaqaabbaa")
represents the key sequence that you can normally press by hand.
Finally, "jjkkjjaabbaa|"
is what the buffer and the point position should look like afterwards.
If you find a hydra bug, it would be really cool to submit a new integration test to make sure that
this bug doesn't happen in the future.
Basic error handling
I really like the use-package feature where it catches load-time errors and issues a message instead of bringing up the debugger. This is really useful, since it's hard to fix the bug with a mostly broken Emacs, in the case when the error happened early in the load process. So the same behavior now happens with defhydra
. In case of an error, defhydra
will be equivalent to a no-op, and the error message will be written to the *Messages*
buffer.
Use a variable instead of a function for the hint
This leads up to the yet unresolved #86, which asks
for heads to be activated conditionally.
For now, you can modify the docstring on your own if you wish.
Here's some code from the expansion of hydra-zoom
to explain what I mean:
(set
(defvar hydra-zoom/hint nil
"Dynamic hint for hydra-zoom.")
'(format
#("zoom: [g]: in, [l]: out."
7 8 (face hydra-face-red)
16 17 (face hydra-face-red))))
;; in head body:
(when hydra-is-helpful
(if hydra-lv
(lv-message
(eval hydra-zoom/hint))
(message
(eval hydra-zoom/hint))))
Eventually, I'll add some automatic stuff to fix #86. But for now, you can
experiment with modifying e.g. hydra-zoom/hint
inside heads, if you want.
Multiple inheritance for Hydra heads
Each hydra, e.g. hydra-foo
will now declare its own heads as a variable
hydra-foo/heads
. It's possible to inherit them like this:
(defhydra hydra-zoom (global-map "<f2>")
"zoom"
("g" text-scale-increase "in")
("s" text-scale-decrease "out"))
(defhydra hydra-arrows ()
("h" backward-char "left")
("j" next-line "down")
("k" previous-line "up")
("l" forward-char "right"))
(defhydra hydra-zoom-child (:inherit (hydra-zoom/heads
hydra-arrows/heads)
:color amaranth)
"zoom"
("q" nil))
Here, hydra-zoom-child
inherits the heads of hydra-zoom
and hydra-arrows
.
It adds one more head q to quit. Also, it changes the color to
amaranth, which means that it's only possible to exit it with q or
C-g. This hydra's parents remain at their original (red) color.
See #57 for more info.
Outro
A big thanks to all who contributed towards this release and to the wiki.
If you have an idea that would be cool in Hydra, do raise an issue.
And if you written some cool code that uses the already available Hydra features, please share it on the wiki.
It's also a good way to protect your code against regressions (although the best one would be an integration test).
Finally, check out the new version of
pandoc-mode which is
one of the coolest and most elaborate uses of Hydra yet.
09 Apr 2015
Intro
If you like my package swiper,
I'm sure you'll also like counsel. It
lives in the same repository, but you can install it separately from
MELPA.
Counsel uses ivy
- the same method as swiper
to:
- Complete Elisp at point with
counsel-el
.
- Complete Clojure at point with
counsel-clj
.
- Open a git-managed file with
counsel-git
.
- Describe an Elisp variable with
counsel-describe-variable
.
- Describe an Elisp function with
counsel-describe-function
.
- Look up an Elisp symbol in the info with
counsel-info-lookup-symbol
.
- Insert a Unicode character at point with
counsel-unicode-char
.
Below, I'll describe the functions that I added just today.
counsel-describe-function
This is just a replacement for describe-function
:
As you can see, regular expressions work here as well. The
space-splitting behavior is the same as in swiper
, so don't expect
to be able to match a single space: spaces are wild.
counsel-describe-variable
This is just a replacement for describe-variable
:
Well, actually I've used ido-mode
with flx
matching for these two
functions before. In my experience, ivy
handles much better:
- you are in charge of which regex you're searching for
- you see the candidate count
- no crazy wrap-around candidate cycling
And it works faster, too.
Here are my bindings:
(global-set-key (kbd "<f1> f") 'counsel-describe-function)
(global-set-key (kbd "<f1> v") 'counsel-describe-variable)
counsel-info-lookup-symbol
I don't use this one too often, but it's nice to have the option:
(global-set-key (kbd "<f2> i") 'counsel-info-lookup-symbol)
counsel-unicode-char
At around 40000 candidates, ivy
starts to feel clunky (around 0.1s
display delay). Unfortunately, I don't really see a way around this,
except using tricks like while-no-input
, which didn't work right
when I tried it earlier. It would be really cool to do the completion
in another thread, but alas.
Outro
Give the new functions a try. I think ivy
can become a viable ido
replacement, at least it has done so for me: the only ido
functions
that I'm still using are ido-switch-buffer
and ido-find-file
.
Also, if you're using projectile
, you can use ivy
completion for it:
(setq projectile-completion-system 'ivy)