diff options
Diffstat (limited to 'lisp/dired-aux.el')
-rw-r--r-- | lisp/dired-aux.el | 501 |
1 files changed, 324 insertions, 177 deletions
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index 0a3ce149474..a2ce3083cfe 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el @@ -264,7 +264,8 @@ the string of command switches used as the third argument of `diff'." (read-string "Options for diff: " (if (stringp diff-switches) diff-switches - (mapconcat #'identity diff-switches " "))))))) + (mapconcat #'identity diff-switches " ")))))) + dired-mode) (let ((current (dired-get-filename t))) (when (or (equal (expand-file-name file) (expand-file-name current)) @@ -290,7 +291,8 @@ With prefix arg, prompt for argument SWITCHES which is options for `diff'." (if (stringp diff-switches) diff-switches (mapconcat #'identity diff-switches " ")))) - nil)) + nil) + dired-mode) (diff-backup (dired-get-filename) switches)) ;;;###autoload @@ -336,7 +338,8 @@ only in the active region if `dired-mark-region' is non-nil." (read-directory-name (format "Compare %s with: " (dired-current-directory)) target-dir target-dir t))) - (read-from-minibuffer "Mark if (lisp expr or RET): " nil nil t nil "nil"))) + (read-from-minibuffer "Mark if (lisp expr or RET): " nil nil t nil "nil")) + dired-mode) (let* ((dir1 (dired-current-directory)) (file-alist1 (dired-files-attributes dir1)) (file-alist2 (dired-files-attributes dir2)) @@ -480,7 +483,8 @@ List has a form of (file-name full-file-name (attribute-list))." (if failures (dired-log-summary (format "%s: error" operation) - nil)))) + nil))) + (dired-post-do-command)) ;;;###autoload (defun dired-do-chmod (&optional arg) @@ -496,7 +500,7 @@ Alternatively, see the man page for \"chmod(1)\". Note that on MS-Windows only the `w' (write) bit is meaningful: resetting it makes the file read-only. Changing any other bit has no effect on MS-Windows." - (interactive "P") + (interactive "P" dired-mode) (let* ((files (dired-get-marked-files t arg nil nil t)) ;; The source of default file attributes is the file at point. (default-file (dired-get-filename t t)) @@ -531,7 +535,8 @@ has no effect on MS-Windows." (if num-modes num-modes (file-modes-symbolic-to-number modes (file-modes file 'nofollow))) 'nofollow)) - (dired-do-redisplay arg))) + (dired-do-redisplay arg)) + (dired-post-do-command)) ;;;###autoload (defun dired-do-chgrp (&optional arg) @@ -539,7 +544,7 @@ has no effect on MS-Windows." Type \\<minibuffer-local-completion-map>\\[next-history-element] \ to pull the file attributes of the file at point into the minibuffer." - (interactive "P") + (interactive "P" dired-mode) (if (and (memq system-type '(ms-dos windows-nt)) (not (file-remote-p default-directory))) (error "chgrp not supported on this system")) @@ -551,7 +556,7 @@ into the minibuffer." Type \\<minibuffer-local-completion-map>\\[next-history-element] \ to pull the file attributes of the file at point into the minibuffer." - (interactive "P") + (interactive "P" dired-mode) (if (and (memq system-type '(ms-dos windows-nt)) (not (file-remote-p default-directory))) (error "chown not supported on this system")) @@ -564,7 +569,7 @@ This calls touch. Type Type \\<minibuffer-local-completion-map>\\[next-history-element] \ to pull the file attributes of the file at point into the minibuffer." - (interactive "P") + (interactive "P" dired-mode) (dired-do-chxxx "Timestamp" dired-touch-program 'touch arg)) ;; Process all the files in FILES in batches of a convenient size, @@ -616,7 +621,7 @@ into the minibuffer." "Print the marked (or next ARG) files. Uses the shell command coming from variables `lpr-command' and `lpr-switches' as default." - (interactive "P") + (interactive "P" dired-mode) (require 'lpr) (let* ((file-list (dired-get-marked-files t arg nil nil t)) (lpr-switches @@ -634,7 +639,8 @@ Uses the shell command coming from variables `lpr-command' and lpr-switches)) " ") 'print arg file-list))) - (dired-run-shell-command (dired-shell-stuff-it command file-list nil)))) + (dired-run-shell-command (dired-shell-stuff-it command file-list nil))) + (dired-post-do-command)) (defun dired-mark-read-string (prompt initial op-symbol arg files &optional default-value collection) @@ -671,7 +677,7 @@ Negative prefix arg KEEP overrides `kept-old-versions' with KEEP made positive. To clear the flags on these files, you can use \\[dired-flag-backup-files] with a prefix argument." - (interactive "P") + (interactive "P" dired-mode) (setq keep (if keep (prefix-numeric-value keep) dired-kept-versions)) (let ((early-retention (if (< keep 0) (- keep) kept-old-versions)) (late-retention (if (<= keep 0) dired-kept-versions keep)) @@ -757,22 +763,6 @@ with a prefix argument." ;;; Shell commands -(declare-function mailcap-file-default-commands "mailcap" (files)) - -(defvar dired-aux-files) - -(defun dired-minibuffer-default-add-shell-commands () - "Return a list of all commands associated with current Dired files. -This function is used to add all related commands retrieved by `mailcap' -to the end of the list of defaults just after the default value." - (interactive) - (let ((commands (and (boundp 'dired-aux-files) - (require 'mailcap nil t) - (mailcap-file-default-commands dired-aux-files)))) - (if (listp minibuffer-default) - (append minibuffer-default commands) - (cons minibuffer-default commands)))) - ;; This is an extra function so that you can redefine it, e.g., to use gmhist. (defun dired-read-shell-command (prompt arg files) "Read a Dired shell command. @@ -783,14 +773,9 @@ file names. The result is used as the prompt. Use `dired-guess-shell-command' to offer a smarter default choice of shell command." - (minibuffer-with-setup-hook - (lambda () - (setq-local dired-aux-files files) - (setq-local minibuffer-default-add-function - #'dired-minibuffer-default-add-shell-commands)) - (setq prompt (format prompt (dired-mark-prompt arg files))) - (dired-mark-pop-up nil 'shell files - 'dired-guess-shell-command prompt files))) + (setq prompt (format prompt (dired-mark-prompt arg files))) + (dired-mark-pop-up nil 'shell files + 'dired-guess-shell-command prompt files)) ;;;###autoload (defcustom dired-confirm-shell-command t @@ -825,7 +810,8 @@ Commands that are run asynchronously do not accept user input." ;; Want to give feedback whether this file or marked files are used: (dired-read-shell-command "& on %s: " current-prefix-arg files) current-prefix-arg - files))) + files)) + dired-mode) (unless (string-match-p "&[ \t]*\\'" command) (setq command (concat command " &"))) (dired-do-shell-command command arg file-list)) @@ -892,7 +878,8 @@ Also see the `dired-confirm-shell-command' variable." ;; Want to give feedback whether this file or marked files are used: (dired-read-shell-command "! on %s: " current-prefix-arg files) current-prefix-arg - files))) + files)) + dired-mode) (let* ((on-each (not (dired--star-or-qmark-p command "*" 'keep))) (no-subst (not (dired--star-or-qmark-p command "?" 'keep))) (confirmations nil) @@ -918,7 +905,8 @@ Also see the `dired-confirm-shell-command' variable." nil file-list) ;; execute the shell command (dired-run-shell-command - (dired-shell-stuff-it command file-list nil arg))))))) + (dired-shell-stuff-it command file-list nil arg)))))) + (dired-post-do-command)) ;; Might use {,} for bash or csh: (defvar dired-mark-prefix "" @@ -957,7 +945,7 @@ Also see the `dired-confirm-shell-command' variable." ;; "&" instead. (cmd-sep (if (and (or (not w32-shell) file-remote) (not parallel-in-background)) - ";" "&")) + "; " "& ")) (stuff-it (if (dired--star-or-qmark-p command nil 'keep) (lambda (x) @@ -988,7 +976,7 @@ Also see the `dired-confirm-shell-command' variable." ;; Add 'wait' to force those POSIX shells to wait until ;; all commands finish. (or (and parallel-in-background (not w32-shell) - " &wait") + " & wait") ""))) (t (let ((files (mapconcat #'shell-quote-argument @@ -1000,9 +988,9 @@ Also see the `dired-confirm-shell-command' variable." ;; Be consistent in how we treat inputs to commands -- do ;; the same here as in the `on-each' case. (if (and in-background (not w32-shell)) - " &wait" + " & wait" ""))))) - (or (and in-background "&") + (or (and in-background "& ") "")))) ;; This is an extra function so that it can be redefined by ange-ftp. @@ -1307,7 +1295,7 @@ See `dired-guess-shell-alist-user'." ;;;###autoload (defun dired-guess-shell-command (prompt files) "Ask user with PROMPT for a shell command, guessing a default from FILES." - (let ((default (dired-guess-default files)) + (let ((default (shell-command-guess files)) default-list val) (if (null default) ;; Nothing to guess @@ -1331,6 +1319,125 @@ See `dired-guess-shell-alist-user'." ;; If we got a return, then return default. (if (equal val "") default val)))) +(defcustom shell-command-guess-functions + '(shell-command-guess-dired) + "List of functions that guess shell commands for files. +Each function receives a list of commands and a list of file names +and should return the same list of commands with changes +such as added new commands." + :type '(repeat + (choice (function-item shell-command-guess-dired) + (function-item shell-command-guess-mailcap) + (function-item shell-command-guess-xdg) + (function-item shell-command-guess-open) + (function :tag "Custom function"))) + :group 'dired + :version "30.1") + +(defun shell-command-guess (files) + "Return a list of shell commands, appropriate for FILES. +The list is populated by calling functions from +`shell-command-guess-functions'. Each function receives the list +of commands and the list of file names and returns the same list +after adding own commands to the composite list." + (let ((commands nil)) + (run-hook-wrapped 'shell-command-guess-functions + (lambda (fun) + (setq commands (funcall fun commands files)) + nil)) + commands)) + +(defun shell-command-guess-dired (commands files) + "Populate COMMANDS using `dired-guess-default'." + (append (ensure-list (dired-guess-default files)) commands)) + +(declare-function mailcap-file-default-commands "mailcap" (files)) + +(defun shell-command-guess-mailcap (commands files) + "Populate COMMANDS by MIME types of FILES." + (require 'mailcap) + (append (mailcap-file-default-commands files) commands)) + +(declare-function xdg-mime-apps "xdg" (mime)) +(declare-function xdg-desktop-read-file "xdg" (filename &optional group)) + +(defun shell-command-guess-xdg (commands files) + "Populate COMMANDS by XDG configuration for FILES." + (require 'xdg) + (let* ((xdg-mime (when (executable-find "xdg-mime") + (string-trim-right + (shell-command-to-string + (concat "xdg-mime query filetype " + (shell-quote-argument (car files))))))) + (xdg-mime-apps (unless (string-empty-p xdg-mime) + (xdg-mime-apps xdg-mime))) + (xdg-commands + (mapcar (lambda (desktop) + (setq desktop (xdg-desktop-read-file desktop)) + (propertize + (replace-regexp-in-string + " .*" "" (gethash "Exec" desktop)) + 'name (gethash "Name" desktop))) + xdg-mime-apps))) + (append xdg-commands commands))) + +(defcustom shell-command-guess-open + (cond + ((executable-find "xdg-open") + "xdg-open") + ((memq system-type '(gnu/linux darwin)) + "open") + ((memq system-type '(windows-nt ms-dos)) + "start") + ((eq system-type 'cygwin) + "cygstart") + ((executable-find "run-mailcap") + "run-mailcap")) + "A shell command to open a file externally." + :type 'string + :group 'dired + :version "30.1") + +(defun shell-command-guess-open (commands _files) + "Populate COMMANDS by the `open' command." + (append (ensure-list shell-command-guess-open) commands)) + +(declare-function w32-shell-execute "w32fns.c") + +(defun dired-do-open (&optional arg) + "Open all marked (or next ARG) files using an external program. +This \"opens\" the file(s) using the external command that is most +appropriate for the file(s) according to the system conventions. +If files are marked, run the command on each marked file. Otherwise, +run it on the next ARG files, or on the file at mouse-click, or on the +file at point. The appropriate command to \"open\" a file on each +system is determined by `shell-command-guess-open'." + (interactive "P" dired-mode) + (let ((files (if (mouse-event-p last-nonmenu-event) + (save-excursion + (mouse-set-point last-nonmenu-event) + (dired-get-marked-files nil arg)) + (dired-get-marked-files nil arg))) + (command shell-command-guess-open)) + (when (and (memq system-type '(windows-nt)) + (equal command "start")) + (setq command "open")) + (when command + (dolist (file files) + (cond + ((memq system-type '(gnu/linux)) + (call-process command nil 0 nil file)) + ((memq system-type '(ms-dos)) + (shell-command (concat command " " (shell-quote-argument file)))) + ((memq system-type '(windows-nt)) + (w32-shell-execute command (convert-standard-filename file))) + ((memq system-type '(cygwin)) + (call-process command nil nil nil file)) + ((memq system-type '(darwin)) + (start-process (concat command " " file) nil command file)) + (t + (error "Open not supported on this system"))))))) + ;;; Commands that delete or redisplay part of the dired buffer @@ -1338,7 +1445,7 @@ See `dired-guess-shell-alist-user'." "Kill the current line (not the files). With a prefix argument, kill that many lines starting with the current line. (A negative argument kills backward.)" - (interactive "P") + (interactive "P" dired-mode) (setq arg (prefix-numeric-value arg)) (let (buffer-read-only file) (while (/= 0 arg) @@ -1360,7 +1467,7 @@ With a prefix argument, kill that many lines starting with the current line. (defun dired-do-kill-lines (&optional arg fmt init-count) "Remove all marked lines, or the next ARG lines. The files or directories on those lines are _not_ deleted. Only the -Dired listing is affected. To restore the removals, use `\\[revert-buffer]'. +Dired listing is affected. To restore the removals, use \\[revert-buffer]. With a numeric prefix arg, remove that many lines going forward, starting with the current line. (A negative prefix arg removes lines @@ -1379,7 +1486,7 @@ lines removed by this invocation, for the reporting message. A FMT of \"\" will suppress the messaging." ;; Returns count of killed lines. - (interactive "P") + (interactive "P" dired-mode) (if arg (if (dired-get-subdir) (dired-kill-subdir) @@ -1516,7 +1623,7 @@ output file. %i path(s) are relative, while %o is absolute.") Prompt for the archive file name. Choose the archiving command based on the archive file-name extension and `dired-compress-files-alist'." - (interactive) + (interactive nil dired-mode) (let* ((in-files (dired-get-marked-files nil nil nil nil t)) (out-file (expand-file-name (read-file-name "Compress to: "))) (rule (cl-find-if @@ -1547,7 +1654,8 @@ and `dired-compress-files-alist'." "Compressed %d files to %s" (length in-files)) (length in-files) - (file-name-nondirectory out-file))))))) + (file-name-nondirectory out-file)))))) + (dired-post-do-command)) ;;;###autoload (defun dired-compress-file (file) @@ -1753,7 +1861,7 @@ the directory and all of its subdirectories, recursively, into a .tar.gz archive. If invoked on a .tar.gz or a .tgz or a .zip or a .7z archive, uncompress and unpack all the files in the archive." - (interactive "P") + (interactive "P" dired-mode) (dired-map-over-marks-check #'dired-compress arg 'compress t)) @@ -1782,7 +1890,7 @@ uncompress and unpack all the files in the archive." ;;;###autoload (defun dired-do-byte-compile (&optional arg) "Byte compile marked (or next ARG) Emacs Lisp files." - (interactive "P") + (interactive "P" dired-mode) (dired-map-over-marks-check #'dired-byte-compile arg 'byte-compile t)) (defun dired-load () @@ -1799,7 +1907,7 @@ uncompress and unpack all the files in the archive." ;;;###autoload (defun dired-do-load (&optional arg) "Load the marked (or next ARG) Emacs Lisp files." - (interactive "P") + (interactive "P" dired-mode) (dired-map-over-marks-check #'dired-load arg 'load t)) ;;;###autoload @@ -1816,7 +1924,7 @@ You can reset all subdirectory switches to the default using \\<dired-mode-map>\\[dired-reset-subdir-switches]. See Info node `(emacs)Subdir switches' for more details." ;; Moves point if the next ARG files are redisplayed. - (interactive "P\np") + (interactive "P\np" dired-mode) (if (and test-for-subdir (dired-get-subdir)) (let* ((dir (dired-get-subdir)) (switches (cdr (assoc-string dir dired-switches-alist)))) @@ -1846,7 +1954,7 @@ See Info node `(emacs)Subdir switches' for more details." (defun dired-reset-subdir-switches () "Set `dired-switches-alist' to nil and revert Dired buffer." - (interactive) + (interactive nil dired-mode) (setq dired-switches-alist nil) (revert-buffer)) @@ -2475,86 +2583,97 @@ Optional arg HOW-TO determines how to treat the target. For any other return value, TARGET is treated as a directory." (or op1 (setq op1 operation)) - (let* ((fn-list (dired-get-marked-files nil arg nil nil t)) - (rfn-list (mapcar #'dired-make-relative fn-list)) - (dired-one-file ; fluid variable inside dired-create-files - (and (consp fn-list) (null (cdr fn-list)) (car fn-list))) - (target-dir (dired-dwim-target-directory)) - (default (and dired-one-file - (not dired-dwim-target) ; Bug#25609 - (expand-file-name (file-name-nondirectory (car fn-list)) - target-dir))) - (defaults (dired-dwim-target-defaults fn-list target-dir)) - (target (expand-file-name ; fluid variable inside dired-create-files - (minibuffer-with-setup-hook - (lambda () - (setq-local minibuffer-default-add-function nil) - (setq minibuffer-default defaults)) - (dired-mark-read-file-name - (format "%s %%s %s: " - (if dired-one-file op1 operation) - (if (memq op-symbol '(symlink hardlink)) - ;; Linking operations create links - ;; from the prompted file name; the - ;; other operations copy (etc) to the - ;; prompted file name. - "from" "to")) - target-dir op-symbol arg rfn-list default)))) - (into-dir - (progn - (when - (or - (not dired-one-file) - (and dired-create-destination-dirs-on-trailing-dirsep - (directory-name-p target))) - (dired-maybe-create-dirs target)) - (cond ((null how-to) - ;; Allow users to change the letter case of - ;; a directory on a case-insensitive - ;; filesystem. If we don't test these - ;; conditions up front, file-directory-p - ;; below will return t on a case-insensitive - ;; filesystem, and Emacs will try to move - ;; foo -> foo/foo, which fails. - (if (and (file-name-case-insensitive-p (car fn-list)) - (eq op-symbol 'move) - dired-one-file - (string= (downcase - (expand-file-name (car fn-list))) - (downcase - (expand-file-name target))) - (not (string= - (file-name-nondirectory (car fn-list)) - (file-name-nondirectory target)))) - nil - (file-directory-p target))) - ((eq how-to t) nil) - (t (funcall how-to target)))))) - (if (and (consp into-dir) (functionp (car into-dir))) - (apply (car into-dir) operation rfn-list fn-list target (cdr into-dir)) - (if (not (or dired-one-file into-dir)) - (error "Marked %s: target must be a directory: %s" operation target)) - (if (and (not (file-directory-p (car fn-list))) - (not (file-directory-p target)) - (directory-name-p target)) - (error "%s: Target directory does not exist: %s" operation target)) - ;; rename-file bombs when moving directories unless we do this: - (or into-dir (setq target (directory-file-name target))) - (prog1 - (dired-create-files - file-creator operation fn-list - (if into-dir ; target is a directory - ;; This function uses fluid variable target when called - ;; inside dired-create-files: - (lambda (from) - (expand-file-name (file-name-nondirectory from) target)) - (lambda (_from) target)) - marker-char) - (when (or (eq dired-do-revert-buffer t) - (and (functionp dired-do-revert-buffer) - (funcall dired-do-revert-buffer target))) - (dired-fun-in-all-buffers (file-name-directory target) nil - #'revert-buffer)))))) + (let ((ret nil)) + (let* ((fn-list (dired-get-marked-files nil arg nil nil t)) + (rfn-list (mapcar #'dired-make-relative fn-list)) + (dired-one-file ; fluid variable inside dired-create-files + (and (consp fn-list) (null (cdr fn-list)) (car fn-list))) + (target-dir (dired-dwim-target-directory)) + (default (and dired-one-file + (not dired-dwim-target) ; Bug#25609 + (expand-file-name (file-name-nondirectory + (car fn-list)) + target-dir))) + (defaults (dired-dwim-target-defaults fn-list target-dir)) + (target (expand-file-name ; fluid variable inside dired-create-files + (minibuffer-with-setup-hook + (lambda () + (setq-local minibuffer-default-add-function nil) + (setq minibuffer-default defaults)) + (dired-mark-read-file-name + (format "%s %%s %s: " + (if dired-one-file op1 operation) + (if (memq op-symbol '(symlink hardlink)) + ;; Linking operations create links + ;; from the prompted file name; the + ;; other operations copy (etc) to the + ;; prompted file name. + "from" "to")) + target-dir op-symbol arg rfn-list default)))) + (into-dir + (progn + (when + (or + (not dired-one-file) + (and dired-create-destination-dirs-on-trailing-dirsep + (directory-name-p target))) + (dired-maybe-create-dirs target)) + (cond ((null how-to) + ;; Allow users to change the letter case of + ;; a directory on a case-insensitive + ;; filesystem. If we don't test these + ;; conditions up front, file-directory-p + ;; below will return t on a case-insensitive + ;; filesystem, and Emacs will try to move + ;; foo -> foo/foo, which fails. + (if (and (file-name-case-insensitive-p (car fn-list)) + (eq op-symbol 'move) + dired-one-file + (string= (downcase + (expand-file-name (car fn-list))) + (downcase + (expand-file-name target))) + (not (string= + (file-name-nondirectory (car fn-list)) + (file-name-nondirectory target)))) + nil + (file-directory-p target))) + ((eq how-to t) nil) + (t (funcall how-to target)))))) + (setq ret + (if (and (consp into-dir) (functionp (car into-dir))) + (apply (car into-dir) operation rfn-list fn-list target + (cdr into-dir)) + (if (not (or dired-one-file into-dir)) + (error "Marked %s: target must be a directory: %s" + operation target)) + (if (and (not (file-directory-p (car fn-list))) + (not (file-directory-p target)) + (directory-name-p target)) + (error "%s: Target directory does not exist: %s" + operation target)) + ;; rename-file bombs when moving directories unless we do this: + (or into-dir (setq target (directory-file-name target))) + (prog1 + (dired-create-files + file-creator operation fn-list + (if into-dir ; target is a directory + ;; This function uses fluid variable target when called + ;; inside dired-create-files: + (lambda (from) + (expand-file-name (file-name-nondirectory from) + target)) + (lambda (_from) target)) + marker-char) + (when (or (eq dired-do-revert-buffer t) + (and (functionp dired-do-revert-buffer) + (funcall dired-do-revert-buffer target))) + (dired-fun-in-all-buffers (file-name-directory target) nil + #'revert-buffer)))))) + (dired-post-do-command) + ;; The return value isn't very well defined but is used by + ;; `dired-test-bug30624'. + ret)) ;; Read arguments for a marked-files command that wants a file name, ;; perhaps popping up the list of marked files. @@ -2675,7 +2794,8 @@ FILENAME is a full file name." Parent directories of DIRECTORY are created as needed. If DIRECTORY already exists, signal an error." (interactive - (list (read-file-name "Create directory: " (dired-current-directory)))) + (list (read-file-name "Create directory: " (dired-current-directory))) + dired-mode) (let* ((expanded (directory-file-name (expand-file-name directory))) new) (if (file-exists-p expanded) @@ -2692,7 +2812,7 @@ If DIRECTORY already exists, signal an error." Add a new entry for the new file in the Dired buffer. Parent directories of FILE are created as needed. If FILE already exists, signal an error." - (interactive (list (read-file-name "Create empty file: "))) + (interactive (list (read-file-name "Create empty file: ")) dired-mode) (let* ((expanded (expand-file-name file)) new) (if (file-exists-p expanded) @@ -2751,11 +2871,11 @@ similar to the \"-d\" option for the \"cp\" shell command. But if `dired-copy-dereference' is non-nil, the symbolic links are dereferenced and then copied, similar to the \"-L\" option for the \"cp\" shell command. If ARG is a cons with -element 4 (`\\[universal-argument]'), the inverted value of +element 4 (\\[universal-argument]), the inverted value of `dired-copy-dereference' will be used. Also see `dired-do-revert-buffer'." - (interactive "P") + (interactive "P" dired-mode) (let ((dired-recursive-copies dired-recursive-copies) (dired-copy-dereference (if (equal arg '(4)) (not dired-copy-dereference) @@ -2778,7 +2898,7 @@ suggested for the target directory depends on the value of For relative symlinks, use \\[dired-do-relsymlink]. Also see `dired-do-revert-buffer'." - (interactive "P") + (interactive "P" dired-mode) (dired-do-create-files 'symlink #'make-symbolic-link "Symlink" arg dired-keep-marker-symlink)) @@ -2795,7 +2915,7 @@ not absolute ones like foo -> /ugly/file/name/that/may/change/any/day/bar/foo For absolute symlinks, use \\[dired-do-symlink]." - (interactive "P") + (interactive "P" dired-mode) (dired-do-create-files 'relsymlink #'dired-make-relative-symlink "RelSymLink" arg dired-keep-marker-relsymlink)) @@ -2860,7 +2980,7 @@ suggested for the target directory depends on the value of `dired-dwim-target', which see. Also see `dired-do-revert-buffer'." - (interactive "P") + (interactive "P" dired-mode) (dired-do-create-files 'hardlink #'dired-hardlink "Hardlink" arg dired-keep-marker-hardlink)) @@ -2881,13 +3001,14 @@ The default suggested for the target directory depends on the value of `dired-dwim-target', which see. Also see `dired-do-revert-buffer'." - (interactive "P") + (interactive "P" dired-mode) (when (seq-find (lambda (file) (member (file-name-nondirectory file) '("." ".."))) (dired-get-marked-files nil arg)) (user-error "Can't rename \".\" or \"..\" files")) (dired-do-create-files 'move #'dired-rename-file - "Move" arg dired-keep-marker-rename "Rename")) + "Move" arg dired-keep-marker-rename "Rename") + (dired-post-do-command)) ;;; Operate on files matched by regexp @@ -2979,7 +3100,7 @@ REGEXP defaults to the last regexp used. With a zero prefix arg, renaming by regexp affects the absolute file name. Normally, only the non-directory part of the file name is used and changed." - (interactive (dired-mark-read-regexp "Rename")) + (interactive (dired-mark-read-regexp "Rename") dired-mode) (dired-do-create-files-regexp #'dired-rename-file "Rename" arg regexp newname whole-name dired-keep-marker-rename)) @@ -2988,7 +3109,7 @@ Normally, only the non-directory part of the file name is used and changed." (defun dired-do-copy-regexp (regexp newname &optional arg whole-name) "Copy selected files whose names match REGEXP to NEWNAME. See function `dired-do-rename-regexp' for more info." - (interactive (dired-mark-read-regexp "Copy")) + (interactive (dired-mark-read-regexp "Copy") dired-mode) (let ((dired-recursive-copies nil)) ; No recursive copies. (dired-do-create-files-regexp #'dired-copy-file @@ -2999,7 +3120,7 @@ See function `dired-do-rename-regexp' for more info." (defun dired-do-hardlink-regexp (regexp newname &optional arg whole-name) "Hardlink selected files whose names match REGEXP to NEWNAME. See function `dired-do-rename-regexp' for more info." - (interactive (dired-mark-read-regexp "HardLink")) + (interactive (dired-mark-read-regexp "HardLink") dired-mode) (dired-do-create-files-regexp #'add-name-to-file "HardLink" arg regexp newname whole-name dired-keep-marker-hardlink)) @@ -3008,7 +3129,7 @@ See function `dired-do-rename-regexp' for more info." (defun dired-do-symlink-regexp (regexp newname &optional arg whole-name) "Symlink selected files whose names match REGEXP to NEWNAME. See function `dired-do-rename-regexp' for more info." - (interactive (dired-mark-read-regexp "SymLink")) + (interactive (dired-mark-read-regexp "SymLink") dired-mode) (dired-do-create-files-regexp #'make-symbolic-link "SymLink" arg regexp newname whole-name dired-keep-marker-symlink)) @@ -3018,7 +3139,7 @@ See function `dired-do-rename-regexp' for more info." "RelSymlink all marked files containing REGEXP to NEWNAME. See functions `dired-do-rename-regexp' and `dired-do-relsymlink' for more info." - (interactive (dired-mark-read-regexp "RelSymLink")) + (interactive (dired-mark-read-regexp "RelSymLink") dired-mode) (dired-do-create-files-regexp #'dired-make-relative-symlink "RelSymLink" arg regexp newname whole-name dired-keep-marker-relsymlink)) @@ -3063,13 +3184,13 @@ Type \\`SPC' or \\`y' to %s one file, \\`DEL' or \\`n' to skip to next, ;;;###autoload (defun dired-upcase (&optional arg) "Rename all marked (or next ARG) files to upper case." - (interactive "P") + (interactive "P" dired-mode) (dired-rename-non-directory #'upcase "Rename upcase" arg)) ;;;###autoload (defun dired-downcase (&optional arg) "Rename all marked (or next ARG) files to lower case." - (interactive "P") + (interactive "P" dired-mode) (dired-rename-non-directory #'downcase "Rename downcase" arg)) @@ -3097,7 +3218,8 @@ See Info node `(emacs)Subdir switches' for more details." (list (dired-get-filename) (if current-prefix-arg (read-string "Switches for listing: " - (or dired-subdir-switches dired-actual-switches))))) + (or dired-subdir-switches dired-actual-switches)))) + dired-mode) (let ((opoint (point))) ;; We don't need a marker for opoint as the subdir is always ;; inserted *after* opoint. @@ -3129,7 +3251,8 @@ This function takes some pains to conform to `ls -lR' output." (list (dired-get-filename) (if current-prefix-arg (read-string "Switches for listing: " - (or dired-subdir-switches dired-actual-switches))))) + (or dired-subdir-switches dired-actual-switches)))) + dired-mode) (setq dirname (file-name-as-directory (expand-file-name dirname))) (or no-error-if-not-dir-p (file-directory-p dirname) @@ -3206,7 +3329,7 @@ In interactive use, the command prompts for DIRNAME. When called from Lisp, if REMEMBER-MARKS is non-nil, return an alist of marked files. If KILL-ROOT is non-nil, kill DIRNAME as well." - (interactive "DKill tree below directory: \ni\nP") + (interactive "DKill tree below directory: \ni\nP" dired-mode) (setq dirname (file-name-as-directory (expand-file-name dirname))) (let ((s-alist dired-subdir-alist) dir m-alist) (while s-alist @@ -3360,7 +3483,8 @@ When called interactively and not on a subdir line, go to this subdir's line." (list (if current-prefix-arg (prefix-numeric-value current-prefix-arg) ;; if on subdir start already, don't stay there! - (if (dired-get-subdir) 1 0)))) + (if (dired-get-subdir) 1 0))) + dired-mode) (dired-next-subdir (- arg) no-error-if-not-found no-skip)) ;;;###autoload @@ -3393,7 +3517,7 @@ The next char is \\n." "Mark all files except `.' and `..' in current subdirectory. If the Dired buffer shows multiple directories, this command marks the files listed in the subdirectory that point is in." - (interactive) + (interactive nil dired-mode) (let ((p-min (dired-subdir-min))) (dired-mark-files-in-region p-min (dired-subdir-max)))) @@ -3402,7 +3526,7 @@ marks the files listed in the subdirectory that point is in." "Remove all lines of current subdirectory. Lower levels are unaffected." ;; With optional REMEMBER-MARKS, return a mark-alist. - (interactive) + (interactive nil dired-mode) (let* ((beg (dired-subdir-min)) (end (dired-subdir-max)) (modflag (buffer-modified-p)) @@ -3429,7 +3553,7 @@ Lower levels are unaffected." ;;;###autoload (defun dired-tree-up (arg) "Go up ARG levels in the Dired tree." - (interactive "p") + (interactive "p" dired-mode) (let ((dir (dired-current-directory))) (while (>= arg 1) (setq arg (1- arg) @@ -3441,7 +3565,7 @@ Lower levels are unaffected." ;;;###autoload (defun dired-tree-down () "Go down in the Dired tree." - (interactive) + (interactive nil dired-mode) (let ((dir (dired-current-directory)) ; has slash pos case-fold-search) ; filenames are case sensitive (let ((rest (reverse dired-subdir-alist)) elt) @@ -3463,7 +3587,7 @@ Lower levels are unaffected." "Hide or unhide the current subdirectory and move to next directory. Optional prefix arg is a repeat factor. Use \\[dired-hide-all] to (un)hide all directories." - (interactive "p") + (interactive "p" dired-mode) (with-silent-modifications (while (>= (setq arg (1- arg)) 0) (let* ((cur-dir (dired-current-directory)) @@ -3484,7 +3608,7 @@ Use \\[dired-hide-all] to (un)hide all directories." "Hide all subdirectories, leaving only their header lines. If there is already something hidden, make everything visible again. Use \\[dired-hide-subdir] to (un)hide a particular subdirectory." - (interactive "P") + (interactive "P" dired-mode) (with-silent-modifications (if (text-property-any (point-min) (point-max) 'invisible 'dired) (dired--unhide (point-min) (point-max)) @@ -3560,14 +3684,14 @@ It's intended to override the default search function." ;;;###autoload (defun dired-isearch-filenames () "Search for a string using Isearch only in file names in the Dired buffer." - (interactive) + (interactive nil dired-mode) (setq-local dired-isearch-filenames t) (isearch-forward nil t)) ;;;###autoload (defun dired-isearch-filenames-regexp () "Search for a regexp using Isearch only in file names in the Dired buffer." - (interactive) + (interactive nil dired-mode) (setq-local dired-isearch-filenames t) (isearch-forward-regexp nil t)) @@ -3577,16 +3701,20 @@ It's intended to override the default search function." ;;;###autoload (defun dired-do-isearch () "Search for a string through all marked files using Isearch." - (interactive) + (interactive nil dired-mode) (multi-isearch-files - (dired-get-marked-files nil nil #'dired-nondirectory-p nil t))) + (prog1 (dired-get-marked-files nil nil + #'dired-nondirectory-p nil t) + (dired-post-do-command)))) ;;;###autoload (defun dired-do-isearch-regexp () "Search for a regexp through all marked files using Isearch." - (interactive) - (multi-isearch-files-regexp - (dired-get-marked-files nil nil 'dired-nondirectory-p nil t))) + (interactive nil dired-mode) + (prog1 (multi-isearch-files-regexp + (dired-get-marked-files nil nil + 'dired-nondirectory-p nil t)) + (dired-post-do-command))) (declare-function fileloop-continue "fileloop" ()) @@ -3598,11 +3726,12 @@ If no files are marked, search through the file under point. Stops when a match is found. To continue searching for next match, use command \\[fileloop-continue]." - (interactive "sSearch marked files (regexp): ") + (interactive "sSearch marked files (regexp): " dired-mode) (fileloop-initialize-search regexp (dired-get-marked-files nil nil #'dired-nondirectory-p) 'default) + (dired-post-do-command) (fileloop-continue)) ;;;###autoload @@ -3620,18 +3749,36 @@ resume the query replace with the command \\[fileloop-continue]." (let ((common (query-replace-read-args "Query replace regexp in marked files" t t))) - (list (nth 0 common) (nth 1 common) (nth 2 common)))) + (list (nth 0 common) (nth 1 common) (nth 2 common))) + dired-mode) (dolist (file (dired-get-marked-files nil nil #'dired-nondirectory-p nil t)) (let ((buffer (get-file-buffer file))) (if (and buffer (with-current-buffer buffer buffer-read-only)) (error "File `%s' is visited read-only" file)))) + (dired-post-do-command) (fileloop-initialize-replace from to (dired-get-marked-files nil nil #'dired-nondirectory-p) (if (equal from (downcase from)) nil 'default) delimited) (fileloop-continue)) +;;;###autoload +(defun dired-do-replace-regexp-as-diff (from to &optional delimited) + "Do `replace-regexp' of FROM with TO as diff, on all marked files. +Third arg DELIMITED (prefix arg) means replace only word-delimited matches. +The replacements are displayed in the buffer *replace-diff* that +you can later apply as a patch after reviewing the changes." + (interactive + (let ((common + (query-replace-read-args + "Replace regexp as diff in marked files" t t))) + (list (nth 0 common) (nth 1 common) (nth 2 common)))) + (dired-post-do-command) + (multi-file-replace-regexp-as-diff + (dired-get-marked-files nil nil #'dired-nondirectory-p) + from to delimited)) + (declare-function xref-query-replace-in-results "xref") (declare-function project--files-in-directory "project") @@ -3647,7 +3794,7 @@ matching `grep-find-ignored-directories' are skipped in the marked directories. REGEXP should use constructs supported by your local `grep' command." - (interactive "sSearch marked files (regexp): ") + (interactive "sSearch marked files (regexp): " dired-mode) (require 'grep) (require 'xref) (defvar grep-find-ignored-files) @@ -3675,6 +3822,7 @@ REGEXP should use constructs supported by your local `grep' command." (user-error "No matches for: %s" regexp)) (message "Searching...done") xrefs)))) + (dired-post-do-command) (xref-show-xrefs fetcher nil))) ;;;###autoload @@ -3701,7 +3849,8 @@ function works." (let ((common (query-replace-read-args "Query replace regexp in marked files" t t))) - (list (nth 0 common) (nth 1 common)))) + (list (nth 0 common) (nth 1 common))) + dired-mode) (require 'xref) (defvar xref-show-xrefs-function) (defvar xref-auto-jump-to-first-xref) @@ -3723,14 +3872,14 @@ function works." If you give a prefix argument \\[universal-argument] to this command, and FILE is a symbolic link, then the command will print the type of the target of the link instead." - (interactive (list (dired-get-filename t) current-prefix-arg)) + (interactive (list (dired-get-filename t) current-prefix-arg) dired-mode) (let (process-file-side-effects) (with-temp-buffer (if deref-symlinks (process-file "file" nil t t "-L" "--" file) (process-file "file" nil t t "--" file)) (when (bolp) - (backward-delete-char 1)) + (delete-char -1)) (message "%s" (buffer-string))))) @@ -3756,7 +3905,7 @@ the same files/directories marked in the VC-Directory buffer that were marked in the original Dired buffer. If the current directory doesn't belong to a VCS repository, prompt for a repository directory. In this case, the VERBOSE argument is ignored." - (interactive "P") + (interactive "P" dired-mode) (let* ((marked-files (dired-get-marked-files nil nil nil nil t)) (mark-files @@ -3767,6 +3916,7 @@ case, the VERBOSE argument is ignored." (file-name-as-directory file) file)) marked-files)))) + (dired-post-do-command) (if mark-files (let ((transient-hook (make-symbol "vc-dir-mark-files"))) (fset transient-hook @@ -3804,9 +3954,6 @@ case, the VERBOSE argument is ignored." (setq model (vc-checkout-model backend only-files-list)))) (list backend files only-files-list state model))) -(define-obsolete-function-alias 'minibuffer-default-add-dired-shell-commands - #'dired-minibuffer-default-add-shell-commands "29.1") - (provide 'dired-aux) |