Skip to content

Commit 7f5b734

Browse files
committed
fix: handle invisible text properties
1 parent df9dcb7 commit 7f5b734

File tree

1 file changed

+44
-44
lines changed

1 file changed

+44
-44
lines changed

evil-easymotion.el

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ This is a safety measure to prevent infinite loops."
159159

160160
(narrow-to-region (max beg (window-start))
161161
(min end (window-end))))
162-
162+
163163
;; Advanced motion collection with better error handling
164164
(let* ((motion-name (if (symbolp func) (symbol-name func) "unknown"))
165165
;; More fine-grained motion classification
@@ -168,7 +168,7 @@ This is a safety measure to prevent infinite loops."
168168
((string-match-p "line\\|paragraph" motion-name) 'line)
169169
((string-match-p "word\\|char\\|sentence" motion-name) 'char)
170170
(t 'unknown)))
171-
(direction
171+
(direction
172172
(cond
173173
((string-match-p "previous\\|backward\\|up" motion-name) 'backward)
174174
((string-match-p "next\\|forward\\|down" motion-name) 'forward)
@@ -178,100 +178,100 @@ This is a safety measure to prevent infinite loops."
178178
(prev-point nil)
179179
(stalled-count 0)
180180
(iteration-count 0))
181-
181+
182182
(while (and (< iteration-count evilem-max-iterations)
183183
(< stalled-count 3) ;; Break after too many failures
184184
(ignore-errors
185185
(setq this-command func
186186
last-command func)
187-
187+
188188
;; Execute the motion command
189189
(let ((pre-pos (point)))
190190
;; Run the motion function
191191
(call-interactively func)
192-
192+
193193
;; Check if we're making progress
194194
(cond
195195
;; Not moving at all
196196
((= pre-pos (point))
197197
(setq stalled-count (1+ stalled-count)))
198-
198+
199199
;; Moving in the wrong direction
200-
((and prev-point
200+
((and prev-point
201201
(not (eq direction 'unknown))
202202
(or (and (eq direction 'backward) (> (point) prev-point))
203203
(and (eq direction 'forward) (< (point) prev-point))))
204204
(setq stalled-count (1+ stalled-count)))
205-
205+
206206
;; Otherwise, we're moving well
207207
(t (setq stalled-count 0))))
208-
208+
209209
;; Handle invisible text properties and overlays
210210
(when (and (not include-invisible)
211211
(or (invisible-p (point)) ;; Check text properties too
212212
(let ((ovs (overlays-at (point))))
213-
(seq-some (lambda (ov)
213+
(seq-some (lambda (ov)
214214
(overlay-get ov 'invisible))
215215
ovs))))
216-
;; Skip over the invisible area in the appropriate direction
216+
;; Skip over the invisible area efficiently
217217
(let* ((pos (point))
218-
;; Find extent of invisibility
219-
(invisible-beg pos)
220-
(invisible-end pos)
221-
;; Find overlays that might cause invisibility
222-
(overlays (overlays-at pos)))
223-
224-
;; Process text properties first (they're often faster)
225-
(while (and (> invisible-beg (point-min))
226-
(invisible-p (1- invisible-beg)))
227-
(setq invisible-beg (1- invisible-beg)))
228-
229-
(while (and (< invisible-end (point-max))
230-
(invisible-p (1+ invisible-end)))
231-
(setq invisible-end (1+ invisible-end)))
232-
233-
;; Then check overlays to see if they extend the invisible region
234-
(dolist (ov overlays)
235-
(when (overlay-get ov 'invisible)
236-
(setq invisible-beg (min invisible-beg (overlay-start ov))
237-
invisible-end (max invisible-end (overlay-end ov)))))
238-
239-
;; Now jump past the invisible region based on direction
218+
(next-change nil)
219+
(prev-change nil))
220+
221+
;; Find next visible position using text properties
222+
(setq next-change (next-single-property-change pos 'invisible nil (point-max)))
223+
(setq next-change (or next-change (point-max)))
224+
225+
;; Find previous visible position using text properties
226+
(setq prev-change (previous-single-property-change pos 'invisible nil (point-min)))
227+
(setq prev-change (or prev-change (point-min)))
228+
229+
;; Check overlays for invisibility boundaries
230+
(let ((next-ov-change (next-overlay-change pos))
231+
(prev-ov-change (previous-overlay-change pos)))
232+
233+
;; Update boundaries if overlay changes are closer
234+
(when (< next-ov-change next-change)
235+
(setq next-change next-ov-change))
236+
(when (> prev-ov-change prev-change)
237+
(setq prev-change prev-ov-change)))
238+
239+
;; Jump in the appropriate direction
240240
(goto-char (if (eq direction 'backward)
241-
(max (point-min) (1- invisible-beg))
242-
(min (point-max) (1+ invisible-end))))
243-
241+
prev-change
242+
next-change))
243+
244244
;; Rerun the motion for consistency
245245
(call-interactively func)))
246-
246+
247247
;; Efficiently track position visit counts using the hash table
248248
(let ((pos-hash (point)))
249-
(puthash pos-hash
249+
(puthash pos-hash
250250
(1+ (gethash pos-hash seen-positions 0))
251251
seen-positions)
252252
;; If we've seen this position too many times, stop
253253
(when (> (gethash pos-hash seen-positions) 2)
254254
(setq stalled-count 3)))
255-
255+
256256
;; Return t to continue the loop
257257
t)
258-
258+
259259
;; Check that the new position is unique
260260
(progn
261261
(setq point (cons (point) (get-buffer-window)))
262262
(not (member point points))))
263-
263+
264264
;; Record this position and advance counters
265265
(push point points)
266266
(setq prev-point (point))
267267
(setq iteration-count (1+ iteration-count)))))))
268-
268+
269269
;; Handle non-function case (list of functions)
270270
(setq points (cl-remove-duplicates
271271
(cl-mapcan (lambda (f)
272272
(evilem--collect f scope all-windows))
273273
func))))
274-
274+
275275
;; Return the sorted points
276276
(funcall (or collect-postprocess
277277
#'evilem--default-collect-postprocess)
@@ -630,4 +630,4 @@ This is a safety measure to prevent infinite loops."
630630
(define-key evilem-map "+" #'evilem-motion-next-line-first-non-blank)
631631

632632
(provide 'evil-easymotion)
633-
;;; evil-easymotion.el ends here
633+
;;; evil-easymotion.el ends here

0 commit comments

Comments
 (0)