(or emacs irrelevant)

Colorful Hydras

This post advertises the release of hydra.el 0.5.0. The package was introduced in an earlier post and received some positive feedback. Currently, it's available in both GNU ELPA (slightly behind) and MELPA (always current).

colorful-hydra

The newfound utility

As I originally released the Hydra, I was asked if it was similar to this approach described on Endless Parentheses. I said that it's not, since Hydra commands are meant to be repeatable instead of being called just once.

Now, after I've designated the repeatable heads with red color and the one-off heads with blue color, Hydra can reproduce the mentioned approach. Here's how it looks like:

(global-set-key
 (kbd "C-c C-v")
 (defhydra hydra-toggle (:color blue)
   "toggle"
   ("a" abbrev-mode "abbrev")
   ("d" toggle-debug-on-error "debug")
   ("f" auto-fill-mode "fill")
   ("t" toggle-truncate-lines "truncate")
   ("w" whitespace-mode "whitespace")
   ("q" nil "cancel")))

And this is what I see in the echo area after pressing C-c C-v:

hydra-toggle

At this point:

  • q will cancel without doing anything. I think it's more convenient than doing the equivalent C-g with the global-set-key approach.
  • a, d, f, t, and a will call the appropriate function. The advantage of blue Hydra heads over global-set-key is that you immediately get the hint: this can be useful for rarely used commands.
  • as with the old red Hydra heads, pressing anything other than a, d, f, t, a, or q will vanquish the Hydra and call the key binding that you just pressed. This is different from the global-set-key approach, which would e.g. error to your C-c C-v C-n with "C-c C-v C-n is undefined", unlike the Hydra, which would call C-n (next-line).

The full defhydra syntax

Note that defhydra looks intentionally like a defun, so that it's easier to remember how it works. Here's a more verbose Hydra that's largely equivalent to the one above:

(defhydra hydra-toggle (global-map "C-c" :color red)
   "toggle"
   ("a" abbrev-mode "abbrev" :color blue)
   ("d" toggle-debug-on-error "debug" :color blue)
   ("f" auto-fill-mode "fill" :color blue)
   ("t" toggle-truncate-lines "truncate" :color blue)
   ("w" whitespace-mode "whitespace" :color blue)
   ("v" recenter-top-bottom "recenter" :color red)
   ("q" nil "cancel" :color blue))
(global-set-key (kbd "C-c C-v") 'hydra-toggle/body)

First argument: Hydra name

This argument decides the prefix to all the functions that will be generated. In this case the following functions will be generated:

hydra-toggle/abbrev-mode
hydra-toggle/toggle-debug-on-error
hydra-toggle/auto-fill-mode
hydra-toggle/toggle-truncate-lines
hydra-toggle/whitespace-mode
hydra-toggle/recenter-top-bottom
hydra-toggle/nil
hydra-toggle/body

The final function calls the Hydra's body, displaying the hint in the echo area and setting the transient map. It's the return result of defhydra, that's why it was possible to pass it to global-set-key in the first example.

Second argument: Hydra body

The Hydra body consists of:

  • a map used for binding, like global-map or c++-mode-map or projectile-mode-map
  • the body prefix: it's a string passable to kbd that will be used in conjunction with heads' prefixes to bind the functions
  • an optional plist, which currently recognizes only the :color key, which in turn can be either red (the old behavior) or blue.

It's possible to omit the map and the body prefix simultaneously (it doesn't make sense to omit one but not the other), or just pass () if you want to get a red Hydra body that you can bind yourself.

Third argument: Hydra hint

This string will be used in the echo area to distinguish the current Hydra. This is optional, it case you don't provide it, it will default to "hydra".

Fourth argument: Hydra heads

Each Hydra head is a list of:

  • the key extension
  • the function
  • optional hint
  • optional plist.

Again, the plist recognizes only :color currently. The color is inherited from the body, if you don't specify it. In turn, the body color is red if you don't specify it.

The code above:

  • binds C-c a, C-c d etc with the usual global-set-key approach.
  • binds C-c C-v a, C-c C-v d with the new approach, which shows you the hint right after C-c C-v and allows you to cancel easier.
  • binds C-c v to be repeatable, i.e. you can press C-c v v v. Same with C-c C-v v v v.

