summaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
authorJuri Linkov <juri@linkov.net>2024-01-25 19:38:03 +0200
committerJuri Linkov <juri@linkov.net>2024-01-25 19:38:03 +0200
commitb07265f8eed74dda792e13062baae94319484b4b (patch)
tree2fa985819833125548ae37a65a2d8678bf6f4b10 /lisp
parenta8cfe3bda8b8008071818d6ac5e5103002ed6c08 (diff)
downloademacs-b07265f8eed74dda792e13062baae94319484b4b.tar.gz
emacs-b07265f8eed74dda792e13062baae94319484b4b.tar.bz2
emacs-b07265f8eed74dda792e13062baae94319484b4b.zip
* lisp/dired.el (dired--move-to-next-line): Improve to avoid an infinite loop.
An infinite loop is possible in a directory without files and subdirectories, where even lines with . and .. are omitted, so 'dired-between-files' is true for all Dired lines. For the case of dired-movement-style=cycle a guard is triggered when the loop wraps twice while the value 'arg' is not changing. And for the case of dired-movement-style=bounded a guard is triggered when point doesn't move while trying to go back to the last non-empty line.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/dired.el29
1 files changed, 21 insertions, 8 deletions
diff --git a/lisp/dired.el b/lisp/dired.el
index 69fa15dde73..cef93ab757c 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -2817,7 +2817,9 @@ is controlled by `dired-movement-style'."
(dired--trivial-next-line arg)))
(defun dired--move-to-next-line (arg jumpfun)
- (let ((old-position (progn
+ (let ((wrapped nil)
+ (old-arg arg)
+ (old-position (progn
;; It's always true that we should move
;; to the filename when possible.
(dired-move-to-filename)
@@ -2832,16 +2834,27 @@ is controlled by `dired-movement-style'."
(when (= old-position (point))
;; Now point is at beginning/end of movable area,
;; but it still wants to move farther.
- (if (eq dired-movement-style 'cycle)
- ;; `cycle': go to the other end.
+ (cond
+ ;; `cycle': go to the other end.
+ ((eq dired-movement-style 'cycle)
+ ;; Argument not changing on the second wrap
+ ;; means infinite loop with no files found.
+ (if (and wrapped (eq old-arg arg))
+ (setq arg 0)
(goto-char (if (cl-plusp moving-down)
(point-min)
- (point-max)))
- ;; `bounded': go back to the last non-empty line.
- (while (dired-between-files)
- (funcall jumpfun (- moving-down)))
+ (point-max))))
+ (setq wrapped t))
+ ;; `bounded': go back to the last non-empty line.
+ ((eq dired-movement-style 'bounded)
+ (while (and (dired-between-files) (not (zerop arg)))
+ (funcall jumpfun (- moving-down))
+ ;; Point not moving means infinite loop.
+ (if (= old-position (point))
+ (setq arg 0)
+ (setq old-position (point))))
;; Encountered a boundary, so let's stop movement.
- (setq arg moving-down)))
+ (setq arg (if (dired-between-files) 0 moving-down)))))
(unless (dired-between-files)
;; Has moved to a non-empty line. This movement does
;; make sense.