(or emacs irrelevant)

Testing your .emacs sanity

Here's a little snippet that came up as a Stack Overflow answer once:

(defun ora-test-emacs ()
  (interactive)
  (require 'async)
  (async-start
   (lambda () (shell-command-to-string
          "emacs --batch --eval \"
(condition-case e
    (progn
      (load \\\"~/.emacs\\\")
      (message \\\"-OK-\\\"))
  (error
   (message \\\"ERROR!\\\")
   (signal (car e) (cdr e))))\""))
   `(lambda (output)
      (if (string-match "-OK-" output)
          (when ,(called-interactively-p 'any)
            (message "All is well"))
        (switch-to-buffer-other-window "*startup error*")
        (delete-region (point-min) (point-max))
        (insert output)
        (search-backward "ERROR!")))))

This function will quietly run a batch Emacs with your current config to see if it errors out or not.

  • in case that there were no start up errors, it will echo "All is well"
  • when there's an error, it will pop to a *startup error* buffer with the error description

The nice thing about this is that in case of an error you have a functional Emacs to fix that error, since fixing errors with emacs -Q is quite painful.

Another approach could be to just start a new Emacs instance, and close the window in case there isn't an error. So all that the code above does is automate closing the window (sort of, since the window never opens). Still, I think it's pretty cool. And you could attach it to the after-save-hook of your .emacs, or a timer.

You could even configure Emacs to send you an email in case it notices that there will be an error on the next start up. Or add the test to before-save-hook and abort the save in case it results in an error. That's some HAL 9000 level stuff right there:

I'm sorry Dave, I'm afraid I can't do that.

Eclipse theme

I started using Emacs around 2010-2011 when I needed an environment for C++ and LaTeX. The default color theme was horrendous (it still is), and I don't fancy myself a designer, so I just copied a color theme of the thing that I was using previously: Eclipse.

This theme modifies almost nothing except the font lock faces, and looks reasonable while called with -nw, although I don't see why anyone wouldn't want to take advantage of what graphical Emacs has to offer.

Here's a sampler:

eclipse-theme.png

It's shown together with my fork of powerline. I'll try to merge it as a theme eventually, I'm delaying it because powerline isn't very easy to understand/modify.

Eclipse theme should be on MELPA soon, I hope you'll enjoy it. I've tried probably 30 themes on MELPA, but I just can't part with eclipse-theme. I'm guessing that it's a feeling that most theme creators share.

ace-window full path

I just closed a really helpful issue for ace-window. Turns out that there's a plugin for vim called Easymotion that's very similar to ace-jump-mode. And that plugin doesn't highlight the leading chars one by one, but instead gives them all at once. Which is a pretty good idea, since it's more convenient to read the whole path at once and type it in at once rather than:

  • read one char
  • type one char
  • read one more char
  • type one more char
  • ... (maybe more steps)

To turn on the new behavior:

(setq aw-leading-char-style 'path)

Although this will only have an effect once you have more than 10 windows. But this method really improves the functions from avy-jump.el. I've added some more commands and renamed the old ones since yesterday.

avy-jump demos

avi-goto-char-2

Here's how I like to bind avi-goto-char-2:

(global-set-key (kbd "C-'") 'avi-goto-char-2)

And here's the result of C-' bu:

avi-goto-char-2

As you can see, nothing is overwritten by the overlay - it's appended after the search chars. In the screenshot above, I have avi-background at nil; you can set it to t if you want a gray background.

avi-goto-char

After binding avi-goto-char:

(global-set-key (kbd "π") 'avi-goto-char)

Here's the result of π b:

avi-goto-char

avi-goto-line

After binding avi-goto-line:

(global-set-key (kbd "M-g f") 'avi-goto-line)

Here's the result of M-g f:

avi-goto-line

I've also added:

  • avi-copy-line
  • avi-move-line
  • avi-copy-region

These functions use the method of avi-goto-line to copy/move stuff. It might be useful for line-based text.

avi-goto-word-0

Here's the simple definition and the binding:

(defun avi-goto-word-0 ()
  "Jump to a word start in current window."
  (interactive)
  (let* ((avi-keys (number-sequence ?a ?z))
         (candidates (avi--regex-candidates "\\b\\sw")))
    (avi--goto
     (avi--process candidates #'avi--overlay-pre))))
(global-set-key (kbd "M-g e") 'avi-goto-word-0)

There might be quite a lot of candidates for this one, but there's no call to read-char. Here's what happens after M-g e:

avi-goto-word-0

avi-goto-word-1

Here's a version of it that reads one char:

(defun avi-goto-word-1 ()
  "Jump to a word start in current window.
Read one char with which the word should start."
  (interactive)
  (let ((candidates (avi--regex-candidates
                     (concat
                      "\\b"
                      (string (read-char "char: "))))))
    (avi--goto
     (avi--process candidates #'avi--overlay-pre))))
(global-set-key (kbd "M-g w") 'avi-goto-word-1)

Here's what happens after M-g w b:

avi-goto-word-1

Outro

Give the new functions a go and see if you like them. New ideas are welcome, especially pertaining to ripping off vim plugins. I did the vimtutor once, but I have no idea how vim plugins work. But it turns out that I like Easymotion.

ace-window without ace

Today, ace-window is dropping the dependency on ace-jump-mode. Most of the dependency was already dropped in 0.7.0, when I had to fix ace-window to work better with defhydra.

The change will not be user-visible, unless you relied on some customizations of ace-jump-mode to transfer to ace-window. You'll be able to transfer your customizations to similarly named variables.

The reason for the move is that, due to the implementation of ace-jump-mode, it's hard to wrap its calls, since the function exits before any of the red chars are selected by the user. Also, ace-jump-mode uses its own defstructs for candidates while I'd rather have plain lists, but that's a minor issue.

New back end: avy.el

I tried to pinpoint the most generic algorithm that ace-jump-mode implements and wrote it down in avy. Here's the core of the implementation:

(defun avy-subdiv (n b)
  "Distribute N in B terms in a balanced way."
  (let* ((p (1- (floor (log n b))))
         (x1 (expt b p))
         (x2 (* b x1))
         (delta (- n x2))
         (n2 (/ delta (- x2 x1)))
         (n1 (- b n2 1)))
    (append
     (make-list n1 x1)
     (list
      (- n (* n1 x1) (* n2 x2)))
     (make-list n2 x2))))

(defun avy-tree (lst keys)
  "Coerce LST into a balanced tree.
The degree of the tree is the length of KEYS.
KEYS are placed appropriately on internal nodes."
  (let ((len (length keys)))
    (cl-labels
        ((rd (ls)
           (let ((ln (length ls)))
             (if (< ln len)
                 (cl-pairlis
                  keys
                  (mapcar (lambda (x) (cons 'leaf x)) ls))
               (let ((ks (copy-sequence keys))
                     res)
                 (dolist (s (avy-subdiv ln len))
                   (push (cons (pop ks)
                               (if (eq s 1)
                                   (cons 'leaf (pop ls))
                                 (rd (avy-multipop ls s))))
                         res))
                 (nreverse res))))))
      (rd lst))))

The first function, avy-subdiv, tries to split a number in terms of the base in a way that the most leaves have the lowest level:

(avy-subdiv 42 5)
;;=> (5 5 5 5 22)

(avy-subdiv 42 4)
;;=> (4 6 16 16)

(avy-subdiv 42 3)
;;=> (9 9 24)

(avy-subdiv 42 2)
;;=> (16 26)

And here's an example of what avy-tree produces:

(avy-tree
 '("Acid green" "Aero blue" "Almond" "Amaranth"
   "Amber" "Amethyst" "Apple green" "Aqua"
   "Aquamarine" "Auburn" "Aureolin" "Azure"
   "Beige" "Black" "Bronze" "Blue" "Burgundy" "Candy apple red")
 '(1 2 3 4))
;;=>
((1 (1 leaf . "Acid green")
    (2 leaf . "Aero blue")
    (3 leaf . "Almond")
    (4 leaf . "Amaranth"))
 (2 (1 leaf . "Amber")
    (2 leaf . "Amethyst")
    (3 leaf . "Apple green")
    (4 leaf . "Aqua"))
 (3 (1 leaf . "Aquamarine")
    (2 leaf . "Auburn")
    (3 leaf . "Aureolin")
    (4 leaf . "Azure"))
 (4 (1 leaf . "Beige")
    (2 leaf . "Black")
    (3 leaf . "Bronze")
    (4 (1 leaf . "Blue")
       (2 leaf . "Burgundy")
       (3 leaf . "Candy apple red"))))

I think the library turned out to be pretty clean, since it knows nothing of points, buffers or overlays, and imposes no restrictions on the type of leaf items and keys.

Some cool avy-based commands

I'll list them together with the code, so it's easier to see what they do. The basic customizable variable is this one:

(defcustom avy-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)
  "Keys for jumping.")

Note that, while ace-jump-mode has 52 selection chars by default, I prefer to have only the 8 chars on the home row. This means that I'll usually have to go around one level deeper, but the characters are easy to find and press.

avy-jump-double-char

(defun avy-jump-double-char ()
  "Read two chars and jump to them in current window."
  (interactive)
  (avy--process (avy--regex-candidates
                 (string
                  (read-char "char 1: ")
                  (read-char "char 2: "))
                 (selected-window))
                #'avy--goto))

This one will read two chars and then offer avy-selection for the matches. This is a pretty sensible approach for a pool of 8 keys, since usually 3 chars total will be necessary, with the first two being in natural succession.

Here's a screenshot of me typing in a natural two-char sequence "do":

avy-jump-double-char

As you see, with 8 keys, 8 candidates will have depth 1, and another 8 candidates will have depth 2. The sorting preference is for the first candidates to have lower depth.

avy-jump-line

(defun avy-jump-line ()
  "Jump to a line start in current buffer."
  (interactive)
  (let ((we (window-end))
        candidates)
    (save-excursion
      (goto-char (window-start))
      (while (< (point) we)
        (push (cons (point) (selected-window))
              candidates)
        (forward-line 1)))
    (avy--process (nreverse candidates)
                  #'avy--goto
                  t)))

This one is quite nice, since I always have less than 8*8=64 lines in any window. Here's how it looks like:

avy-jump-line

I removed the gray background, since the leading chars are always in an expected position.

avy-jump-isearch

Saving the most clever one for last:

(defun avy-jump-isearch ()
  "Jump to one of the current isearch candidates."
  (interactive)
  (let ((candidates
         (mapcar (lambda (x) (cons (1+ (car x))
                              (cdr x)))
                 (avy--regex-candidates isearch-string))))
    (avy--process candidates #'avy--goto t)
    (isearch-done)))
(define-key isearch-mode-map "'" 'avy-jump-isearch)

I don't mind not being able to isearch-forward-regexp for a single quote without using C-q (quoted-insert). In return, I get the ability to very quickly jump to a search candidate on screen. I like this command the most. In case when there's only one match, it's a faster way to call isearch-done (than C-m). Here's the result of C-s sen ':

avy-jump-isearch

Outro

I've used the new functionality for a few days already, so it shouldn't be fragile. If the newest MELPA version bugs out for you, you can fall back to version 0.7.1 on MELPA Stable and post an issue. Finally, I hope that some people will take advantage of avy.el simplicity and come up with some cool new commands to share with me. Happy hacking!

Hydra-repeat

Did you know that you can repeat the most recent Emacs command with repeat:

Repeat most recently executed command. If REPEAT-ARG is non-nil (interactively, with a prefix argument), supply a prefix argument to that command. Otherwise, give the command the same prefix argument it was given before, if any.

The default binding to repeat is C-x z. You can then continue with just z: C-x zzzzzzzz.

Unfortunately, since defhydra defines new command names based on the ones that you give it, passing repeat as one of the heads will not work. So I've added hydra-repeat that's supposed to work in the same way.

So now, I can define a Hydra like this:

(defhydra hydra-vi ()
  "vi"
  ("h" backward-char)
  ("j" next-line)
  ("k" previous-line)
  ("l" forward-char)
  ("." hydra-repeat))
(global-set-key (kbd "C-v") 'hydra-vi/body)

And if I press C-v 4l.., it will result in movement forward (forward-char) by 4 chars 3 times:

  • first time from 4l
  • other two times, with the same prefix 4, from ..