Skip to content

Commit 6b95442

Browse files
committed
fix: avoid infinite loops being stuck in overlays
1 parent f96c2ed commit 6b95442

File tree

1 file changed

+60
-21
lines changed

1 file changed

+60
-21
lines changed

evil-easymotion.el

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -153,27 +153,66 @@
153153

154154
(narrow-to-region (max beg (window-start))
155155
(min end (window-end))))
156-
(while (and (ignore-errors
157-
(setq this-command func
158-
last-command func)
159-
(call-interactively func)
160-
(unless include-invisible
161-
(let ((ov (car (overlays-at (point)))))
162-
(while (and ov (member
163-
'invisible
164-
(overlay-properties ov)))
165-
(goto-char (overlay-end ov))
166-
;; This is a bit of a hack, since we
167-
;; can't guarantee that we will end
168-
;; up at the same point if we start
169-
;; at the end of the invisible
170-
;; region vs. looping through it.
171-
(call-interactively func)
172-
(setq ov (car (overlays-at (point)))))))
173-
t)
174-
(setq point (cons (point) (get-buffer-window)))
175-
(not (member point points))
176-
(push point points))))))
156+
157+
;; Use a robust approach to prevent infinite loops by tracking overlay interactions
158+
(let ((prev-point nil)
159+
(seen-overlays (make-hash-table :test 'eq))
160+
(same-overlay-count 0)
161+
(making-progress t))
162+
163+
(while (and making-progress
164+
(ignore-errors
165+
(setq this-command func
166+
last-command func)
167+
168+
;; Execute the motion command
169+
(call-interactively func)
170+
171+
;; Check if we're in an overlay
172+
(unless include-invisible
173+
(let* ((ov (car (overlays-at (point))))
174+
(overlay-id (and ov (overlay-start ov))))
175+
176+
;; If we're in an overlay and have seen it before
177+
(when (and ov (gethash overlay-id seen-overlays))
178+
;; Calculate if we're getting closer to either edge
179+
(let ((dist-to-start (abs (- (point) (overlay-start ov))))
180+
(dist-to-end (abs (- (point) (overlay-end ov))))
181+
(prev-dist-start (car (gethash overlay-id seen-overlays)))
182+
(prev-dist-end (cdr (gethash overlay-id seen-overlays))))
183+
184+
;; If we're getting closer to either edge, we're making progress
185+
(let ((progress-to-edge (or (< dist-to-start prev-dist-start)
186+
(< dist-to-end prev-dist-end))))
187+
188+
;; If we're not making progress in this overlay
189+
(unless progress-to-edge
190+
(setq same-overlay-count (1+ same-overlay-count))
191+
;; After 2 tries in the same overlay without progress, skip it
192+
(when (>= same-overlay-count 2)
193+
(goto-char (overlay-end ov))
194+
(call-interactively func))))))
195+
196+
;; Record our position in this overlay for next time
197+
(when ov
198+
(puthash overlay-id
199+
(cons (abs (- (point) (overlay-start ov)))
200+
(abs (- (point) (overlay-end ov))))
201+
seen-overlays))))
202+
203+
;; Check if we're making progress at all (point has moved)
204+
(setq making-progress (or (not prev-point)
205+
(/= prev-point (point))))
206+
t)
207+
208+
;; Create the position key and check for duplicates
209+
(setq point (cons (point) (get-buffer-window)))
210+
(not (member point points)))
211+
212+
;; Record this position
213+
(push point points)
214+
(setq prev-point (point)))))))
215+
177216
(setq points (cl-remove-duplicates
178217
(cl-mapcan (lambda (f)
179218
(evilem--collect f scope all-windows))

0 commit comments

Comments
 (0)