|
153 | 153 |
|
154 | 154 | (narrow-to-region (max beg (window-start))
|
155 | 155 | (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 | + |
177 | 216 | (setq points (cl-remove-duplicates
|
178 | 217 | (cl-mapcan (lambda (f)
|
179 | 218 | (evilem--collect f scope all-windows))
|
|
0 commit comments