diff options
| author | Tino Calancha | 2017-08-06 13:46:51 +0900 |
|---|---|---|
| committer | Tino Calancha | 2017-08-06 13:46:51 +0900 |
| commit | cbea38e5c4af5386192fb9a48ef4fca5080d6561 (patch) | |
| tree | e27b535d8e51591be70045289240380d2be6d4d9 | |
| parent | 785a4a1d52fd7da3f3169fda26841341667c1661 (diff) | |
| download | emacs-cbea38e5c4af5386192fb9a48ef4fca5080d6561.tar.gz emacs-cbea38e5c4af5386192fb9a48ef4fca5080d6561.zip | |
dired-do-delete: Allow to delete dirs recursively without prompts
* lisp/dired.el (dired-delete-file): Accept 2 additional answers:
'all', to delete all directories recursively and no prompt anymore.
'quit', to cancel directory deletions (Bug#27940).
Show help message when user inputs 'help'.
(dired-do-flagged-delete): Bind locally dired-recursive-deletes
so that we can overwrite its global value.
Wrapp the loop within a catch '--delete-cancel to catch when
the user abort the directtry deletion.
* doc/emacs/dired.texi (Dired Deletion): Update manual.
* etc/NEWS (Changes in Specialized Modes and Packages in Emacs 26.1):
Announce this change.
| -rw-r--r-- | doc/emacs/dired.texi | 8 | ||||
| -rw-r--r-- | etc/NEWS | 4 | ||||
| -rw-r--r-- | lisp/dired.el | 66 |
3 files changed, 60 insertions, 18 deletions
diff --git a/doc/emacs/dired.texi b/doc/emacs/dired.texi index 150ac8427ab..c1cc2f8cf96 100644 --- a/doc/emacs/dired.texi +++ b/doc/emacs/dired.texi | |||
| @@ -236,6 +236,14 @@ Dired cannot delete directories that are nonempty. If the variable | |||
| 236 | @code{dired-recursive-deletes} is non-@code{nil}, then Dired can | 236 | @code{dired-recursive-deletes} is non-@code{nil}, then Dired can |
| 237 | delete nonempty directories including all their contents. That can | 237 | delete nonempty directories including all their contents. That can |
| 238 | be somewhat risky. | 238 | be somewhat risky. |
| 239 | Even if you have set @code{dired-recursive-deletes} to @code{nil}, | ||
| 240 | you might want sometimes to delete recursively directories | ||
| 241 | without being asked for confirmation for all of them. This is handy | ||
| 242 | when you have marked many directories for deletion and you are very | ||
| 243 | sure that all of them can safely being deleted. For every nonempty | ||
| 244 | directory you are asked for confirmation; if you answer @code{all}, | ||
| 245 | then all the remaining directories will be deleted without more | ||
| 246 | questions. | ||
| 239 | 247 | ||
| 240 | @vindex delete-by-moving-to-trash | 248 | @vindex delete-by-moving-to-trash |
| 241 | If you change the variable @code{delete-by-moving-to-trash} to | 249 | If you change the variable @code{delete-by-moving-to-trash} to |
| @@ -611,6 +611,10 @@ paragraphs, for the purposes of bidirectional display. | |||
| 611 | ** Dired | 611 | ** Dired |
| 612 | 612 | ||
| 613 | +++ | 613 | +++ |
| 614 | *** You can answer 'all' in 'dired-do-delete' to delete recursively all | ||
| 615 | remaining directories without more prompts. | ||
| 616 | |||
| 617 | +++ | ||
| 614 | *** Dired supports wildcards in the directory part of the file names. | 618 | *** Dired supports wildcards in the directory part of the file names. |
| 615 | 619 | ||
| 616 | +++ | 620 | +++ |
diff --git a/lisp/dired.el b/lisp/dired.el index d04bd6fe037..0bad2562eb4 100644 --- a/lisp/dired.el +++ b/lisp/dired.el | |||
| @@ -2981,6 +2981,14 @@ Any other value means to ask for each directory." | |||
| 2981 | ;; Match anything but `.' and `..'. | 2981 | ;; Match anything but `.' and `..'. |
| 2982 | (defvar dired-re-no-dot "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*") | 2982 | (defvar dired-re-no-dot "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*") |
| 2983 | 2983 | ||
| 2984 | (defconst dired-delete-help | ||
| 2985 | "Type: | ||
| 2986 | `yes' to delete recursively the current directory, | ||
| 2987 | `no' to skip to next, | ||
| 2988 | `all' to delete all remaining directories with no more questions, | ||
| 2989 | `quit' to exit, | ||
| 2990 | `help' to show this help message.") | ||
| 2991 | |||
| 2984 | ;; Delete file, possibly delete a directory and all its files. | 2992 | ;; Delete file, possibly delete a directory and all its files. |
| 2985 | ;; This function is useful outside of dired. One could change its name | 2993 | ;; This function is useful outside of dired. One could change its name |
| 2986 | ;; to e.g. recursive-delete-file and put it somewhere else. | 2994 | ;; to e.g. recursive-delete-file and put it somewhere else. |
| @@ -2996,23 +3004,40 @@ its possible values is: | |||
| 2996 | 3004 | ||
| 2997 | TRASH non-nil means to trash the file instead of deleting, provided | 3005 | TRASH non-nil means to trash the file instead of deleting, provided |
| 2998 | `delete-by-moving-to-trash' (which see) is non-nil." | 3006 | `delete-by-moving-to-trash' (which see) is non-nil." |
| 2999 | ;; This test is equivalent to | 3007 | ;; This test is equivalent to |
| 3000 | ;; (and (file-directory-p fn) (not (file-symlink-p fn))) | 3008 | ;; (and (file-directory-p fn) (not (file-symlink-p fn))) |
| 3001 | ;; but more efficient | 3009 | ;; but more efficient |
| 3002 | (if (not (eq t (car (file-attributes file)))) | 3010 | (if (not (eq t (car (file-attributes file)))) |
| 3003 | (delete-file file trash) | 3011 | (delete-file file trash) |
| 3004 | (if (and recursive | 3012 | (let* ((valid-answers (list "yes" "no" "all" "quit" "help")) |
| 3005 | (directory-files file t dired-re-no-dot) ; Not empty. | 3013 | (answer "") |
| 3006 | (or (eq recursive 'always) | 3014 | (input-fn (lambda () |
| 3007 | (yes-or-no-p (format "Recursively %s %s? " | 3015 | (setq answer |
| 3008 | (if (and trash | 3016 | (completing-read |
| 3009 | delete-by-moving-to-trash) | 3017 | (format "Recursively %s %s? [yes, no, all, quit, help] " |
| 3010 | "trash" | 3018 | (if (and trash |
| 3011 | "delete") | 3019 | delete-by-moving-to-trash) |
| 3012 | (dired-make-relative file))))) | 3020 | "trash" |
| 3013 | (if (eq recursive 'top) (setq recursive 'always)) ; Don't ask again. | 3021 | "delete") |
| 3014 | (setq recursive nil)) | 3022 | (dired-make-relative file)) |
| 3015 | (delete-directory file recursive trash))) | 3023 | valid-answers nil t)) |
| 3024 | (when (string= answer "help") | ||
| 3025 | (setq answer "") | ||
| 3026 | (with-help-window "*Help*" | ||
| 3027 | (with-current-buffer "*Help*" (insert dired-delete-help)))) | ||
| 3028 | answer))) | ||
| 3029 | (if (and recursive | ||
| 3030 | (directory-files file t dired-re-no-dot) ; Not empty. | ||
| 3031 | (eq recursive 'always)) | ||
| 3032 | (if (eq recursive 'top) (setq recursive 'always)) ; Don't ask again. | ||
| 3033 | ;; Otherwise prompt user: | ||
| 3034 | (while (string= "" answer) (funcall input-fn)) | ||
| 3035 | (pcase answer | ||
| 3036 | ('"all" (setq recursive 'always dired-recursive-deletes recursive)) | ||
| 3037 | ('"yes" (if (eq recursive 'top) (setq recursive 'always))) | ||
| 3038 | ('"no" (setq recursive nil)) | ||
| 3039 | ('"quit" (keyboard-quit)))) | ||
| 3040 | (delete-directory file recursive trash)))) | ||
| 3016 | 3041 | ||
| 3017 | (defun dired-do-flagged-delete (&optional nomessage) | 3042 | (defun dired-do-flagged-delete (&optional nomessage) |
| 3018 | "In Dired, delete the files flagged for deletion. | 3043 | "In Dired, delete the files flagged for deletion. |
| @@ -3061,6 +3086,9 @@ non-empty directories is allowed." | |||
| 3061 | (let* ((files (mapcar #'car l)) | 3086 | (let* ((files (mapcar #'car l)) |
| 3062 | (count (length l)) | 3087 | (count (length l)) |
| 3063 | (succ 0) | 3088 | (succ 0) |
| 3089 | ;; Bind `dired-recursive-deletes' so that we can change it | ||
| 3090 | ;; locally according with the user answer within `dired-delete-file'. | ||
| 3091 | (dired-recursive-deletes dired-recursive-deletes) | ||
| 3064 | (trashing (and trash delete-by-moving-to-trash))) | 3092 | (trashing (and trash delete-by-moving-to-trash))) |
| 3065 | ;; canonicalize file list for pop up | 3093 | ;; canonicalize file list for pop up |
| 3066 | (setq files (nreverse (mapcar #'dired-make-relative files))) | 3094 | (setq files (nreverse (mapcar #'dired-make-relative files))) |
| @@ -3070,6 +3098,7 @@ non-empty directories is allowed." | |||
| 3070 | (if trashing "Trash" "Delete") | 3098 | (if trashing "Trash" "Delete") |
| 3071 | (dired-mark-prompt arg files))) | 3099 | (dired-mark-prompt arg files))) |
| 3072 | (save-excursion | 3100 | (save-excursion |
| 3101 | (catch '--delete-cancel | ||
| 3073 | (let ((progress-reporter | 3102 | (let ((progress-reporter |
| 3074 | (make-progress-reporter | 3103 | (make-progress-reporter |
| 3075 | (if trashing "Trashing..." "Deleting...") | 3104 | (if trashing "Trashing..." "Deleting...") |
| @@ -3087,6 +3116,7 @@ non-empty directories is allowed." | |||
| 3087 | (dired-fun-in-all-buffers | 3116 | (dired-fun-in-all-buffers |
| 3088 | (file-name-directory fn) (file-name-nondirectory fn) | 3117 | (file-name-directory fn) (file-name-nondirectory fn) |
| 3089 | #'dired-delete-entry fn)) | 3118 | #'dired-delete-entry fn)) |
| 3119 | (quit (throw '--delete-cancel (message "OK, canceled"))) | ||
| 3090 | (error ;; catch errors from failed deletions | 3120 | (error ;; catch errors from failed deletions |
| 3091 | (dired-log "%s\n" err) | 3121 | (dired-log "%s\n" err) |
| 3092 | (setq failures (cons (car (car l)) failures))))) | 3122 | (setq failures (cons (car (car l)) failures))))) |
| @@ -3097,7 +3127,7 @@ non-empty directories is allowed." | |||
| 3097 | (format "%d of %d deletion%s failed" | 3127 | (format "%d of %d deletion%s failed" |
| 3098 | (length failures) count | 3128 | (length failures) count |
| 3099 | (dired-plural-s count)) | 3129 | (dired-plural-s count)) |
| 3100 | failures)))) | 3130 | failures))))) |
| 3101 | (message "(No deletions performed)"))) | 3131 | (message "(No deletions performed)"))) |
| 3102 | (dired-move-to-filename)) | 3132 | (dired-move-to-filename)) |
| 3103 | 3133 | ||