noctuid / link-hint.el

Pentadactyl-like Link Hinting in Emacs with Avy
GNU General Public License v3.0
160 stars 22 forks source link

Fix *Completions* in Emacs >29 #216

Open mmarshall540 opened 1 year ago

mmarshall540 commented 1 year ago

Related to #215.

Corrects problem caused by change in how Emacs's next-completion command works.

noctuid commented 1 year ago

Thanks for bringing this to my attention. I don't think the fallback bound should be necessary. Is there some case where forward-char is now necessary? If next-completion now just does nothing, I think this should be fine:

(defun link-hint--next-completion-list-candidate (bound)
  "Find the next completion list candidate location.
Only search the range between just after the point and BOUND."
  (let ((start (point)))
    (next-completion 1)
    (let ((point (point)))
      (when (< start point bound)
        point))))

Didn't have a chance to look into it further, but feel free to update the PR with that if it works or let me know where the forward-char is necessary.

mmarshall540 commented 1 year ago

Thanks for the review! I should have commented the code more to explain that.

The scenario requiring forward-char is when completion-show-help has been set to nil in Emacs >29.

In that case, the first character of the first completion-candidate is also the very first character in the *Completions* buffer. So the first time next-completion runs, point's location doesn't change, and it is as if there were no remaining candidates.

Moving point forward by a character ensures that point's value after calling next-completion is always different from start but still distinguishable from bound.

(defun link-hint--next-completion-list-candidate (bound)
  "Find the next completion list candidate location.
Only search the range between just after the point and BOUND."
  (let ((start (point))
        point)
    ;; In Emacs >29 if `completion-show-help' is set to nil, calling
    ;; `next-completion' the first time will not change point's
    ;; location, unless we move it first.
    (forward-char)
    (next-completion 1)
    (setq point (point))
    (when (and
       ;; In Emacs >29, when there are no more completions, point
       ;; returns to start.
       (not (eql start point))
       ;; If this is not the last completion, point will have
       ;; moved > 1 char forward.
       (> (- point start) 1)
       ;; In Emacs <29, when there are no more completions, point
       ;; will have moved past the last completion-candidate.
       (< point bound))
      point)))

Does this look better? I may have over-compensated for the lack of comments in the earlier version.