(or emacs irrelevant)

Saving match data in-between Elisp evals

This is a new feature I've added recently to lispy that's useful when debugging regex-related code.

The gist of it is that the match data is a single global object in Emacs. So if you call string-match with your C-x C-e, there's no guarantee that e.g. match-beginning will return the proper thing with another C-x C-e, since any package running in your Emacs could mess with the match data (packages that use timers or post-command hooks etc.).

After getting annoyed by this a few times, I've finally added a fail-safe to e (lispy-eval) and p (lispy-eval-other-window). Here's how it looks like:

(defvar lispy-eval-match-data nil)

(defun lispy--eval-elisp-form (form lexical)
  "Eval FORM and return its value.
If LEXICAL is t, evaluate using lexical scoping.
Restore and save `lispy-eval-match-data' appropriately,
so that no other packages disturb the match data."
  (let (val)
    (fset '\, #'identity)
    (set-match-data lispy-eval-match-data)
    (setq val (eval form lexical))
    (setq lispy-eval-match-data (match-data))
    (fset '\, nil)
    val))

There's also a little dance of ignoring comma operators in the rare case when I want to eval inside a backquoted list. The two functions that you can take away from this exercise are match-data and set-match-data which appropriately return and store a list of integers. Keeping the string separate from the regex match is a neat way to improve performance.

Embedding sexps in Hydra docstrings

In yesterday's post I showed how to embed variable values into the docstring, among other things. Today, I've extended this approach to work with s-expressions. Here's how it looks like:

(defhydra hydra-marked-items (dired-mode-map "")
      "
Number of marked items: %(length (dired-get-marked-files))
"
      ("m" dired-mark "mark"))

This piece of code will remind you how many files you've marked so far each time you press m. By the way, this is the 64th post on the blog; I found out by pressing tm in dired buffer or the _posts directory. Also, I don't think that I've showed passing "" as the keyboard prefix parameter before. Apparently, it works and just translates to this:

(define-key dired-mode-map
    "m" 'hydra-marked-items/dired-mark)

Here's how it looks like: hydra-docstring-sexp

There's no need for a quitting key, it will auto-vanish when you press anything other than m.

Hydra for Buffer-menu

Here's a little code I've made today for Buffer-menu-mode:

(defhydra hydra-buffer-menu (:color pink)
  "
  Mark               Unmark             Actions            Search
-------------------------------------------------------------------------
_m_: mark          _u_: unmark        _x_: execute       _R_: re-isearch
_s_: save          _U_: unmark up     _b_: bury          _I_: isearch
_d_: delete                           _g_: refresh       _O_: multi-occur
_D_: delete up                        _T_: files only: %`Buffer-menu-files-only
_~_: modified
"
  ("m" Buffer-menu-mark nil)
  ("u" Buffer-menu-unmark nil)
  ("U" Buffer-menu-backup-unmark nil)
  ("d" Buffer-menu-delete nil)
  ("D" Buffer-menu-delete-backwards nil)
  ("s" Buffer-menu-save nil)
  ("~" Buffer-menu-not-modified nil)
  ("x" Buffer-menu-execute nil)
  ("b" Buffer-menu-bury nil)
  ("g" revert-buffer nil)
  ("T" Buffer-menu-toggle-files-only nil)
  ("O" Buffer-menu-multi-occur nil :color blue)
  ("I" Buffer-menu-isearch-buffers nil :color blue)
  ("R" Buffer-menu-isearch-buffers-regexp nil :color blue)
  ("c" nil "cancel")
  ("v" Buffer-menu-select "select" :color blue)
  ("o" Buffer-menu-other-window "other-window" :color blue)
  ("q" quit-window "quit" :color blue))

