abo-abo / avy

Jump to things in Emacs tree-style
1.73k stars 110 forks source link

avy-jump without complete paths and overlays on top of the jump target (like in ace-jump) #5

Closed tsdh closed 9 years ago

tsdh commented 9 years ago

I've switched from ace-jump to avy-jump just recently. One major difference is that ace-jump's overlays are displayed on top of the jump target and only one jump character is displayed at a time. With avy-mode, the overlays always show the complete jump character sequence and are displayed right of the jump target.

At least my personal preference (which is not ace-jump biased too much; I started using that only two weeks ago before switching to avy-jump yesterday) is that I like the ace-jump behavior better because the buffer contents won't switch to the right. That is, if you have 5 matches on a line, each requiring a 2-char key sequence to jump to, then the last match has switched 8 chars to the right. With ace-jump, it stays where it has been before. So this "fix target with your eyes and then jump" thingy works better.

abo-abo commented 9 years ago

Isn't that a valid assumption?

No. It's valid sometimes, but the original avy-tree puts no assumption on the structure of the arguments.

For example, in ace-window the type is (pos . window).

tsdh commented 9 years ago

Ok, I see. I could test if the car of a match is a cons or a plain integer to work around this exact issue. But it's not possible to be completely agnostic to the match representation because the algorithm requires the start position and the window in order to figure out if a subpart of the De Bruijn sequence needs to be skipped when there are almost adjacent matches.

abo-abo commented 9 years ago

I've just had a test of the code and it seems to work fine.

You should try to integrate it if you have the time.

My suggestion:

Then just tie avy--generic-jump to use this overlay fn for 'de-bruin:

(defun avy--overlay-debruin (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* ((str (propertize
               (apply #'string (reverse path))
               'face 'avy-lead-face))
         (len (length path))
         (beg (if (consp (car leaf))
                  (caar leaf)
                (car leaf)))
         (wnd (cdr leaf)))
    (when (> (length str) 1)
      (set-text-properties 0 1 '(face avy-lead-face-0) str))
    (with-selected-window wnd
      (save-excursion
        (goto-char beg)
        (let* ((end (min (+ beg len) (line-end-position)))
               (ol (make-overlay
                    beg end
                    (current-buffer)))
               (old-str (buffer-substring beg (1+ beg))))
          (when avy-background
            (setq old-str (propertize
                           old-str 'face 'avy-background-face)))
          (overlay-put ol 'window wnd)
          (overlay-put ol 'category 'avy)
          (overlay-put ol 'display (if (string= old-str "\n")
                                       (concat str "\n")
                                     str))
          (push ol avy--overlays-lead))))))
tsdh commented 9 years ago

@abo-abo Cool, I'm gonna do that as soon as I find some spare time.

Wrt. seq-len, I can easily add an estimate so that we start with the shortest path length that works for the number of matches in case there are no "almost adjacent" overlaps. Of course, it's still possible that seq-len needs to be incremented if there are many such overlaps which don't allow for using all subsequences of the De Brujin seq. But you are right that it's suboptimal to try 1-char sequences if there are 20 matches but only 8 avy-keys.

PythonNut commented 9 years ago

There seems to be a slight bug where the overlays start incorrectly marking decision chars.

Example Jump text

;; This buffer is for notes you don't want to save, and for Lisp evaluation.
;; If you want to create a file, visit that file with C-x C-f,
;; then enter the text in that file's own buffer.

;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;

avy-striping

Other than that, it seems to work perfectly!

There is one other possible difficulty: it's hard to tell how many characters a certain target needs. Of course, you can tell from context (you can scan forward to the end of the cluster and count the number of non decision chars to determine the needed length.)

I'm not entirely sure how to solve this. One way would be to have different color decision chars based on the number of characters left to type. (As far as I can tell, this is the way evil-easymotion does it. They have yellow for single character jumps and red for two character jumps (no idea what happens if they need three characters). Of course this is

I'm convinced that the second isn't much of a problem. (We already have quite a bit of code dedicated to this style). The first is probably also a non-issue, as de-bruijn will probably not come as the default.

tsdh commented 9 years ago

@PythonNut I can reproduce that, but for me all three lines look like your first line of semicolons, e.g., after the first two lead chars, only every second char is shown as a lead char although every char is.

Aside from that, could you please open a separate issue for that? This issue is solved IMHO and already has a gazillion comments completely unrelated to this specific bug.

@abo-abo Please close this one.

abo-abo commented 9 years ago

@abo-abo Please close this one.

It's been closed for weeks now :)

tsdh commented 9 years ago

Ups. ;-)