@@ -159,7 +159,7 @@ This is a safety measure to prevent infinite loops."
159
159
160
160
(narrow-to-region (max beg (window-start ))
161
161
(min end (window-end ))))
162
-
162
+
163
163
; ; Advanced motion collection with better error handling
164
164
(let* ((motion-name (if (symbolp func) (symbol-name func) " unknown" ))
165
165
; ; More fine-grained motion classification
@@ -168,7 +168,7 @@ This is a safety measure to prevent infinite loops."
168
168
((string-match-p " line\\ |paragraph" motion-name) 'line )
169
169
((string-match-p " word\\ |char\\ |sentence" motion-name) 'char )
170
170
(t 'unknown )))
171
- (direction
171
+ (direction
172
172
(cond
173
173
((string-match-p " previous\\ |backward\\ |up" motion-name) 'backward )
174
174
((string-match-p " next\\ |forward\\ |down" motion-name) 'forward )
@@ -178,100 +178,100 @@ This is a safety measure to prevent infinite loops."
178
178
(prev-point nil )
179
179
(stalled-count 0 )
180
180
(iteration-count 0 ))
181
-
181
+
182
182
(while (and (< iteration-count evilem-max-iterations)
183
183
(< stalled-count 3 ) ; ; Break after too many failures
184
184
(ignore-errors
185
185
(setq this-command func
186
186
last-command func)
187
-
187
+
188
188
; ; Execute the motion command
189
189
(let ((pre-pos (point )))
190
190
; ; Run the motion function
191
191
(call-interactively func)
192
-
192
+
193
193
; ; Check if we're making progress
194
194
(cond
195
195
; ; Not moving at all
196
196
((= pre-pos (point ))
197
197
(setq stalled-count (1+ stalled-count)))
198
-
198
+
199
199
; ; Moving in the wrong direction
200
- ((and prev-point
200
+ ((and prev-point
201
201
(not (eq direction 'unknown ))
202
202
(or (and (eq direction 'backward ) (> (point ) prev-point))
203
203
(and (eq direction 'forward ) (< (point ) prev-point))))
204
204
(setq stalled-count (1+ stalled-count)))
205
-
205
+
206
206
; ; Otherwise, we're moving well
207
207
(t (setq stalled-count 0 ))))
208
-
208
+
209
209
; ; Handle invisible text properties and overlays
210
210
(when (and (not include-invisible)
211
211
(or (invisible-p (point )) ; ; Check text properties too
212
212
(let ((ovs (overlays-at (point ))))
213
- (seq-some (lambda (ov )
213
+ (seq-some (lambda (ov )
214
214
(overlay-get ov 'invisible ))
215
215
ovs))))
216
- ; ; Skip over the invisible area in the appropriate direction
216
+ ; ; Skip over the invisible area efficiently
217
217
(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
240
240
(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
+
244
244
; ; Rerun the motion for consistency
245
245
(call-interactively func)))
246
-
246
+
247
247
; ; Efficiently track position visit counts using the hash table
248
248
(let ((pos-hash (point )))
249
- (puthash pos-hash
249
+ (puthash pos-hash
250
250
(1+ (gethash pos-hash seen-positions 0 ))
251
251
seen-positions)
252
252
; ; If we've seen this position too many times, stop
253
253
(when (> (gethash pos-hash seen-positions) 2 )
254
254
(setq stalled-count 3 )))
255
-
255
+
256
256
; ; Return t to continue the loop
257
257
t )
258
-
258
+
259
259
; ; Check that the new position is unique
260
260
(progn
261
261
(setq point (cons (point ) (get-buffer-window )))
262
262
(not (member point points))))
263
-
263
+
264
264
; ; Record this position and advance counters
265
265
(push point points)
266
266
(setq prev-point (point ))
267
267
(setq iteration-count (1+ iteration-count)))))))
268
-
268
+
269
269
; ; Handle non-function case (list of functions)
270
270
(setq points (cl-remove-duplicates
271
271
(cl-mapcan (lambda (f )
272
272
(evilem--collect f scope all-windows))
273
273
func))))
274
-
274
+
275
275
; ; Return the sorted points
276
276
(funcall (or collect-postprocess
277
277
#'evilem--default-collect-postprocess )
@@ -630,4 +630,4 @@ This is a safety measure to prevent infinite loops."
630
630
(define-key evilem-map " +" #'evilem-motion-next-line-first-non-blank )
631
631
632
632
(provide 'evil-easymotion )
633
- ; ;; evil-easymotion.el ends here
633
+ ; ;; evil-easymotion.el ends here
0 commit comments