(define-key Buffer-menu-mode-map "." 'hydra-buffer-menu/body)

You can change the color on the top to your taste: either red or pink or amaranth will work. For extensive Hydras I tend to pick pink, since I don't want to quit by accident, while still keeping the non-head bindings. For small ones, red is better. Here's how the result looks like: hydra-buffer-menu

You can install the cow with:

apt-get moo

I didn't list it in the source, since Jekyll would wrap the long lines. The source is already in hydra-examples.el. You only have to:

(require 'hydra-examples)
(define-key Buffer-menu-mode-map "." 'hydra-buffer-menu/body)

I've been hearing some opinions lately that the growing number of Hydra options makes it intimidating or unclear. I hope that's not the majority's feeling and that the gentle repetitiveness of this example proves otherwise.

On the other hand, I've started reading "The Reasoned Schemer" this week. Now that's intimidating.

Two new Hydra colors - pink and teal

Two new colors are being added up to a total of five: red, blue, amaranth, pink and teal. I should carefully restate what they do to avoid confusion.

The three rules of Hydratics

1. A hydra may not injure a human being or, through inaction, allow a human being to come to harm.

Seriously though, see below.

Rule 1: Hydra heads are either red or blue

Once you're in a Hydra state:

  • calling a red head will call the command and continue the state
  • calling a blue head will call the command and stop the state

They may have a reddish or a bluish face that isn't exactly red or blue, but that's what they are underneath. I hope you get what I mean.

Rule 2: red or blue is inherited from the body color

This is merely a convenience, you can still explicitly override each head to be blue or red:

  • if the body is red, amaranth or pink, the heads inherit red
  • if the body is blue or teal, the heads inherit blue

Rule 3:

When you call a binding which isn't a head:

  • amaranth, teal and pink Hydras will intercept it
  • red and blue Hydras will quit and let Emacs execute your binding

Finally, on intercepting a non-head, amaranth and teal will issue a warning and do nothing without quitting. And pink will try to call the intercepted command without quitting. Currently only non-prefix bindings can be called, since I haven't figured out how to do it for prefixes.

A nice table to sum things up

Thanks to @kaushalmodi for pointing me in this direction:

|----------+-----------+-----------------------+-----------------|
| Body     | Head      | Executing NON-HEADS   | Executing HEADS |
| Color    | Inherited |                       |                 |
|          | Color     |                       |                 |
|----------+-----------+-----------------------+-----------------|
| amaranth | red       | Disallow and Continue | Continue        |
| teal     | blue      | Disallow and Continue | Quit            |
| pink     | red       | Allow and Continue    | Continue        |
| red      | red       | Allow and Quit        | Continue        |
| blue     | blue      | Allow and Quit        | Quit            |
|----------+-----------+-----------------------+-----------------|

The extra-awesome Ruby-style Hydra docstrings

Turns out learning Ruby wasn't a complete waste of time, at least I learned about string interpolation. And now I'm sticking it into Elisp packages, first tiny, and now hydra.

How it works:

(defhydra hydra-toggle (:color pink)
  "
_a_ abbrev-mode:       %`abbrev-mode
_d_ debug-on-error:    %`debug-on-error
_f_ auto-fill-mode:    %`auto-fill-function
_g_ golden-ratio-mode: %`golden-ratio-mode
_t_ truncate-lines:    %`truncate-lines
_w_ whitespace-mode:   %`whitespace-mode

"
  ("a" abbrev-mode nil)
  ("d" toggle-debug-on-error nil)
  ("f" auto-fill-mode nil)
  ("g" golden-ratio-mode nil)
  ("t" toggle-truncate-lines nil)
  ("w" whitespace-mode nil)
  ("q" nil "cancel"))

(global-set-key (kbd "C-c C-v") 'hydra-toggle/body)

Here, using e.g. "_a_" translates to "a" with proper face. More interestingly, e.g.

"foobar %`abbrev-mode"

translates roughly to

(format "foobar %S" abbrev-mode)

This means that you actually see the state of the mode that you're changing. The escape syntax was chosen with another intent in mind: because of the backquote, if you have company-mode on, you can complete the symbols while in string.

See how it looks like in action:

hydra-toggle-pink

Small note on pink Hydras

It's useful for instance it the above example, when I don't care about self-inserting, but I still want to do navigation. Basically pink Hydra is the closest thing to an actual minor mode. Thanks to @angelic-sedition for the idea.

Small note on teal Hydras

It provides an interface similar to magit dispatch: pressing appropriate keys does things and pressing the wrong keys issues a warning. The only difference between teal and amaranth is the color inheritance, otherwise they behave exactly the same. This means that if you want a non-quitting Hydra that will end up with more blue heads, start with teal, otherwise, start with amaranth. Thanks to @ffevotte for the idea.

Outro

It feels like things are finally falling into place with this package. I hope that you like the new changes and find new cool uses for the added abilities. Happy hacking!

Reverting nonsense

It happens to me frequently when making a demo, or just experimenting around that I want to revert the buffer to the last saved state. Obviously such a command exists in Emacs, and it's unsurprisingly called revert-buffer:

Replace current buffer text with the text of the visited file on disk. This undoes all changes since the file was visited or saved.

But the poor old revert-buffer isn't bound by default in Emacs. The perfect binding for it is C-x C-r:

(global-set-key
 (kbd "C-x C-r")
 (lambda () (interactive) (revert-buffer nil t)))

I believe the lambda is used to get the "no questions asked" treatment. Anyway, by default Emacs binds C-x C-r to find-file-read-only, which really is a trash-tier command.

Why is find-file-read-only useless?

Because C-x C-q is bound to read-only-mode - a really good command (made even better with wdired and wgrep). So find-file-read-only is just C-x C-f C-x C-q. And I don't ever recall needing to use that, since v (dired-view-file) is almost equivalent if not better.

As a bonus, C-x C-r is mnemonic for "revert".

Auto-reverting

While on the topic, let me mention auto-revert-mode. I have this in my config:

(global-auto-revert-mode 1)

This way, if any opened and saved file was modified outside of Emacs, it will be updated in a short while. I was able to use this to a great advantage when writing the SVG picture for the Xmodmap post:

  • I opened the SVG in the default image mode in one Emacs instance
  • and opened the same document in XML mode in another (mode is toggled with C-c C-c)

With that setup, I was able to see the picture update as I was inputting the XML. Here's some Elisp for XML generation, if you're interested

(defun make-row (row-str ix iy fill)
  (mapconcat
   (lambda (x)
     (format
      "<g><text x=\"%d\" y=\"%d\" style=\"font-size:10px;fill:%s;font-family:Deja Vu Sans Mono\">%s</text></g>"
      (+ ix (* x 30))
      iy
      fill
      (let ((y (elt row-str x)))
        (if (stringp y)
            y
          (make-string 1 y)))))
   (number-sequence 0 (1- (length row-str)))
   "\n"))

(make-row
 "QWERTYUIOP"
 95 140
 "#2b2828")
;; =>

The last statement would generate: Q W E R T Y U I O P.