10 Mar 2015
I like the idea of
helm-swoop, but it
somehow has minor annoyances that stop me from using it, like
automatic helm-input, and especially the circular candidates. Or maybe it's just NIH talking.
Anyway, I'm rolling my own, and it's called swiper.

Swiper in action
Here's how it looks like:

As you can see, the search string "dec fun pro" is transformed into
a regex "\\(dec\\).*\\(fun\\).*\\(pro\\)", and each group in the
matches is highlighted with a different face. This is quite similar
to the way re-builder does it. In fact it's possible to use swiper
as a poor man's re-builder (since it matches only single lines).
I'm doing my own matching this time, as the part-swapping behavior of
helm-match-plugin is more annoying than useful.
Also note that:
- The whole
*swiper* buffer is fully syntax highlighted.
- The appropriate parts of the matches are highlighted as well.
Swiper in a dired buffer
Here's another screenshot:

It appears that helm is ignoring the display of file attributes, since they have
a sort of invisible property set. I kind of like this behavior.
See how the faces are recycled
I've defined only 4 faces currently (foxes aren't unicorns, the
palette is quite limited), so they loop about if you have many groups:

Yup, the technology is there. Although a powerline theme for the
helm mode line is still missing.
09 Mar 2015
It was kind of disappointing to summarize in
the last post
that there weren't many new features for
lispy 0.24.0. So I thought long and hard and came up with something
quite obvious: since lispy offers commands to quickly manipulate point and mark, it should offer one
to quickly restore them.
Here's the bulk of the new code:
(defvar lispy-pos-ring (make-ring 200)
"Ring for point and mark position history.")
(ring-insert lispy-pos-ring 1)
(defun lispy--remember ()
"Store the current point and mark in history."
(if (region-active-p)
(let ((bnd (lispy--bounds-dwim)))
(unless (equal bnd (ring-ref lispy-pos-ring 0))
(ring-insert lispy-pos-ring bnd)))
(unless (eq (point) (ring-ref lispy-pos-ring 0))
(ring-insert lispy-pos-ring (point)))))
(defun lispy-back ()
"Move point to a previous position"
(interactive)
(if (zerop (ring-length lispy-pos-ring))
(user-error "At beginning of point history")
(let ((pt (ring-remove lispy-pos-ring 0)))
(if (consp pt)
(lispy--mark pt)
(deactivate-mark)
(goto-char pt)))))
Here, I'm using lispy-pos-ring made with make-ring to store the
last 200 point and mark positions. In Elisp, a ring is basically a stack backed by a vector.
When the vector space overflows, the older stuff is overwritten.
In this ring I store each time either the point, or a cons of the
point and mark if the region is active. This way possible to restore
the region even if it was deactivated several movement commands ago.
I've put lispy--remember into the most used navigation commands:
- j -
lispy-down
- k -
lispy-up
- h -
lispy-left
- l -
lispy-right
- f -
lispy-flow
- i -
lispy-mark-car (when the region is active)
- a -
lispy-ace-paren
And lispy-back is now bound to b. The previous binding of
b - lispy-store-region-and-buffer is now bound to
xB (quite close to B - the binding for
lispy-ediff-regions).
I really like the new command, it's especially useful to reverse
h and l. Previously, they could be reversed
with f, but that can get annoying if you have to press it
many times. This results in a much more relaxed editing - I know that
whatever I press, I can restore the point position quickly if needed.
This feature is added to the already present list of safeguards:
- j and k are guaranteed not to exit the parent list.
- > and < are guaranteed not to exit the parent list.
- C reverses itself.
Here's a recipe to copy the third item of the current list and move
the point back: 4mnb. You can use it to copy a function's
docstring if you're in Elisp. You'll need 3mnb for
Clojure, since it weirdly has the docstring before the arguments. I
think it's pretty cool: by typing 3mnb I'm basically
calling (kill-new (caddr (current-sexp))) on my own code.
08 Mar 2015
The last release was a month ago, and there have been 70 commits to
master since then. If you're not familiar with lispy, see
my intro post for version 0.21.0.
I'll just copy the release notes here,
while adding a few things.
Fixes
- DEL behaves properly after a string and one space.
- C-k works better for expressions preceded with "#".
- 3 should not add a space when there is one already.
- # will not add a space after a comma.
- C-j works better in comments after a quote.
lispy--eval-elisp-form first arg is now named lispy-form instead of form. It was impossible
to evaluate an unrelated form variable with the previous behavior.
- F again works properly when jumping to a jar (e.g. to
defn) from Clojure source.
- C-k won't call
delete-region in some obscure branches.
Enhancements
- P (
lispy-paste) will add a newline when called from start of line. This way,
nP becomes equivalent to c (lispy-clone). Of course, it's more flexible: you
can do e.g. nkP.
- xb (
lispy-bind-variable) now works on regions as well. Use it to bind the current
sexp or region as a let-bound variable: it will put you in iedit. When you're done with iedit, press
M-m (lispy-mark-symbol) to exit iedit. If you need to move the let binding around, use
a combination of C (lispy-convolute) and h (lispy-left).
- g will ignore
loaddefs.el for Elisp.
- M-m works better in unbalanced buffers, which should be an rare thing.
- add
defhydra to lispy-tag-arity: now g will recognize defhydra statements.
- The tag logic was improved to do less parsing.
lispy-outline was updated to match the standard ^;;; outline regex. Try pressing I
in e.g. org.el, it's quite beautiful.
- All
lispy-eval functions will preserve the match data.
- > will delete the extra whitespace while slurping.
- Added
undercover/Coveralls test coverage report.
- H (
lispy-ace-symbol-replace) is now a Hydra: type h to delete more, type
u to undo.
- Q (
lispy-ace-char) now uses avy to jump. This change allows to cover this
function with a test.
New features
p can now iterate dolist variables in Elisp.
(defun range (a b)
(message "called range")
(number-sequence a b))
(dolist |(i (range 1 3))
(message "i=%d" i))
Pressing p with point where | is, will
- call
range and set i to 1
- set
i to 2
- set
i to 3
- set
i to nil
- call
range and set i to 1
This is another step toward edebug-less debugging, adding to special behavior for let, cond
and labels. Remember that you can drop out of edebug with Z (lispy-edebug-stop).
This function will take the current function arguments that edebug provides, store them in
top-level, and exit edebug.
This is really cool for setting up entry conditions for a function that you want to debug,
or even a function with an empty body that you want to write. Why am I so eager to exit edebug?
Because it puts the code in read-only mode, which is quite restrictive.
Incompatible changes
lispy-helm-columns is now a list '(60 80). The first number is
the width of the tag name column, the second number is the width of
both tag name and tag file. The tag name column is left-aligned, while the file column is right-aligned.
- j and k should now move to outline when at
beginning of comment. The previous behavior was to look for the first
sexp in the direction. You can still do that with f.
- I (
lispy-shiftab) is now a two-way cycle, instead of
three-way, like org-mode. The contents can be obtained with
C-u I or C-u C-TAB.
Outro
It seems that lispy is winding down feature-wise, which is a good
thing, because I'm almost out of keys - there's only Y and
U left.
Possible next steps would be to improve the test coverage (currently
48%) and the documentation. Perhaps I'll try to implement some
automation for generating
the function reference, or learn some
texinfo and write an actual manual, see how ox-texinfo holds up.
I hope that you'll grow to enjoy lispy as much as I do. Happy hacking!
07 Mar 2015
Here's a new Hydra for you:
(defhydra hydra-org-template (:color blue :hint nil)
"
_c_enter _q_uote _L_aTeX:
_l_atex _e_xample _i_ndex:
_a_scii _v_erse _I_NCLUDE:
_s_rc ^ ^ _H_TML:
_h_tml ^ ^ _A_SCII:
"
("s" (hot-expand "<s"))
("e" (hot-expand "<e"))
("q" (hot-expand "<q"))
("v" (hot-expand "<v"))
("c" (hot-expand "<c"))
("l" (hot-expand "<l"))
("h" (hot-expand "<h"))
("a" (hot-expand "<a"))
("L" (hot-expand "<L"))
("i" (hot-expand "<i"))
("I" (hot-expand "<I"))
("H" (hot-expand "<H"))
("A" (hot-expand "<A"))
("<" self-insert-command "ins")
("o" nil "quit"))
(defun hot-expand (str)
"Expand org template."
(insert str)
(org-try-structure-completion))
I bind it for myself like this:
(define-key org-mode-map "<"
(lambda () (interactive)
(if (looking-back "^")
(hydra-org-template/body)
(self-insert-command 1))))
This means that when I press < from the start of the
line, a Hydra will be called instead of inserting <, otherwise <
will be inserted.
As the default insert method for org-mode blocks is already pretty
convenient, this Hydra is more of an illustration than anything,
especially of the new :hint nil feature.
Just to remind you, each head has four placeholders:
- key binding
- body
- hint
- plist
When a Hydra is active, it will show its doc in the echo area in the
bottom of the frame. This doc is composed of two parts: the body doc
and the heads' doc. The body doc you specify yourself, the heads' doc
is built by concatenating the key binding and the hint for each head
into a (single) line.
If you don't specify a hint for a head, it's assumed to be ""; this
head's binding will still be in the heads' doc. If you don't want a
head's binding to be in the heads' doc, set the hint to nil. This is
commonly done because a head is already documented in the body doc.
It can sometimes become tedious to set all the hints to nil, for
instance in the Hydra above, I would need to do it 13 times. Hence
the :hint nil shortcut.
Here's how it looks like:

