Storax

Soon to be a major emacs mode.

Consistent avy colors

Avy is a very cool package to quickly jump around in Emacs. It marks candidates with a sequence of letters. Pressing the letters will make the cursor jump to the position. It's similar to ace-jump but uses mostly buttons on the home row. One issue I had was quickly identifing the first key to press. Avy uses a different color for each key in the sequence. But depending on the sequence lenght the color of the first key changes. The last key has always the same color. This is exactly the opposite of what I wanted. To change the behavior is somewhat ugly. You have to override avy--overlay-at-full.

The fix reverses the face selection order so it's consistent and indepedent of the sequence lenght. Here is the code that's used by the official avy package:

(dotimes (i len)
      (set-text-properties (- len i 1) (- len i)
                           `(face ,(nth i avy-lead-faces))
                           str))

It produces the following colors: /assets/blog/2016/05/01/consistent-avy-colors/avy-colors-wrong.png

Here is the fixed code:

(dotimes (i len)
      (set-text-properties (- len i 1) (- len i)
                           `(face ,(nth (- len i) avy-lead-faces))
                           str))

And here it is in action: /assets/blog/2016/05/01/consistent-avy-colors/avy-colors-fixed.png

As you can see, sequences with one letter start with the same letter than sequences with muliple letters. Especially when two candidates are close together and overlap, this helps to identify the sequence start.

You can either advice the function or simply override it. Here is the complete code including the fix:

(defun avy--overlay-at-full (path leaf)
  "Create an overlay with PATH at LEAF.
PATH is a list of keys from tree root to LEAF.
LEAF is normally ((BEG . END) . WND)."
  (let* ((path (mapcar #'avy--key-to-char path))
         (str (propertize
               (apply #'string (reverse path))
               'face 'avy-lead-face))
         (len (length path))
         (beg (avy-candidate-beg leaf))
         (wnd (cdr leaf))
         end)
    (dotimes (i len)
      (set-text-properties (- len i 1) (- len i)
                           `(face ,(nth (- len i) avy-lead-faces))
                           str))
    (when (eq avy-style 'de-bruijn)
      (setq str (concat
                 (propertize avy-current-path
                             'face 'avy-lead-face-1)
                 str))
      (setq len (length str)))
    (with-selected-window wnd
      (save-excursion
        (goto-char beg)
        (let* ((lep (if (bound-and-true-p visual-line-mode)
                        (save-excursion
                          (end-of-visual-line)
                          (point))
                      (line-end-position)))
               (len-and-str (avy--update-offset-and-str len str lep)))
          (setq len (car len-and-str))
          (setq str (cdr len-and-str))
          (setq end (if (= beg lep)
                        (1+ beg)
                      (min (+ beg
                              (if (eq (char-after) ?\t)
                                  1
                                len))
                           lep)))
          (when (and (bound-and-true-p visual-line-mode)
                     (> len (- end beg)))
            (setq len (- end beg))
            (let ((old-str (apply #'string (reverse path))))
              (setq str
                    (substring
                     (propertize
                      old-str
                      'face
                      (if (= (length old-str) 1)
                          'avy-lead-face
                        'avy-lead-face-0))
                     0 len)))))))
    (avy--overlay
     str beg end wnd
     (lambda (str old-str)
       (cond ((string= old-str "\n")
              (concat str "\n"))
             ((string= old-str "\t")
              (concat str (make-string (max (- tab-width len) 0) ?\ )))
             (t
              ;; add padding for wide-width character
              (if (eq (string-width old-str) 2)
                  (concat str " ")
                str)))))))

Comments

comments powered by Disqus