New function read-char-choice for reading a restricted set of chars.
[bpt/emacs.git] / lisp / dired-aux.el
index bf87ce7..fda40b4 100644 (file)
@@ -1,11 +1,13 @@
-;;; dired-aux.el --- less commonly used parts of dired  -*-byte-compile-dynamic: t;-*-
+;;; dired-aux.el --- less commonly used parts of dired
 
 ;; Copyright (C) 1985, 1986, 1992, 1994, 1998, 2000, 2001, 2002, 2003,
-;;   2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;;   2004, 2005, 2006, 2007, 2008, 2009, 2010
+;;   Free Software Foundation, Inc.
 
 ;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>.
 ;; Maintainer: FSF
 ;; Keywords: files
+;; Package: emacs
 
 ;; This file is part of GNU Emacs.
 
@@ -59,31 +61,45 @@ The prompted-for file is the first file given to `diff'.
 With prefix arg, prompt for second argument SWITCHES,
 which is options for `diff'."
   (interactive
-   (let ((current (dired-get-filename t))
-        (default (if (mark t)
-                     (save-excursion (goto-char (mark t))
-                                     (dired-get-filename t t)))))
-     (if (or (equal default current)
-            (and (not (equal (dired-dwim-target-directory)
-                             (dired-current-directory)))
-                 (not mark-active)))
-        (setq default nil))
+   (let* ((current (dired-get-filename t))
+         ;; Get the file at the mark.
+         (file-at-mark (if (mark t)
+                           (save-excursion (goto-char (mark t))
+                                           (dired-get-filename t t))))
+         ;; Use it as default if it's not the same as the current file,
+         ;; and the target dir is the current dir or the mark is active.
+         (default (if (and (not (equal file-at-mark current))
+                           (or (equal (dired-dwim-target-directory)
+                                      (dired-current-directory))
+                               mark-active))
+                      file-at-mark))
+         (target-dir (if default
+                         (dired-current-directory)
+                       (dired-dwim-target-directory)))
+         (defaults (dired-dwim-target-defaults (list current) target-dir)))
      (require 'diff)
-     (list (read-file-name (format "Diff %s with%s: "
-                                  current
-                                  (if default
-                                      (concat " (default " default ")")
-                                    ""))
-                          (if default
-                              (dired-current-directory)
-                            (dired-dwim-target-directory))
-                          default t)
-          (if current-prefix-arg
-              (read-string "Options for diff: "
-                           (if (stringp diff-switches)
-                               diff-switches
-                             (mapconcat 'identity diff-switches " ")))))))
-  (diff file (dired-get-filename t) switches))
+     (list
+      (minibuffer-with-setup-hook
+         (lambda ()
+           (set (make-local-variable 'minibuffer-default-add-function) nil)
+           (setq minibuffer-default defaults))
+       (read-file-name
+        (format "Diff %s with%s: " current
+                (if default (format " (default %s)" default) ""))
+        target-dir default t))
+      (if current-prefix-arg
+         (read-string "Options for diff: "
+                      (if (stringp diff-switches)
+                          diff-switches
+                        (mapconcat 'identity diff-switches " ")))))))
+  (let ((current (dired-get-filename t)))
+    (when (or (equal (expand-file-name file)
+                    (expand-file-name current))
+             (and (file-directory-p file)
+                  (equal (expand-file-name current file)
+                         (expand-file-name current))))
+      (error "Attempt to compare the file to itself"))
+    (diff file current switches)))
 
 ;;;###autoload
 (defun dired-backup-diff (&optional switches)
@@ -128,11 +144,17 @@ Examples of PREDICATE:
     (not (and (= (nth 2 fa1) (nth 2 fa2))   - mark files with different UID
               (= (nth 3 fa1) (nth 3 fa2))))   and GID."
   (interactive
-   (list (read-directory-name (format "Compare %s with: "
-                                     (dired-current-directory))
-                             (dired-dwim-target-directory)
-                             (dired-dwim-target-directory))
-         (read-from-minibuffer "Mark if (lisp expr or RET): " nil nil t nil "nil")))
+   (list
+    (let* ((target-dir (dired-dwim-target-directory))
+          (defaults (dired-dwim-target-defaults nil target-dir)))
+      (minibuffer-with-setup-hook
+         (lambda ()
+           (set (make-local-variable 'minibuffer-default-add-function) nil)
+           (setq minibuffer-default defaults))
+       (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")))
   (let* ((dir1 (dired-current-directory))
          (file-alist1 (dired-files-attributes dir1))
          (file-alist2 (dired-files-attributes dir2))
@@ -196,7 +218,7 @@ condition.  Two file items are considered to match if they are equal
 
 (defun dired-files-attributes (dir)
   "Return a list of all file names and attributes from DIR.
-List has a form of (file-name full-file-name (attribute-list))"
+List has a form of (file-name full-file-name (attribute-list))."
   (mapcar
    (lambda (file-name)
      (let ((full-file-name (expand-file-name file-name dir)))
@@ -476,8 +498,8 @@ with a prefix argument."
 (declare-function mailcap-file-default-commands "mailcap" (files))
 
 (defun minibuffer-default-add-dired-shell-commands ()
-  "Return a list of all commands associted with current dired files.
-This function is used to add all related commands retieved by `mailcap'
+  "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 'files) (require 'mailcap nil t)
@@ -488,7 +510,7 @@ to the end of the list of defaults just after the default value."
 
 ;; 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 prompting with PROMPT (using read-shell-command).
+  "Read a dired shell command prompting with PROMPT (using `read-shell-command').
 ARG is the prefix arg and may be used to indicate in the prompt which
 FILES are affected."
   (minibuffer-with-setup-hook
@@ -551,9 +573,9 @@ This feature does not try to redisplay Dired buffers afterward, as
 there's no telling what files COMMAND may have changed.
 Type \\[dired-do-redisplay] to redisplay the marked files.
 
-When COMMAND runs, its working directory is the top-level directory of
-the Dired buffer, so output files usually are created there instead of
-in a subdir.
+When COMMAND runs, its working directory is the top-level directory
+of the Dired buffer, so output files usually are created there
+instead of in a subdir.
 
 In a noninteractive call (from Lisp code), you must specify
 the list of file names explicitly with the FILE-LIST argument, which
@@ -679,7 +701,7 @@ can be produced by `dired-get-marked-files', for example."
        (save-excursion (and file
                             (dired-goto-subdir file)
                             (dired-kill-subdir)))
-       (delete-region (progn (beginning-of-line) (point))
+       (delete-region (line-beginning-position)
                       (progn (forward-line 1) (point)))
        (if (> arg 0)
            (setq arg (1- arg))
@@ -713,7 +735,7 @@ command with a prefix argument (the value does not matter)."
        (while (and (not (eobp))
                    (re-search-forward regexp nil t))
          (setq count (1+ count))
-         (delete-region (progn (beginning-of-line) (point))
+         (delete-region (line-beginning-position)
                         (progn (forward-line 1) (point))))
        (or (equal "" fmt)
            (message (or fmt "Killed %d line%s.") count (dired-plural-s count)))
@@ -752,6 +774,7 @@ command with a prefix argument (the value does not matter)."
     ("\\.dz\\'" "" "dictunzip")
     ("\\.tbz\\'" ".tar" "bunzip2")
     ("\\.bz2\\'" "" "bunzip2")
+    ("\\.xz\\'" "" "unxz")
     ;; This item controls naming for compression.
     ("\\.tar\\'" ".tgz" nil))
   "Control changes in file name suffixes for compression and uncompression.
@@ -798,8 +821,8 @@ Otherwise, the rule is a compression rule, and compression is done with gzip.")
               (let ((out-name (concat file ".gz")))
                 (and (or (not (file-exists-p out-name))
                          (y-or-n-p
-                          (format "File %s already exists.  Really compress? "
-                                  out-name)))
+                          "File %s already exists.  Really compress? "
+                          out-name))
                      (not (dired-check-process (concat "Compressing " file)
                                                "gzip" "-f" file))
                      (or (file-exists-p out-name)
@@ -866,48 +889,35 @@ Otherwise, the rule is a compression rule, and compression is done with gzip.")
                   (downcase string) count total (dired-plural-s total))
           failures)))))
 
-(defvar dired-query-alist
-  '((?\y . y) (?\040 . y)              ; `y' or SPC means accept once
-    (?n . n) (?\177 . n)               ; `n' or DEL skips once
-    (?! . yes)                         ; `!' accepts rest
-    (?q . no) (?\e . no)               ; `q' or ESC skips rest
-    ;; None of these keys quit - use C-g for that.
-    ))
-
 ;;;###autoload
-(defun dired-query (qs-var qs-prompt &rest qs-args)
-  ;; Query user and return nil or t.
-  ;; Store answer in symbol VAR (which must initially be bound to nil).
-  ;; Format PROMPT with ARGS.
-  ;; Binding variable help-form will help the user who types the help key.
-  (let* ((char (symbol-value qs-var))
-        (action (cdr (assoc char dired-query-alist))))
-    (cond ((eq 'yes action)
-          t)                           ; accept, and don't ask again
-         ((eq 'no action)
-          nil)                         ; skip, and don't ask again
-         (t;; no lasting effects from last time we asked - ask now
-          (let ((qprompt (concat qs-prompt
-                                 (if help-form
-                                     (format " [Type yn!q or %s] "
-                                             (key-description
-                                              (char-to-string help-char)))
-                                   " [Type y, n, q or !] ")))
-                result elt)
-            ;; Actually it looks nicer without cursor-in-echo-area - you can
-            ;; look at the dired buffer instead of at the prompt to decide.
-            (apply 'message qprompt qs-args)
-            (setq char (set qs-var (read-char)))
-            (while (not (setq elt (assoc char dired-query-alist)))
-              (message "Invalid char - type %c for help." help-char)
-              (ding)
-              (sit-for 1)
-              (apply 'message qprompt qs-args)
-              (setq char (set qs-var (read-char))))
-            ;; Display the question with the answer.
-            (message "%s" (concat (apply 'format qprompt qs-args)
-                             (char-to-string char)))
-            (memq (cdr elt) '(t y yes)))))))
+(defun dired-query (sym prompt &rest args)
+  "Format PROMPT with ARGS, query user, and store the result in SYM.
+The return value is either nil or t.
+
+The user may type y or SPC to accept once; n or DEL to skip once;
+! to accept this and subsequent queries; or q or ESC to decline
+this and subsequent queries.
+
+If SYM is already bound to a non-nil value, this function may
+return automatically without querying the user.  If SYM is !,
+return t; if SYM is q or ESC, return nil."
+  (let* ((char (symbol-value sym))
+        (char-choices '(?y ?\s ?n ?\177 ?! ?q ?\e)))
+    (cond ((eq char ?!)
+          t)       ; accept, and don't ask again
+         ((memq char '(?q ?\e))
+          nil)     ; skip, and don't ask again
+         (t        ; no previous answer - ask now
+          (setq prompt
+                (concat (apply 'format prompt args)
+                        (if help-form
+                            (format " [Type yn!q or %s] "
+                                    (key-description
+                                     (char-to-string help-char)))
+                          " [Type y, n, q or !] ")))
+          (set sym (setq char (read-char-choice prompt char-choices)))
+          (if (memq char '(?y ?\s ?!)) t)))))
+
 \f
 ;;;###autoload
 (defun dired-do-compress (&optional arg)
@@ -989,10 +999,14 @@ See Info node `(emacs)Subdir switches' for more details."
     ;; message much faster than making dired-map-over-marks show progress
     (dired-uncache
      (if (consp dired-directory) (car dired-directory) dired-directory))
-    (dired-map-over-marks (let ((fname (dired-get-filename)))
+    (dired-map-over-marks (let ((fname (dired-get-filename))
+                               ;; Postphone readin hook till we map
+                               ;; over all marked files (Bug#6810).
+                               (dired-after-readin-hook nil))
                            (message "Redisplaying... %s" fname)
                            (dired-update-file-line fname))
                          arg)
+    (run-hooks 'dired-after-readin-hook)
     (dired-move-to-filename)
     (message "Redisplaying...done")))
 
@@ -1008,10 +1022,10 @@ See Info node `(emacs)Subdir switches' for more details."
   ;; Keeps any marks that may be present in column one (doing this
   ;; here is faster than with dired-add-entry's optional arg).
   ;; Does not update other dired buffers.  Use dired-relist-entry for that.
-  (beginning-of-line)
-  (let ((char (following-char)) (opoint (point))
+  (let ((char (following-char))
+       (opoint (line-beginning-position))
        (buffer-read-only))
-    (delete-region (point) (progn (forward-line 1) (point)))
+    (delete-region opoint (progn (forward-line 1) (point)))
     (if file
        (progn
          (dired-add-entry file nil t)
@@ -1074,7 +1088,7 @@ See Info node `(emacs)Subdir switches' for more details."
              ;; Don't expand `.'.  Show just the file name within directory.
              (let ((default-directory directory))
                (dired-insert-directory directory
-                                       (concat dired-actual-switches "d")
+                                       (concat dired-actual-switches " -d")
                                        (list filename)))
               (goto-char opoint)
              ;; Put in desired marker char.
@@ -1104,8 +1118,7 @@ See Info node `(emacs)Subdir switches' for more details."
                  (save-excursion ;; ...so we can run it right now:
                    (save-restriction
                      (beginning-of-line)
-                     (narrow-to-region (point) (save-excursion
-                                                 (forward-line 1) (point)))
+                     (narrow-to-region (point) (line-beginning-position 2))
                      (run-hooks 'dired-after-readin-hook))))
              (dired-move-to-filename))
            ;; return nil if all went well
@@ -1138,7 +1151,7 @@ See Info node `(emacs)Subdir switches' for more details."
     (and (dired-goto-file file)
         (let (buffer-read-only)
           (delete-region (progn (beginning-of-line) (point))
-                         (save-excursion (forward-line 1) (point)))))))
+                         (line-beginning-position 2))))))
 
 ;;;###autoload
 (defun dired-relist-file (file)
@@ -1159,14 +1172,14 @@ See Info node `(emacs)Subdir switches' for more details."
           (delete-region (progn (beginning-of-line)
                                 (setq marker (following-char))
                                 (point))
-                         (save-excursion (forward-line 1) (point))))
+                         (line-beginning-position 2)))
       (setq file (directory-file-name file))
       (dired-add-entry file (if (eq ?\040 marker) nil marker)))))
 \f
 ;;; Copy, move/rename, making hard and symbolic links
 
 (defcustom dired-backup-overwrite nil
-  "*Non-nil if Dired should ask about making backups before overwriting files.
+  "Non-nil if Dired should ask about making backups before overwriting files.
 Special value `always' suppresses confirmation."
   :type '(choice (const :tag "off" nil)
                 (const :tag "suppress" always)
@@ -1210,51 +1223,7 @@ Special value `always' suppresses confirmation."
             (or (eq recursive 'always)
                 (yes-or-no-p (format "Recursive copies of %s? " from))))
        ;; This is a directory.
-       (let ((mode (file-modes from))
-             (files
-              (condition-case err
-                  (directory-files from nil dired-re-no-dot)
-                (file-error
-                 (push (dired-make-relative from)
-                       dired-create-files-failures)
-                 (dired-log "Copying error for %s:\n%s\n" from err)
-                 (setq dirfailed t)
-                 nil))))
-         (if (eq recursive 'top) (setq recursive 'always)) ; Don't ask any more.
-         (unless dirfailed
-           (if (file-exists-p to)
-               (or top (dired-handle-overwrite to))
-             (condition-case err
-                 ;; We used to call set-file-modes here, but on some
-                 ;; Linux kernels, that returns an error on vfat
-                 ;; filesystems
-                 (let ((default-mode (default-file-modes)))
-                   (unwind-protect
-                       (progn
-                         (set-default-file-modes #o700)
-                         (make-directory to))
-                     (set-default-file-modes default-mode)))
-               (file-error
-                (push (dired-make-relative from)
-                      dired-create-files-failures)
-                (setq files nil)
-                (dired-log "Copying error for %s:\n%s\n" from err)))))
-         (dolist (file files)
-           (let ((thisfrom (expand-file-name file from))
-                 (thisto (expand-file-name file to)))
-             ;; Catch errors copying within a directory,
-             ;; and report them through the dired log mechanism
-             ;; just as our caller will do for the top level files.
-             (condition-case err
-                 (dired-copy-file-recursive
-                  thisfrom thisto
-                  ok-flag preserve-time nil recursive)
-               (file-error
-                (push (dired-make-relative thisfrom)
-                      dired-create-files-failures)
-                (dired-log "Copying error for %s:\n%s\n" thisfrom err)))))
-         (when (file-directory-p to)
-           (set-file-modes to mode)))
+       (copy-directory from to dired-copy-preserve-time)
       ;; Not a directory.
       (or top (dired-handle-overwrite to))
       (condition-case err
@@ -1288,8 +1257,7 @@ Special value `always' suppresses confirmation."
   (let ((expanded-from-dir (expand-file-name from-dir))
        (blist (buffer-list)))
     (while blist
-      (save-excursion
-       (set-buffer (car blist))
+      (with-current-buffer (car blist)
        (if (and buffer-file-name
                 (dired-in-this-tree buffer-file-name expanded-from-dir))
            (let ((modflag (buffer-modified-p))
@@ -1464,7 +1432,7 @@ ESC or `q' to not overwrite any of the remaining files,
                                        how-to)
   "Create a new file for each marked file.
 Prompts user for target, which is a directory in which to create
-  the new files.  Target may be a plain file if only one marked
+  the new files.  Target may also be a plain file if only one marked
   file exists.  The way the default for the target directory is
   computed depends on the value of `dired-dwim-target-directory'.
 OP-SYMBOL is the symbol for the operation.  Function `dired-mark-pop-up'
@@ -1474,30 +1442,23 @@ ARG as in `dired-get-marked-files'.
 Optional arg MARKER-CHAR as in `dired-create-files'.
 Optional arg OP1 is an alternate form for OPERATION if there is
   only one file.
-Optional arg HOW-TO is used to set the value of the into-dir variable
-  which determines how to treat target.
-  If into-dir is set to nil then target is not regarded as a directory,
-    there must be exactly one marked file, else error.
-  Else if into-dir is set to a list, then target is a generalized
-    directory (e.g. some sort of archive).  The first element of into-dir
-    must be a function with at least four arguments:
-      operation as OPERATION above.
-      rfn-list a list of the relative names for the marked files.
-      fn-list a list of the absolute names for the marked files.
-      target.
+Optional arg HOW-TO determiness how to treat the target.
+  If HOW-TO is nil, use `file-directory-p' to determine if the
+   target is a directory.  If so, the marked file(s) are created
+   inside that directory.  Otherwise, the target is a plain file;
+   an error is raised unless there is exactly one marked file.
+  If HOW-TO is t, target is always treated as a plain file.
+  Otherwise, HOW-TO should be a function of one argument, TARGET.
+   If its return value is nil, TARGET is regarded as a plain file.
+   If it return value is a list, TARGET is a generalized
+    directory (e.g. some sort of archive).  The first element of
+    this list must be a function with at least four arguments:
+      operation - as OPERATION above.
+      rfn-list  - list of the relative names for the marked files.
+      fn-list   - list of the absolute names for the marked files.
+      target    - the name of the target itself.
       The rest of into-dir are optional arguments.
-  Else into-dir is not a list.  Target is a directory.
-    The marked file(s) are created inside the target directory.
-
-  If HOW-TO is not given (or nil), then into-dir is set to true if
-    target is a directory and otherwise to nil.
-  Else if HOW-TO is t, then into-dir is set to nil.
-  Else HOW-TO is assumed to be a function of one argument, target,
-    that looks at target and returns a value for the into-dir
-    variable.  The function `dired-into-dir-with-symlinks' is provided
-    for the case (common when creating symlinks) that symbolic
-    links to directories are not to be considered as directories
-    (as `file-directory-p' would if HOW-TO had been nil)."
+   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))
         (rfn-list (mapcar (function dired-make-relative) fn-list))
@@ -1507,10 +1468,15 @@ Optional arg HOW-TO is used to set the value of the into-dir variable
         (default (and dired-one-file
                       (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
-                  (dired-mark-read-file-name
-                   (concat (if dired-one-file op1 operation) " %s to: ")
-                   target-dir op-symbol arg rfn-list default)))
+                 (minibuffer-with-setup-hook
+                     (lambda ()
+                       (set (make-local-variable 'minibuffer-default-add-function) nil)
+                       (setq minibuffer-default defaults))
+                   (dired-mark-read-file-name
+                    (concat (if dired-one-file op1 operation) " %s to: ")
+                    target-dir op-symbol arg rfn-list default))))
         (into-dir (cond ((null how-to)
                          ;; Allow DOS/Windows users to change the letter
                          ;; case of a directory.  If we don't test these
@@ -1567,19 +1533,69 @@ Optional arg HOW-TO is used to set the value of the into-dir variable
 
 (defun dired-dwim-target-directory ()
   ;; Try to guess which target directory the user may want.
-  ;; If there is a dired buffer displayed in the next window, use
-  ;; its current subdir, else use current subdir of this dired buffer.
+  ;; If there is a dired buffer displayed in one of the next windows,
+  ;; use its current subdir, else use current subdir of this dired buffer.
   (let ((this-dir (and (eq major-mode 'dired-mode)
                       (dired-current-directory))))
     ;; non-dired buffer may want to profit from this function, e.g. vm-uudecode
     (if dired-dwim-target
-       (let* ((other-buf (window-buffer (next-window)))
-              (other-dir (save-excursion
-                           (set-buffer other-buf)
-                           (and (eq major-mode 'dired-mode)
-                                (dired-current-directory)))))
+       (let* ((other-win (get-window-with-predicate
+                          (lambda (window)
+                            (with-current-buffer (window-buffer window)
+                              (eq major-mode 'dired-mode)))))
+              (other-dir (and other-win
+                              (with-current-buffer (window-buffer other-win)
+                                (and (eq major-mode 'dired-mode)
+                                     (dired-current-directory))))))
          (or other-dir this-dir))
       this-dir)))
+
+(defun dired-dwim-target-defaults (fn-list target-dir)
+  ;; Return a list of default values for file-reading functions in Dired.
+  ;; This list may contain directories from Dired buffers in other windows.
+  ;; `fn-list' is a list of file names used to build a list of defaults.
+  ;; When nil or more than one element, a list of defaults will
+  ;; contain only directory names.  `target-dir' is a directory name
+  ;; to exclude from the returned list, for the case when this
+  ;; directory name is already presented in initial input.
+  ;; For Dired operations that support `dired-dwim-target',
+  ;; the argument `target-dir' should have the value returned
+  ;; from `dired-dwim-target-directory'.
+  (let ((dired-one-file
+        (and (consp fn-list) (null (cdr fn-list)) (car fn-list)))
+       (current-dir (and (eq major-mode 'dired-mode)
+                         (dired-current-directory)))
+       dired-dirs)
+    ;; Get a list of directories of visible buffers in dired-mode.
+    (walk-windows (lambda (w)
+                   (with-current-buffer (window-buffer w)
+                     (and (eq major-mode 'dired-mode)
+                          (push (dired-current-directory) dired-dirs)))))
+    ;; Force the current dir to be the first in the list.
+    (setq dired-dirs
+         (delete-dups (delq nil (cons current-dir (nreverse dired-dirs)))))
+    ;; Remove the target dir (if specified) or the current dir from
+    ;; default values, because it should be already in initial input.
+    (setq dired-dirs (delete (or target-dir current-dir) dired-dirs))
+    ;; Return a list of default values.
+    (if dired-one-file
+       ;; For one file operation, provide a list that contains
+       ;; other directories, other directories with the appended filename
+       ;; and the current directory with the appended filename, e.g.
+       ;; 1. /TARGET-DIR/
+       ;; 2. /TARGET-DIR/FILENAME
+       ;; 3. /CURRENT-DIR/FILENAME
+       (append dired-dirs
+               (mapcar (lambda (dir)
+                         (expand-file-name
+                          (file-name-nondirectory (car fn-list)) dir))
+                       (reverse dired-dirs))
+               (list (expand-file-name
+                      (file-name-nondirectory (car fn-list))
+                      (or target-dir current-dir))))
+      ;; For multi-file operation, return only a list of other directories.
+      dired-dirs)))
+
 \f
 ;;;###autoload
 (defun dired-create-directory (directory)
@@ -1614,7 +1630,7 @@ Optional arg HOW-TO is used to set the value of the into-dir variable
 ;; symlinks.
 
 (defvar dired-copy-how-to-fn nil
-  "nil or a function used by `dired-do-copy' to determine target.
+  "Either nil or a function used by `dired-do-copy' to determine target.
 See HOW-TO argument for `dired-do-create-files'.")
 
 ;;;###autoload
@@ -2277,7 +2293,7 @@ Use \\[dired-hide-all] to (un)hide all directories."
     (restore-buffer-modified-p modflag)))
 
 ;;;###autoload
-(defun dired-hide-all (arg)
+(defun dired-hide-all (&optional ignored)
   "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."
@@ -2311,25 +2327,28 @@ Use \\[dired-hide-subdir] to (un)hide a particular subdirectory."
 ;; Search only in file names in the Dired buffer.
 
 (defcustom dired-isearch-filenames nil
-  "*If non-nil, Isearch in Dired matches only file names."
+  "Non-nil to Isearch in file names only.
+If t, Isearch in Dired always matches only file names.
+If `dwim', Isearch matches file names when initial point position is on
+a file name.  Otherwise, it searches the whole buffer without restrictions."
   :type '(choice (const :tag "No restrictions" nil)
-                (const :tag "Isearch only in file names" dired-filename))
+                (const :tag "When point is on a file name initially, search file names" dwim)
+                (const :tag "Always search in file names" t))
   :group 'dired
   :version "23.1")
 
-(defvar dired-isearch-orig-success-function nil)
+(defvar dired-isearch-filter-predicate-orig nil)
 
 (defun dired-isearch-filenames-toggle ()
   "Toggle file names searching on or off.
-When on, Isearch checks the success of the current matching point
-using the function `dired-isearch-success-function' that matches only
-at file names.  When off, it uses the default function
-`isearch-success-function-default'."
+When on, Isearch skips matches outside file names using the predicate
+`dired-isearch-filter-filenames' that matches only at file names.
+When off, it uses the original predicate."
   (interactive)
-  (setq isearch-success-function
-       (if (eq isearch-success-function 'dired-isearch-success-function)
-           'isearch-success-function-default
-         'dired-isearch-success-function))
+  (setq isearch-filter-predicate
+       (if (eq isearch-filter-predicate 'dired-isearch-filter-filenames)
+           dired-isearch-filter-predicate-orig
+         'dired-isearch-filter-filenames))
   (setq isearch-success t isearch-adjusted t)
   (isearch-update))
 
@@ -2337,22 +2356,28 @@ at file names.  When off, it uses the default function
 (defun dired-isearch-filenames-setup ()
   "Set up isearch to search in Dired file names.
 Intended to be added to `isearch-mode-hook'."
-  (when dired-isearch-filenames
+  (when (or (eq dired-isearch-filenames t)
+           (and (eq dired-isearch-filenames 'dwim)
+                (get-text-property (point) 'dired-filename)))
+    (setq isearch-message-prefix-add "filename ")
     (define-key isearch-mode-map "\M-sf" 'dired-isearch-filenames-toggle)
-    (setq dired-isearch-orig-success-function
-         (default-value 'isearch-success-function))
-    (setq-default isearch-success-function 'dired-isearch-success-function)
+    (setq dired-isearch-filter-predicate-orig
+         (default-value 'isearch-filter-predicate))
+    (setq-default isearch-filter-predicate 'dired-isearch-filter-filenames)
     (add-hook 'isearch-mode-end-hook 'dired-isearch-filenames-end nil t)))
 
 (defun dired-isearch-filenames-end ()
   "Clean up the Dired file name search after terminating isearch."
+  (setq isearch-message-prefix-add nil)
   (define-key isearch-mode-map "\M-sf" nil)
-  (setq-default isearch-success-function dired-isearch-orig-success-function)
+  (setq-default isearch-filter-predicate dired-isearch-filter-predicate-orig)
   (remove-hook 'isearch-mode-end-hook 'dired-isearch-filenames-end t))
 
-(defun dired-isearch-success-function (beg end)
-  "Match only at visible regions with the text property `dired-filename'."
-  (and (isearch-success-function-default beg end)
+(defun dired-isearch-filter-filenames (beg end)
+  "Test whether the current search hit is a visible file name.
+Return non-nil if the text from BEG to END is part of a file
+name (has the text property `dired-filename') and is visible."
+  (and (isearch-filter-visible beg end)
        (if dired-isearch-filenames
           (text-property-not-all (min beg end) (max beg end)
                                  'dired-filename nil)
@@ -2425,15 +2450,20 @@ with the command \\[tags-loop-continue]."
 If FILE is a symbolic link and the optional argument DEREF-SYMLINKS is
 true then the type of the file linked to by FILE is printed instead."
   (interactive (list (dired-get-filename t) current-prefix-arg))
-  (with-temp-buffer
-    (if deref-symlinks
-       (call-process "file" nil t t "-L" "--" file)
-      (call-process "file" nil t t "--" file))
-    (when (bolp)
-      (backward-delete-char 1))
-    (message "%s" (buffer-string))))
+  (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))
+      (message "%s" (buffer-string)))))
 
 (provide 'dired-aux)
 
-;; arch-tag: 4b508de9-a153-423d-8d3f-a1bbd86f4f60
+;; Local Variables:
+;; byte-compile-dynamic: t
+;; generated-autoload-file: "dired.el"
+;; End:
+
 ;;; dired-aux.el ends here