I'm not a Scrabble pro: clash for word score 10 is my result, although
a longer word would break the nice column layout.
The first two columns contain begin/end templates, while the
third one contains the one-line templates.
06 Mar 2015
It's strange that I haven't implemented this feature before, as it's
quite a common usage pattern:
- You select a window with
ace-window.
- You do some stuff there.
- You want to return the previous window.
aw-flip-window
In the step 3, you have to go though the whole aw-keys dispatch,
only to select a window which can be pre-determined. Not any more, if
you call aw-flip-window:
(defun aw-flip-window ()
"Switch to the window you were previously in."
(interactive)
(aw-switch-to-window (aw--pop-window)))
So now, you could have a grid of 10 windows, select one of them with
ace-window, and switch indefinitely between it and the previous
window with ace-flip-window, while ignoring the other 8.
aw-ignored-buffers
Remember that if you have some window that you never want to switch to
with ace-window, you can add it to aw-ignored-buffers:
(defcustom aw-ignored-buffers '("*Calc Trail*" "*LV*")
"List of buffers to ignore when selecting window."
:type '(repeat string))
It's not a big deal, but it's convenient at least for this scenario:
- I start with one active window.
- M-x
calc; now I have three windows.
- I can toggle back and forth between
calc and the main window with
ace-window without having to type aw-keys, since *Calc Trail* is
ignored, so that makes only two total windows.
Selecting last window during the ace-window dispatch
This is a really cool feature, in my opinion: for all three actions -
aw-select-window, aw-swap-window, and aw-delete-window, you can
select the previous window as a target with the same key n.
This is, of course, customizable:
(defcustom aw-flip-keys '("n")
"Keys which should select the last window."
:set (lambda (sym val)
(set sym val)
(setq aw--flip-keys
(mapcar (lambda (x) (aref (kbd x) 0)) val))))
So you could have a whole list of bindings that select the previous
window during the aw-keys dispatch. This is cool because there's no
visual feedback necessary, so this binding can be easily added to the
muscle memory. The bindings don't necessarily need to be single keys,
anything with one chord, e.g. C-f, is acceptable.
Here's how I've set it up for myself:
(global-set-key "ν" 'ace-window)
(csetq aw-flip-keys '("n" "ν"))
This means that:
- I can select the previous window with νν - a double call to
ace-window.
- I can swap with the previous window with ψνν, ψ calls
universal-argument for me.
- I can delete the previous window with ψψνν.
Outro
Thanks to @luciferasm for the idea, I
hope you'll enjoy the new feature.