Some more ideas for blue Hydras

Here's one for some helm-related functions, don't ask how projectile-find-file ended up here:

(global-set-key
 "κ"
 (defhydra hydra-helm (:color blue)
   "helm"
   ("f" projectile-find-file "file")
   ("w" helm-org-wiki "wiki")
   ("r" helm-recentf "recent")
   ("s" helm-swoop "swoop")
   ("q" nil "quit")))

Here's one more for gnus; I'm just getting the hang of it, so some hints are useful:

(defhydra hydra-gnus-reply (:color blue)
  "reply"
  ("o" gnus-summary-reply-with-original "one")
  ("O" gnus-summary-reply)
  ("a" gnus-summary-wide-reply-with-original "all")
  ("A" gnus-summary-wide-reply)
  ("u" gnus-summary-very-wide-reply-with-original "universe")
  ("U" gnus-summary-very-wide-reply)
  ("q" nil "quit"))
(define-key gnus-summary-mode-map "r" 'hydra-gnus-reply/body)

I omit the hint for the commands that do the same as the previous one, just without citing.

Outro

I hope that you enjoy the update and let me know when you invent some efficient blue or red-and-blue Hydras. Happy hacking!

Blogging about blogging

In Emacs, of course. As I mentioned before, this blog is run using Jekyll and a fork of the lanyon theme.

It started out pretty convenient: thanks to jekyll serve I would see the live updates at http://localhost:4000/ as I was editing the markdown. But after a few posts, I've experienced a drastic decrease in refresh time: it went from under a second to 15 seconds. Below, I'll show how I've managed to speed it back up.

No posts - no problem

Thanks to (require 'dired-x) I can jump from the current post to the posts directory with C-x C-j. It even puts the point on the current file. Now:

  • m to mark to current file
  • t to invert the mark, making the current file unmarked and all others marked
  • D to delete all marked files. No need to worry, since they are all version-controlled (except the original one, which isn't being deleted), dired even asks you for confirmation, so I hit y.

Now, that there is only one post in the whole blog, jekyll serve is much faster at refreshing.

Even faster jekyll serve

Which brings me to the next point. Since I'm calling it so much, might as well wrap it in some Elisp. Elisp is like frosting - it makes everything better:

(defun jekyll-serve ()
  (interactive)
  (let* ((default-directory
          (if (string-match "_posts/$" default-directory)
              (directory-parent default-directory)
            default-directory))
         (buffer (if (get-buffer "*jekyll*")
                     (switch-to-buffer "*jekyll*")
                   (ansi-term "/bin/bash" "jekyll")))
         (proc (get-buffer-process buffer)))
    (term-send-string proc "jekyll serve\n")
    (sit-for 3)
    (browse-url "localhost:4000")))

This function, when called from the current post or the current blog, will:

  • open a new ansi-term called *jekyll*
  • issue a jekyll serve command to it
  • wait for 3 seconds for Jekyll to start
  • open localhost:4000 in Firefox

One post isn't a blog

Here's how to quickly bring back the deleted posts.

  • Fire up magit; I have magit-status bound to μm.
  • Stage the current post with s (magit-stage-item).
  • Start the commit with C (magit-commit-add-log). I'm using my own modification of magit-commit-add-log that arranges the whitespace in a nice way, when aimed at a file instead of a hunk.
  • I get _posts/2015-02-01-blogging-about-blogging.md: string auto-generated by C.
  • I just amend it to look like _posts/2015-02-01-blogging-about-blogging.md: add and finalize the commit with C-c C-c (git-commit-commit).
  • Now I have around 40 files marked as deleted, but not staged. I create a stash with zz and name it foo or something. Then delete the stash with magit-discard-item, which I like to bind to d to be similar to dired. Now it's as if these files were never deleted.

Whoa, now that I look at it, it's a lot of steps. But somehow dired and magit are very similar to Super Mario Bros: it takes long to explain what you're doing, but as you play it, it's very simple and natural.

abel.el - abbrevs for Elisp

This is a follow-up to an older post about abbrevs.

I did try to make Elisp abbrevs work, but after a few times of getting is expanded to indent-sexp in strings or comments, I just could take it no longer.

Luckily and timely, Artur Malabarba revealed his speed-of-thought-lisp. This package does many things, but the main idea that I liked was that the abbrevs should only expand when in the function position, i.e. the abbrev is:

  • right after opening parenthesis
  • not in a comment
  • not in a string
  • not in the arguments list

With that idea, I've "refactored" my old abbrevs into Abel. It's a minor mode add-on for abbrev-mode. When you activate it, around a hundred abbrevs are added to your abbrev list for emacs-lisp-mode. When you deactivate it, these abbrevs are disabled, and your original abbrev list is restored. It even overrides the mode-line description to Abbrev -> Abel while it's active, thanks to diminish.

So while you should try sotl, which provides many other things, keep abel in mind: it's a simple upgrade to abbrev-mode that binds no bindings and asks no questions.

Here's the current list:

(defcustom abel-abbrevs
  '(
    ;; basics
    ("a" "and")
    ("bp" "boundp")
    ("c" "concat")
    ("fp" "fboundp")
    ("ii" "interactive")
    ("i" "insert")
    ("l" "lambda")
    ("m" "message")
    ("n" "not")
    ("f" "format")
    ("u" "unless")
    ("up" "unwind-protect")
    ("w" "when")
    ("wl" "while")
    ("r" "require")
    ("ci" "call-interactively")
    ("cc" "condition-case")
    ("pg" "plist-get")
    ("sa" "save-excursion")
    ("sr" "save-restriction")
    ("smd" "save-match-data")
    ;; defines
    ("de" "declare-function")
    ("df" "defface")
    ("da" "defmacro")
    ("du" "defcustom")
    ("dv" "defvar")
    ;; everything with char
    ("bc" "backward-char")
    ("scb" "skip-chars-backward")
    ("scf" "skip-chars-forward")
    ("gc" "goto-char")
    ("fc" "forward-char")
    ("dc" "delete-char")
    ("ca" "char-after")
    ;; everything with region
    ("ra" "region-active-p")
    ("rb" "region-beginning")
    ("re" "region-end")
    ("ntr" "narrow-to-region")
    ("dr" "delete-region")
    ("ir" "indent-region")
    ;; error related
    ("ie" "ignore-errors")
    ("e" "error")
    ;; regex match related
    ("la" "looking-at")
    ("lb" "looking-back")
    ("mb" "match-beginning")
    ("me" "match-end")
    ("ms" "match-string")
    ("msn" "match-string-no-properties")
    ("rm" "replace-match")
    ("ro" "regexp-opt")
    ("rq" "regexp-quote")
    ("rr" "replace-regexp-in-string")
    ("rsb" "re-search-backward")
    ("rsf" "re-search-forward")
    ("sf" "search-forward")
    ("sm" "string-match")
    ;; words
    ("fw" "forward-word")
    ("bw" "backward-word")
    ;; lines
    ("eol" "end-of-line")
    ("fl" "forward-line")
    ("lbp" "line-beginning-position")
    ("lep" "line-end-position")
    ("nai" "newline-and-indent")
    ;; buffer
    ("bfn" "buffer-file-name")
    ("bn" "buffer-name")
    ("bs" "buffer-substring")
    ("bsn" "buffer-substring-no-properties")
    ("cb" "current-buffer")
    ("wcb" "with-current-buffer")
    ("wtb" "with-temp-buffer")
    ("efn" "expand-file-name")
    ("ff" "find-file")
    ("ffn" "find-file-noselect")
    ;; window
    ("ow" "other-window")
    ("sw" "selected-window")
    ;; string
    ("ssn" "substring-no-properties")
    ("ss" "substring")
    ("si" "split-string")
    ("se" "string=")
    ("sl" "string<")
    ("sp" "stringp")
    ;; point
    ("pi" "point-min")
    ("pa" "point-max")
    ("p" "point")
    ;; key
    ("gk" "global-set-key")
    ("dk" "define-key")
    ;; rest
    ("ah" "add-hook")
    ("atl" "add-to-list")
    ("bod" "beginning-of-defun")
    ("bol" "beginning-of-line")
    ("dm" "deactivate-mark")
    ("fs" "forward-sexp")
    ("jos" "just-one-space")
    ("kn" "kill-new")
    ("lp" "load-path")
    ("mm" "major-mode")
    ("sic" "self-insert-command")
    ("sn" "symbol-name")
    ("tap" "thing-at-point")
    ("tc" "this-command")
    ("ul" "up-list"))
  "List of (ABBREV EXPANSION) used by `abel'."
  :set (lambda (symbol value)
         "Update abbrevs accoring to `abel-abbrevs'."
         (set symbol value)
         (mapc #'abel-define value))
  :group 'abel)

Re-introducing auto-yasnippet

I wonder, when the code isn't touched in a long time, is it good (no need for changes) or bad (became obsolete)? Let's find out. I'll explain here auto-yasnippet, my second package in MELPA out of more than a dozen currently that saw almost no changes since the initial commit two years ago, and see if you like it.

Short description of yasnippet

YASnippet is a template system for Emacs. It allows you to type an abbreviation and automatically expand it into function templates. Bundled language templates include: C, C++, C#, Perl, Python, Ruby, SQL, LaTeX, HTML, CSS and more.

Snippet step-by-step

Here's one of the snippets that I use for emacs-lisp-mode:

# -*- mode: snippet -*-
# name: function
# key: d
# --
(defun $1 ($2)
$0)
  • The name of the snippet, function is more like a comment than anything else.
  • On the other hand, key is very important: it's what I have to insert in the buffer to get the expansion with M-x yas-expand.
  • Everything after # -- is the snippet body.
  • This particular snippet has two fields, in places of $1 and $2.
  • $0 is where the point will be when the snippet expansion is finished

As I expand, pressing TAB will move from field to field until the expansion is finished.

Snippets are mode-local

Here's the corresponding snippet for clojure-mode:

# -*- mode: snippet -*-
# name: defn
# key: d
# --
(defn $1 [$2]
$0)

As you see, the key here is the same; you're allowed to overload them based on the current major-mode.

Even after quite a few posts, I still keep forgetting Jekyll's syntax for the post header. This is my reminder:

# -*- mode: snippet -*-
# name: post
# key: post
# --
---
layout: post
title: $0
---

Mirrors in snippets

This simple snippet introduces a powerful concept, and an important yasnippet feature that auto-yasnippet uses:

# -*- mode: snippet -*-
#name : class ... { ... }
# --
class $1$2
{
public:
 $1($0)
};

This is a snippet for a class declaration in c++-mode; $1, the name of the class, is mirrored in the name of the constructor. This way, you don't have to enter it twice.

What auto-yasnippet does

All the snippets listed above are pre-configured, persistent and very rarely changed. They are like plain functions in the source code. Each of them needs their own file and so on.

What auto-yasnippet provides are throw-away lambdas, that don't need a file and aren't persistent.

Basic install of auto-yasnippet

To get a usable install, you just need to bind aya-create, which is similar in spirit to M-w (kill-ring-save):

(global-set-key (kbd "H-w") 'aya-create)

and aya-expand, which is similar to C-y (yank):

(global-set-key (kbd "H-y") 'aya-expand)

I also like to bind:

(global-set-key (kbd "C-o") 'aya-open-line)

I'm using C-o to do all of these:

  • expand-abbrev
  • yas-expand and yas-next-field-or-maybe-expand
  • open-line

Example 1: JavaScript

Let's say that you have this code and want to generate more like it:

field1 = document.getElementById("field1");

Let's even assume that you know how auto-yasnippet works and wrote down a slightly modified code beforehand:

field~1 = document.getElementById("field~1");

Here, ~ are meant to represent yasnippet's mirrors, they will be consistent across every expansion. Now you type H-w (aya-create), which works on the current line when there's no region. Your code becomes the initial one without ~, and aya-current variable now holds:

aya-current
;; => "field$1 = document.getElementById(\"field$1\");"

By typing e.g. H-y 2 C-o RET, H-y 3 C-o RET, H-y Final C-o RET you get:

field2 = document.getElementById("field2");
field3 = document.getElementById("field3");
fieldFinal = document.getElementById("fieldFinal");

Note again, that there would be little point to saving this snippet in a file, since the situation where you need to use it may not come up again.

Example 2: Java

Here's the starting code, with fields and mirrors already in place (note one mirror named ~On, one field named ~on and one field named ~true):

class Light~On implements Runnable {
  public Light~On() {}
  public void run() {
    System.out.println("Turning ~on lights");
    light = ~true;
  }
}

Since the code spans multiple lines, as is often the case with Java, you need to mark it with a region before H-w.

Here's the final result:

class LightOn implements Runnable {
  public LightOn() {}
  public void run() {
    System.out.println("Turning on lights");
    light = true;
  }
}
class LightOff implements Runnable {
  public LightOff() {}
  public void run() {
    System.out.println("Turning off lights");
    light = false;
  }
}

No need for AbstractLightFactoryAdapterProvider when we can just copy-paste stuff with auto-yasnippet. In fact, I should probably emphasize that when describing auto-yasnippet: it's just an advanced copy-paste tool.

Example 3: C++

Suppose that I want to generate curl from the grad. I can start with this template:

const Point<3> curl(grad[~2][~1] - grad[~1][~2],

Here, I need less than a line, so region needs to be marked again. The result:

    const Point<3> curl(grad[2][1] - grad[1][2],
                        grad[0][2] - grad[2][0],
                        grad[1][0] - grad[0][1]);

Note how annoying it would be to triple check that the indices match. This time, I just had to check the first line.

Example 4: taking ~ out of the equation

This works only for one-line snippets with a single mirror parameter. In the JavaScript example, you can leave a $ instead of each occurrence of $1, and with the point in place of the last occurrence you call H-w (aya-create). Here, | represents the point:

field$ = document.getElementById("|");

The final result is the same:

field1 = document.getElementById("field1");
field2 = document.getElementById("field2");
field3 = document.getElementById("field3");
fieldFinal = document.getElementById("fieldFinal");

Outro

I hope that this package will lessen your suffering when dealing with verbose programming languages and repetitive text, and that a day will come when repetition is no longer needed and auto-yasnippet will become obsolete.

Combining ace-window and windmove with hydra

I was inspired by Sacha Chua's recent post explaining her window bindings, that combine both ace-window and windmove. So I wrote down an update to Hydra in order to get a similar setup.

Sacha's code

Here it is:

(key-chord-define-global
 "yy"
 (sacha/def-rep-command
  '(nil
    ("<left>" . windmove-left)
    ("<right>" . windmove-right)
    ("<down>" . windmove-down)
    ("<up>" . windmove-up)
    ("y" . other-window)
    ("h" . ace-window)
    ("s" . (lambda () (interactive) (ace-window 4)))
    ("d" . (lambda () (interactive) (ace-window 16))))))

My code

Here's what I've come up with, thanks to the newest code in hydra:

(defun hydra-universal-argument (arg)
  (interactive "P")
  (setq prefix-arg (if (consp arg)
                       (list (* 4 (car arg)))
                     (if (eq arg '-)
                         (list -4)
                       '(4)))))

(defhydra hydra-window (global-map "C-M-o")
  "window"
  ("h" windmove-left "left")
  ("j" windmove-down "down")
  ("k" windmove-up "up")
  ("l" windmove-right "right")
  ("a" ace-window "ace")
  ("u" hydra-universal-argument "universal")
  ("s" (lambda () (interactive) (ace-window 4)) "swap")
  ("d" (lambda () (interactive) (ace-window 16)) "delete")
  ("o"))

(key-chord-define-global "yy" 'hydra-window/body)

The new code should already be available in MELPA. I'll update the code in GNU ELPA soon, when I make sure that there were no bugs introduced by the change.

If anyone wants to see how the defhydra macro expands, you can check out hydra-test.el. I just added a Travis CI setup, so if you're interested in starting to test your Elisp code, you can have a very simple example.

How the defined Hydra works

With this setup:

  • to swap two windows (i.e. call C-u ace-window), I can do any of:

    • C-M-o s
    • C-M-o ua
    • yys
    • yyua
  • to delete one window (i.e. call C-u C-u ace-window), any of:

    • C-M-o d
    • C-M-o uua
    • yyd
    • yyuua
  • to move one window down, two windows right, and one window up:

    • C-M-o jllk
    • yyjllk

Although every other shortcut except the Hydra heads will vanquish the Hydra, sometimes I have nothing on my mind that needs doing. For that case, as you can see above, I enter o in its own list without a function, so that o will dismiss the Hydra without doing anything.