(dired-show-file-type): Format filename with "%s" to escape any format-like
[bpt/emacs.git] / lisp / dired.el
index d3f657c..5fe4e4a 100644 (file)
@@ -39,7 +39,7 @@
 
 (defgroup dired nil
   "Directory editing."
-  :group 'environment)
+  :group 'files)
 
 (defgroup dired-mark nil
   "Handling marks in Dired."
@@ -72,6 +72,9 @@ some of the `ls' switches are not supported; see the doc string of
       "/etc/chown"))
   "Name of chown command (usually `chown' or `/etc/chown').")
 
+(defvar dired-use-ls-dired (not (not (string-match "gnu" system-configuration)))
+  "Non-nil means Dired should use `ls --dired'.")
+
 (defvar dired-chmod-program "chmod"
   "Name of chmod command (usually `chmod').")
 
@@ -164,24 +167,32 @@ The target is used in the prompt for file copy, rename etc."
 
 ;;; Hook variables
 
-(defvar dired-load-hook nil
+(defcustom dired-load-hook nil
   "Run after loading dired.
-You can customize key bindings or load extensions with this.")
+You can customize key bindings or load extensions with this."
+  :group 'dired
+  :type 'hook)
 
-(defvar dired-mode-hook nil
-  "Run at the very end of dired-mode.")
+(defcustom dired-mode-hook nil
+  "Run at the very end of dired-mode."
+  :group 'dired
+  :type 'hook)
 
-(defvar dired-before-readin-hook nil
-  "This hook is run before a dired buffer is read in (created or reverted).")
+(defcustom dired-before-readin-hook nil
+  "This hook is run before a dired buffer is read in (created or reverted)."
+  :group 'dired
+  :type 'hook)
 
-(defvar dired-after-readin-hook nil
+(defcustom dired-after-readin-hook nil
   "Hook run after each time a file or directory is read by Dired.
 After each listing of a file or directory, this hook is run
-with the buffer narrowed to the listing.")
+with the buffer narrowed to the listing."
+  :group 'dired
+  :type 'hook)
 ;; Note this can't simply be run inside function `dired-ls' as the hook
 ;; functions probably depend on the dired-subdir-alist to be OK.
 
-;;; Internal variables
+;; Internal variables
 
 (defvar dired-marker-char ?*           ; the answer is 42
   ;; so that you can write things like
@@ -209,9 +220,10 @@ This is what the `do' commands look for and what the `mark' commands store.")
 (defvar dired-file-version-alist)
 
 (defvar dired-directory nil
-  "The directory name or shell wildcard that was used as argument to `ls'.
+  "The directory name or wildcard spec that this Dired directory lists.
 Local to each dired buffer.  May be a list, in which case the car is the
-directory name and the cdr is the actual files to list.")
+directory name and the cdr is the list of files to mention.
+The directory name must be absolute, but need not be fully expanded.")
 
 (defvar dired-actual-switches nil
   "The value of `dired-listing-switches' used to make this buffer's text.")
@@ -292,11 +304,10 @@ Subexpression 2 must end right before the \\n or \\r.")
    ;;
    ;; Files suffixed with `completion-ignored-extensions'.
    '(eval .
-     (let ((extensions (mapcar 'regexp-quote completion-ignored-extensions)))
-       ;; It is quicker to first find just an extension, then go back to the
-       ;; start of that file name.  So we do this complex MATCH-ANCHORED form.
-       (list (concat "\\(" (mapconcat 'identity extensions "\\|") "\\|#\\)$")
-            '(".+" (dired-move-to-filename) nil (0 font-lock-string-face))))))
+     ;; It is quicker to first find just an extension, then go back to the
+     ;; start of that file name.  So we do this complex MATCH-ANCHORED form.
+     (list (concat "\\(" (regexp-opt completion-ignored-extensions) "\\|#\\)$")
+          '(".+" (dired-move-to-filename) nil (0 font-lock-string-face)))))
   "Additional expressions to highlight in Dired mode.")
 \f
 ;;; Macros must be defined before they are used, for the byte compiler.
@@ -389,21 +400,28 @@ BODY should not be too long as it is expanded four times."
      ;; save-excursion loses, again
      (dired-move-to-filename)))
 
-(defun dired-get-marked-files (&optional localp arg)
+(defun dired-get-marked-files (&optional localp arg filter)
   "Return the marked files' names as list of strings.
 The list is in the same order as the buffer, that is, the car is the
   first marked file.
-Values returned are normally absolute pathnames.
+Values returned are normally absolute file names.
 Optional arg LOCALP as in `dired-get-filename'.
-Optional second argument ARG forces to use other files.  If ARG is an
-  integer, use the next ARG files.  If ARG is otherwise non-nil, use
-  current file.  Usually ARG comes from the current prefix arg."
-  (save-excursion
-    (nreverse (dired-map-over-marks (dired-get-filename localp) arg))))
-
-\f
-;; Function dired-ls is redefinable for VMS, ange-ftp, Prospero or
-;; other special applications.
+Optional second argument ARG specifies files near point
+ instead of marked files.  If ARG is an integer, use the next ARG files.
+  If ARG is otherwise non-nil, use file.  Usually ARG comes from
+  the command's prefix arg.
+Optional third argument FILTER, if non-nil, is a function to select
+  some of the files--those for which (funcall FILTER FILENAME) is non-nil."
+  (let ((all-of-them
+        (save-excursion
+          (dired-map-over-marks (dired-get-filename localp) arg)))
+       result)
+    (if (not filter)
+       (nreverse all-of-them)
+      (dolist (file all-of-them)
+       (if (funcall filter file)
+           (push file result)))
+      result)))
 \f
 ;; The dired command
 
@@ -493,14 +511,17 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
   ;; like find-file does.
   ;; Optional argument MODE is passed to dired-find-buffer-nocreate,
   ;; see there.
-  (let* ((dirname (if (consp dir-or-list) (car dir-or-list) dir-or-list))
-        ;; The following line used to use dir-or-list.
-        ;; That never found an existing buffer, in the case
-        ;; where it is a list.
-        (buffer (dired-find-buffer-nocreate dirname mode))
+  (let* (dirname
+        buffer
         ;; note that buffer already is in dired-mode, if found
-        (new-buffer-p (not buffer))
+        new-buffer-p
         (old-buf (current-buffer)))
+    (if (consp dir-or-list)
+       (setq dirname (car dir-or-list))
+      (setq dirname dir-or-list))
+    ;; Look for an existing buffer.
+    (setq buffer (dired-find-buffer-nocreate dirname mode)
+         new-buffer-p (null buffer))
     (or buffer
        (let ((default-major-mode 'fundamental-mode))
          ;; We don't want default-major-mode to run hooks and set auto-fill
@@ -511,8 +532,7 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
     (if (not new-buffer-p)     ; existing buffer ...
        (cond (switches        ; ... but new switches     
               ;; file list may have changed
-              (if (consp dir-or-list) 
-                  (setq dired-directory dir-or-list))
+              (setq dired-directory dir-or-list)
               ;; this calls dired-revert
               (dired-sort-other switches))  
              ;; If directory has changed on disk, offer to revert.
@@ -535,21 +555,16 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
            (file-name-directory dirname))
       (or switches (setq switches dired-listing-switches))
       (if mode (funcall mode)
-        (dired-mode dirname switches))
+        (dired-mode dir-or-list switches))
       ;; default-directory and dired-actual-switches are set now
       ;; (buffer-local), so we can call dired-readin:
       (let ((failed t))
        (unwind-protect
-           (progn (dired-readin dir-or-list buffer)
+           (progn (dired-readin)
                   (setq failed nil))
          ;; dired-readin can fail if parent directories are inaccessible.
          ;; Don't leave an empty buffer around in that case.
          (if failed (kill-buffer buffer))))
-      ;; No need to narrow since the whole buffer contains just
-      ;; dired-readin's output, nothing else.  The hook can
-      ;; successfully use dired functions (e.g. dired-get-filename)
-      ;; as the subdir-alist has been built in dired-readin.
-      (run-hooks 'dired-after-readin-hook)
       (goto-char (point-min))
       (dired-initial-position dirname))
     (set-buffer old-buf)
@@ -565,6 +580,7 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
   ;; This differs from dired-buffers-for-dir in that it does not consider
   ;; subdirs of default-directory and searches for the first match only.
   ;; Also, the major mode must be MODE.
+  (setq dirname (expand-file-name dirname))
   (let (found (blist dired-buffers))    ; was (buffer-list)
     (or mode (setq mode 'dired-mode))
     (while blist
@@ -573,9 +589,11 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
        (save-excursion
          (set-buffer (cdr (car blist)))
          (if (and (eq major-mode mode)
-                  (if (consp dired-directory)
-                      (equal (car dired-directory) dirname)
-                    (equal dired-directory dirname)))
+                  (equal dirname
+                         (expand-file-name
+                          (if (consp dired-directory)
+                              (car dired-directory)
+                            dired-directory))))
              (setq found (cdr (car blist))
                    blist nil)
            (setq blist (cdr blist))))))
@@ -587,40 +605,30 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
 ;; dired-readin differs from dired-insert-subdir in that it accepts
 ;; wildcards, erases the buffer, and builds the subdir-alist anew
 ;; (including making it buffer-local and clearing it first).
-(defun dired-readin (dir-or-list buffer)
+(defun dired-readin ()
   ;; default-directory and dired-actual-switches must be buffer-local
   ;; and initialized by now.
-  ;; Thus we can test (equal default-directory dirname) instead of
-  ;; (file-directory-p dirname) and save a filesystem transaction.
-  ;; Also, we can run this hook which may want to modify the switches
-  ;; based on default-directory, e.g. with ange-ftp to a SysV host
-  ;; where ls won't understand -Al switches.
-  (let (dirname
-       (indent-tabs-mode nil))
-    (if (consp dir-or-list)
-       (setq dirname (car dir-or-list))
-      (setq dirname dir-or-list))
+  (let (dirname)
+    (if (consp dired-directory)
+       (setq dirname (car dired-directory))
+      (setq dirname dired-directory))
     (setq dirname (expand-file-name dirname))
-    (if (consp dir-or-list)
-       (setq dir-or-list (cons dirname (cdr dir-or-list))))
-    (run-hooks 'dired-before-readin-hook)
     (save-excursion
+      ;; This hook which may want to modify dired-actual-switches
+      ;; based on dired-directory, e.g. with ange-ftp to a SysV host
+      ;; where ls won't understand -Al switches.
+      (run-hooks 'dired-before-readin-hook)
       (message "Reading directory %s..." dirname)
-      (set-buffer buffer)
-      (let (buffer-read-only (failed t))
+      (if (consp buffer-undo-list)
+         (setq buffer-undo-list nil))
+      (let (buffer-read-only
+           ;; Don't make undo entries for readin.
+           (buffer-undo-list t))
        (widen)
        (erase-buffer)
-       (dired-readin-insert dir-or-list)
-       (indent-rigidly (point-min) (point-max) 2)
-       ;; We need this to make the root dir have a header line as all
-       ;; other subdirs have:
-       (goto-char (point-min))
-        (if (not (looking-at "^  /.*:$"))
-            (dired-insert-headerline default-directory))
-       ;; can't run dired-after-readin-hook here, it may depend on the subdir
-       ;; alist to be OK.
-       )
+       (dired-readin-insert))
       (message "Reading directory %s...done" dirname)
+      (goto-char (point-min))
       ;; Must first make alist buffer local and set it to nil because
       ;; dired-build-subdir-alist will call dired-clear-alist first
       (set (make-local-variable 'dired-subdir-alist) nil)
@@ -628,54 +636,57 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
       (let ((attributes (file-attributes dirname)))
        (if (eq (car attributes) t)
            (set-visited-file-modtime (nth 5 attributes))))
-      (set-buffer-modified-p nil))))
+      (set-buffer-modified-p nil)
+      ;; No need to narrow since the whole buffer contains just
+      ;; dired-readin's output, nothing else.  The hook can
+      ;; successfully use dired functions (e.g. dired-get-filename)
+      ;; as the subdir-alist has been built in dired-readin.
+      (run-hooks 'dired-after-readin-hook))))
 
 ;; Subroutines of dired-readin
 
-(defun dired-readin-insert (dir-or-list)
-  ;; Just insert listing for the passed-in directory or
-  ;; directory-and-file list, assuming a clean buffer.
-  (let (dirname)
-    (if (consp dir-or-list)
-       (setq dirname (car dir-or-list))
-      (setq dirname dir-or-list))
-    ;; Expand before comparing in case one or both have been abbreviated.
-    (if (and (equal (expand-file-name default-directory)
-                   (expand-file-name dirname))
-            (not (consp dir-or-list)))
+(defun dired-readin-insert ()
+  ;; Insert listing for the specified dir (and maybe file list)
+  ;; already in dired-directory, assuming a clean buffer.
+  (let (dir file-list)
+    (if (consp dired-directory)
+       (setq dir (car dired-directory)
+             file-list (cdr dired-directory))
+      (setq dir dired-directory
+           file-list nil))
+    (setq dir (expand-file-name dir))
+    (if (and (equal "" (file-name-nondirectory dir))
+            (not file-list))
        ;; If we are reading a whole single directory...
-       (dired-insert-directory dir-or-list dired-actual-switches nil t)
+       (dired-insert-directory dir dired-actual-switches nil nil t)
       (if (not (file-readable-p
-               (directory-file-name (file-name-directory dirname))))
-         (error "Directory %s inaccessible or nonexistent" dirname)
-       ;; Else assume it contains wildcards,
-       ;; unless it is an explicit list of files.
-       (dired-insert-directory dir-or-list dired-actual-switches
-                               (not (listp dir-or-list)))
-       (or (consp dir-or-list)
-           (save-excursion     ;; insert wildcard instead of total line:
-             (goto-char (point-min))
-             (insert "wildcard " (file-name-nondirectory dirname) "\n")))))))
-
-(defun dired-insert-directory (dir-or-list switches &optional wildcard full-p)
-  ;; Do the right thing whether dir-or-list is atomic or not.  If it is,
-  ;; inset all files listed in the cdr (the car is the passed-in directory
-  ;; list).
+               (directory-file-name (file-name-directory dir))))
+         (error "Directory %s inaccessible or nonexistent" dir)
+       ;; Else treat it as a wildcard spec
+       ;; unless we have an explicit list of files.
+       (dired-insert-directory dir dired-actual-switches
+                               file-list (not file-list) t)))))
+
+(defun dired-insert-directory (dir switches &optional file-list wildcard hdr)
+  "Insert a directory listing of DIR, Dired style.
+Use SWITCHES to make the listings.
+If FILE-LIST is non-nil, list only those files.
+Otherwise, if WILDCARD is non-nil, expand wildcards;
+ in that case, DIR should be a file name that uses wildcards.
+In other cases, DIR should be a directory name or a directory filename.
+If HDR is non-nil, insert a header line with the directory name."
   (let ((opoint (point))
        (process-environment (copy-sequence process-environment))
        end)
+    (if (or dired-use-ls-dired (file-remote-p dir))
+       (setq switches (concat "--dired " switches)))
     ;; We used to specify the C locale here, to force English month names;
     ;; but this should not be necessary any more,
     ;; with the new value of dired-move-to-filename-regexp.
-    (if (consp dir-or-list)
-       ;; In this case, use the file names in the cdr
-       ;; exactly as originally given to dired-noselect.
-       (mapcar
-        (function (lambda (x) (insert-directory x switches wildcard full-p)))
-        (cdr dir-or-list))
-      ;; Expand the file name here because it may have been abbreviated
-      ;; in dired-noselect.
-      (insert-directory (expand-file-name dir-or-list) switches wildcard full-p))
+    (if file-list
+       (dolist (f file-list)
+         (insert-directory f switches nil nil))
+      (insert-directory dir switches wildcard (not wildcard)))
     ;; Quote certain characters, unless ls quoted them for us.
     (if (not (string-match "b" dired-actual-switches))
        (save-excursion
@@ -687,8 +698,25 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
          (while (search-forward "\^m" end t)
            (replace-match "\\015" nil t))
          (set-marker end nil)))
-    (dired-insert-set-properties opoint (point)))
-  (setq dired-directory dir-or-list))
+    (dired-insert-set-properties opoint (point))
+    ;; If we used --dired and it worked, the lines are already indented.
+    ;; Otherwise, indent them.
+    (unless (save-excursion
+             (goto-char opoint)
+             (looking-at "  "))
+      (let ((indent-tabs-mode nil))
+       (indent-rigidly opoint (point) 2)))
+    ;; Insert text at the beginning to standardize things.
+    (save-excursion
+      (goto-char opoint)
+      (if (and (or hdr wildcard) (not (looking-at "^  /.*:$")))
+         ;; Note that dired-build-subdir-alist will replace the name
+         ;; by its expansion, so it does not matter whether what we insert
+         ;; here is fully expanded, but it should be absolute.
+         (insert "  " (directory-file-name (file-name-directory dir)) ":\n"))
+      (when wildcard
+       ;; Insert "wildcard" line where "total" line would be for a full dir.
+       (insert "  wildcard " (file-name-nondirectory dir) "\n")))))
 
 ;; Make the file names highlight when the mouse is on them.
 (defun dired-insert-set-properties (beg end)
@@ -706,13 +734,6 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
                 help-echo "mouse-2: visit this file in other window")))
        (error nil))
       (forward-line 1))))
-
-(defun dired-insert-headerline (dir);; also used by dired-insert-subdir
-  ;; Insert DIR's headerline with no trailing slash, exactly like ls
-  ;; would, and put cursor where dired-build-subdir-alist puts subdir
-  ;; boundaries.
-  (save-excursion (insert "  " (directory-file-name dir) ":\n")))
-
 \f
 ;; Reverting a dired buffer
 
@@ -735,7 +756,7 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
     ;; treat top level dir extra (it may contain wildcards)
     (dired-uncache
      (if (consp dired-directory) (car dired-directory) dired-directory))
-    (dired-readin dired-directory (current-buffer))
+    (dired-readin)
     (let ((dired-after-readin-hook nil))
       ;; don't run that hook for each subdir...
       (dired-insert-old-subdirs old-subdir-alist))
@@ -897,7 +918,7 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
     (define-key map "*\177" 'dired-unmark-backward)
     (define-key map "*\C-n" 'dired-next-marked-file)
     (define-key map "*\C-p" 'dired-prev-marked-file)
-    (define-key map "*t" 'dired-do-toggle)
+    (define-key map "*t" 'dired-toggle-marks)
     ;; Lower keys for commands not operating on all the marked files
     (define-key map "a" 'dired-find-alternate-file)
     (define-key map "d" 'dired-flag-file-deletion)
@@ -916,7 +937,7 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
     (define-key map "p" 'dired-previous-line)
     (define-key map "q" 'quit-window)
     (define-key map "s" 'dired-sort-toggle-or-edit)
-    (define-key map "t" 'dired-do-toggle)
+    (define-key map "t" 'dired-toggle-marks)
     (define-key map "u" 'dired-unmark)
     (define-key map "v" 'dired-view-file)
     (define-key map "w" 'dired-copy-filename-as-kill)
@@ -1097,7 +1118,7 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
       '(menu-item "Mark" dired-mark
                  :help "Mark current line's file for future operations"))
     (define-key map [menu-bar mark toggle-marks]
-      '(menu-item "Toggle Marks" dired-do-toggle
+      '(menu-item "Toggle Marks" dired-toggle-marks
                  :help "Mark unmarked files, unmark marked ones"))
 
     (define-key map [menu-bar operate]
@@ -1340,30 +1361,57 @@ Creates a buffer if necessary."
   (interactive)
   (set-buffer-modified-p nil)
   (find-alternate-file (dired-get-file-for-visit)))
+;; Don't override the setting from .emacs.
+;;;###autoload (put 'dired-find-alternate-file 'disabled t)
 
 (defun dired-mouse-find-file-other-window (event)
   "In Dired, visit the file or directory name you click on."
   (interactive "e")
-  (let (file)
+  (let (window pos file)
     (save-excursion
-      (set-buffer (window-buffer (posn-window (event-end event))))
-      (save-excursion
-       (goto-char (posn-point (event-end event)))
-       (setq file (dired-get-file-for-visit))))
-    (select-window (posn-window (event-end event)))
+      (setq window (posn-window (event-end event))
+           pos (posn-point (event-end event)))
+      (if (not (windowp window))
+         (error "No file chosen"))
+      (set-buffer (window-buffer window))
+      (goto-char pos)
+      (setq file (dired-get-file-for-visit)))
+    (select-window window)
     (find-file-other-window (file-name-sans-versions file t))))
 
+(defcustom dired-view-command-alist
+  '(("[.]ps\\'" . "gv -spartan -color -watch")
+    ("[.]pdf\\'" . "xpdf")
+    ("[.]dvi\\'" . "xdvi -sidemargin 0.5 -topmargin 1"))
+  "Alist specifying how to view special types of files.
+Each element has the form (REGEXP . SHELL-COMMAND).
+When the file name matches REGEXP, `dired-view-file'
+invokes SHELL-COMMAND to view the file, putting the file name
+at the end of the command."
+  :group 'dired
+  :type '(alist :key-type regexp :value-type string)
+  :version "21.4")
+
 (defun dired-view-file ()
   "In Dired, examine a file in view mode, returning to dired when done.
-When file is a directory, show it in this buffer if it is inserted;
-otherwise, display it in another buffer."
+When file is a directory, show it in this buffer if it is inserted.
+Some kinds of files are displayed using external viewer programs;
+see `dired-view-command-alist'.  Otherwise, display it in another buffer."
   (interactive)
   (let ((file (dired-get-file-for-visit)))
     (if (file-directory-p file)
        (or (and (cdr dired-subdir-alist)
                 (dired-goto-subdir file))
            (dired file))
-      (view-file file))))
+      (let (cmd)
+       ;; Look for some other way to view a certain file.
+       (dolist (elt dired-view-command-alist)
+         (if (string-match (car elt) file)
+             (setq cmd (cdr elt))))
+       (if cmd
+           (dired-run-shell-command (concat cmd " "
+                                            (shell-quote-argument file)))
+         (view-file file))))))
 
 (defun dired-find-file-other-window ()
   "In Dired, visit this file or directory in another window."
@@ -1401,7 +1449,7 @@ Optional arg NO-ERROR-IF-NOT-FILEP means return nil if no filename on
          (setq file
                (read
                 (concat "\""
-                        ;; some ls -b don't escape quotes, argh!
+                        ;; Some ls -b don't escape quotes, argh!
                         ;; This is not needed for GNU ls, though.
                         (or (dired-string-replace-match
                              "\\([^\\]\\|\\`\\)\"" file "\\1\\\\\"" nil t)
@@ -1417,14 +1465,33 @@ Optional arg NO-ERROR-IF-NOT-FILEP means return nil if no filename on
         (not default-file-name-coding-system)
         (setq file (encode-coding-string file buffer-file-coding-system)))
     (cond
+     ((null file)
+      nil)
      ((eq localp 'verbatim)
       file)
      ((and (eq localp 'no-dir) already-absolute)
       (file-name-nondirectory file))
-     ((or already-absolute (eq localp 'no-dir))
+     (already-absolute
+      (let ((handler (find-file-name-handler file nil)))
+       ;; check for safe-magic property so that we won't
+       ;; put /: for names that don't really need them.
+       ;; For instance, .gz files when auto-compression-mode is on.
+       (if (and handler (not (get handler 'safe-magic)))
+           (concat "/:" file)
+         file)))
+     ((eq localp 'no-dir)
       file)
+     ((equal (dired-current-directory) "/")
+      (setq file (concat (dired-current-directory localp) file))
+      (let ((handler (find-file-name-handler file nil)))
+       ;; check for safe-magic property so that we won't
+       ;; put /: for names that don't really need them.
+       ;; For instance, .gz files when auto-compression-mode is on.
+       (if (and handler (not (get handler 'safe-magic)))
+           (concat "/:" file)
+         file)))
      (t
-      (and file (concat (dired-current-directory localp) file))))))
+      (concat (dired-current-directory localp) file)))))
 
 (defun dired-string-replace-match (regexp string newtext
                                          &optional literal global)
@@ -1517,12 +1584,21 @@ regardless of the language.")
 ;; Returns position (point) or nil if no filename on this line."
 (defun dired-move-to-filename (&optional raise-error eol)
   ;; This is the UNIX version.
-  (or eol (setq eol (progn (end-of-line) (point))))
+  (or eol (setq eol (line-end-position)))
   (beginning-of-line)
-  (if (re-search-forward dired-move-to-filename-regexp eol t)
-      (goto-char (match-end 0))
-    (if raise-error
-       (error "No file on this line"))))
+  ;; First try assuming `ls --dired' was used.
+  (let ((change (next-single-property-change (point) 'dired-filename nil eol)))
+    (cond
+     ((and change (< change eol))
+      (goto-char change))
+     ((re-search-forward dired-move-to-filename-regexp eol t)
+      (goto-char (match-end 0)))
+     ((re-search-forward dired-permission-flags-regexp eol t)
+      ;; Ha!  There *is* a file.  Our regexp-from-hell just failed to find it.
+      (funcall (if raise-error 'error 'message)
+              "Unrecognized line!  Check dired-move-to-filename-regexp"))
+     (raise-error
+      (error "No file on this line")))))
 
 (defun dired-move-to-end-of-filename (&optional no-error)
   ;; Assumes point is at beginning of filename,
@@ -1531,63 +1607,65 @@ regardless of the language.")
   ;; (dired-move-to-filename t).
   ;; On failure, signals an error (with non-nil NO-ERROR just returns nil).
   ;; This is the UNIX version.
-  (let (opoint file-type executable symlink hidden case-fold-search used-F eol)
-    ;; case-fold-search is nil now, so we can test for capital F:
-    (setq used-F (string-match "F" dired-actual-switches)
-         opoint (point)
-          eol (save-excursion (end-of-line) (point))
-         hidden (and selective-display
-                     (save-excursion (search-forward "\r" eol t))))
-    (if hidden
-       nil
-      (save-excursion;; Find out what kind of file this is:
-       ;; Restrict perm bits to be non-blank,
-       ;; otherwise this matches one char to early (looking backward):
-       ;; "l---------" (some systems make symlinks that way)
-       ;; "----------" (plain file with zero perms)
-       (if (re-search-backward
-            dired-permission-flags-regexp nil t)
-           (setq file-type (char-after (match-beginning 1))
-                 symlink (eq file-type ?l)
-                 ;; Only with -F we need to know whether it's an executable
-                 executable (and
-                             used-F
-                             (string-match
-                              "[xst]";; execute bit set anywhere?
-                              (concat
-                               (buffer-substring (match-beginning 2)
-                                                 (match-end 2))
-                               (buffer-substring (match-beginning 3)
-                                                 (match-end 3))
-                               (buffer-substring (match-beginning 4)
-                                                 (match-end 4))))))
-         (or no-error (error "No file on this line"))))
-      ;; Move point to end of name:
-      (if symlink
-         (if (search-forward " ->" eol t)
-             (progn
-               (forward-char -3)
-               (and used-F
-                    dired-ls-F-marks-symlinks
-                    (eq (preceding-char) ?@);; did ls really mark the link?
-                    (forward-char -1))))
-       (goto-char eol);; else not a symbolic link
-       ;; ls -lF marks dirs, sockets and executables with exactly one
-       ;; trailing character. (Executable bits on symlinks ain't mean
-       ;; a thing, even to ls, but we know it's not a symlink.)
-       (and used-F
-            (or (memq file-type '(?d ?s))
-                executable)
-            (forward-char -1))))
-    (or no-error
-       (not (eq opoint (point)))
-       (error (if hidden
-                  (substitute-command-keys
-                   "File line is hidden, type \\[dired-hide-subdir] to unhide")
-                "No file on this line")))
-    (if (eq opoint (point))
-       nil
-      (point))))
+  (if (get-text-property (point) 'dired-filename)
+      (goto-char (next-single-property-change (point) 'dired-filename))
+    (let (opoint file-type executable symlink hidden case-fold-search used-F eol)
+      ;; case-fold-search is nil now, so we can test for capital F:
+      (setq used-F (string-match "F" dired-actual-switches)
+           opoint (point)
+           eol (save-excursion (end-of-line) (point))
+           hidden (and selective-display
+                       (save-excursion (search-forward "\r" eol t))))
+      (if hidden
+         nil
+       (save-excursion ;; Find out what kind of file this is:
+         ;; Restrict perm bits to be non-blank,
+         ;; otherwise this matches one char to early (looking backward):
+         ;; "l---------" (some systems make symlinks that way)
+         ;; "----------" (plain file with zero perms)
+         (if (re-search-backward
+              dired-permission-flags-regexp nil t)
+             (setq file-type (char-after (match-beginning 1))
+                   symlink (eq file-type ?l)
+                   ;; Only with -F we need to know whether it's an executable
+                   executable (and
+                               used-F
+                               (string-match
+                                "[xst]" ;; execute bit set anywhere?
+                                (concat
+                                 (buffer-substring (match-beginning 2)
+                                                   (match-end 2))
+                                 (buffer-substring (match-beginning 3)
+                                                   (match-end 3))
+                                 (buffer-substring (match-beginning 4)
+                                                   (match-end 4))))))
+           (or no-error (error "No file on this line"))))
+       ;; Move point to end of name:
+       (if symlink
+           (if (search-forward " ->" eol t)
+               (progn
+                 (forward-char -3)
+                 (and used-F
+                      dired-ls-F-marks-symlinks
+                      (eq (preceding-char) ?@) ;; did ls really mark the link?
+                      (forward-char -1))))
+         (goto-char eol) ;; else not a symbolic link
+         ;; ls -lF marks dirs, sockets and executables with exactly one
+         ;; trailing character. (Executable bits on symlinks ain't mean
+         ;; a thing, even to ls, but we know it's not a symlink.)
+         (and used-F
+              (or (memq file-type '(?d ?s))
+                  executable)
+              (forward-char -1))))
+      (or no-error
+         (not (eq opoint (point)))
+         (error (if hidden
+                    (substitute-command-keys
+                     "File line is hidden, type \\[dired-hide-subdir] to unhide")
+                  "No file on this line")))
+      (if (eq opoint (point))
+         nil
+       (point)))))
 
 \f
 ;;; COPY NAMES OF MARKED FILES INTO KILL-RING.
@@ -2052,9 +2130,9 @@ if there are no flagged files."
                      ;; if we get here, removing worked
                      (setq succ (1+ succ))
                      (message "%s of %s deletions" succ count)
-                     (delete-region (progn (beginning-of-line) (point))
-                                    (progn (forward-line 1) (point)))
-                     (dired-clean-up-after-deletion fn))
+                     (dired-fun-in-all-buffers
+                      (file-name-directory fn) (file-name-nondirectory fn)
+                      (function dired-delete-entry) fn))
                  (error;; catch errors from failed deletions
                   (dired-log "%s\n" err)
                   (setq failures (cons (car (car l)) failures)))))
@@ -2069,6 +2147,29 @@ if there are no flagged files."
       (message "(No deletions performed)")))
   (dired-move-to-filename))
 
+(defun dired-fun-in-all-buffers (directory file fun &rest args)
+  ;; In all buffers dired'ing DIRECTORY, run FUN with ARGS.
+  ;; If the buffer has a wildcard pattern, check that it matches FILE.
+  ;; (FILE does not include a directory component.)
+  ;; FILE may be nil, in which case ignore it.
+  ;; Return list of buffers where FUN succeeded (i.e., returned non-nil).
+  (let (success-list)
+    (dolist (buf (dired-buffers-for-dir (expand-file-name directory)
+                                       file))
+      (with-current-buffer buf
+       (if (apply fun args)
+           (setq success-list (cons (buffer-name buf) success-list)))))
+    success-list))
+
+;; Delete the entry for FILE from 
+(defun dired-delete-entry (file)
+  (save-excursion
+    (and (dired-goto-file file)
+        (let (buffer-read-only)
+          (delete-region (progn (beginning-of-line) (point))
+                         (save-excursion (forward-line 1) (point))))))
+  (dired-clean-up-after-deletion file))
+
 ;; This is a separate function for the sake of dired-x.el.
 (defun dired-clean-up-after-deletion (fn)
   ;; Clean up after a deleted file or directory FN.
@@ -2107,7 +2208,7 @@ if there are no flagged files."
     ;; let window shrink to fit:
     (let ((window (selected-window))
          target-lines w2)
-      (cond ;; if split-window-threshold is enabled, use the largest window
+      (cond ;; if split-height-threshold is enabled, use the largest window
             ((and (> (window-height (setq w2 (get-largest-window)))
                     split-height-threshold)
                  (= (frame-width) (window-width w2)))
@@ -2147,12 +2248,13 @@ Command symbols are `byte-compile', `chgrp', `chmod', `chown', `compress',
 `uncompress'.")
 
 (defun dired-mark-pop-up (bufname op-symbol files function &rest args)
-  "Args BUFNAME OP-SYMBOL FILES FUNCTION &rest ARGS.
-Return FUNCTION's result on ARGS after popping up a window (in a buffer
-named BUFNAME, nil gives \" *Marked Files*\") showing the marked
-files.  Uses function `dired-pop-to-buffer' to do that.
- FUNCTION should not manipulate files.
- It should only read input (an argument or confirmation).
+  "Return FUNCTION's result on ARGS after showing which files are marked.
+Displays the file names in a buffer named BUFNAME;
+ nil gives \" *Marked Files*\".
+This uses function `dired-pop-to-buffer' to do that.
+
+FUNCTION should not manipulate files, just read input
+ (an argument or confirmation).
 The window is not shown if there is just one file or
  OP-SYMBOL is a member of the list in `dired-no-confirm'.
 FILES is the list of marked files."
@@ -2315,9 +2417,8 @@ Optional prefix ARG says how many lines to unflag; default is one line."
   (interactive "p")
   (dired-unmark (- arg)))
 
-(defun dired-do-toggle ()
-  "Toggle marks.
-That is, currently marked files become unmarked and vice versa.
+(defun dired-toggle-marks ()
+  "Toggle marks: marked files become unmarked, and vice versa.
 Files marked with other flags (such as `D') are not affected.
 `.' and `..' are never toggled.
 As always, hidden subdirs are not affected."
@@ -2558,38 +2659,50 @@ Thus, use \\[backward-page] to find the beginning of a group of errors."
            (progn
              (select-window window)
              (goto-char (point-max))
-             (recenter -1))
+             (forward-line -1)
+             (backward-page 1)
+             (recenter 0))
          (select-window owindow)))))
 
 (defun dired-log (log &rest args)
   ;; Log a message or the contents of a buffer.
   ;; If LOG is a string and there are more args, it is formatted with
   ;; those ARGS.  Usually the LOG string ends with a \n.
-  ;; End each bunch of errors with (dired-log t): this inserts
-  ;; current time and buffer, and a \f (formfeed).
+  ;; End each bunch of errors with (dired-log t): 
+  ;; this inserts the current time and buffer at the start of the page,
+  ;; and \f (formfeed) at the end.
   (let ((obuf (current-buffer)))
-    (unwind-protect                    ; want to move point
-       (progn
-         (set-buffer (get-buffer-create dired-log-buffer))
-         (goto-char (point-max))
-         (let (buffer-read-only)
-           (cond ((stringp log)
-                  (insert (if args
-                              (apply (function format) log args)
-                            log)))
-                 ((bufferp log)
-                  (insert-buffer log))
-                 ((eq t log)
-                  (insert "\n\t" (current-time-string)
-                          "\tBuffer `" (buffer-name obuf) "'\n\f\n")))))
-      (set-buffer obuf))))
+    (with-current-buffer (get-buffer-create dired-log-buffer)
+      (goto-char (point-max))
+      (let ((inhibit-read-only t))
+       (cond ((stringp log)
+              (insert (if args
+                          (apply (function format) log args)
+                        log)))
+             ((bufferp log)
+              (insert-buffer log))
+             ((eq t log)
+              (backward-page 1)
+              (unless (bolp)
+                (insert "\n"))
+              (insert (current-time-string)
+                      "\tBuffer `" (buffer-name obuf) "'\n")
+              (goto-char (point-max))
+              (insert "\f\n")))))))
 
 (defun dired-log-summary (string failures)
-  (message (if failures "%s--type ? for details (%s)"
-            "%s--type ? for details")
-          string failures)
+  (if (= (length failures) 1)
+      (message "%s"
+              (with-current-buffer dired-log-buffer
+                (goto-char (point-max))
+                (backward-page 1)
+                (if (eolp) (forward-line 1))
+                (buffer-substring (point) (point-max))))
+    (message (if failures "%s--type ? for details (%s)"
+              "%s--type ? for details")
+            string failures))
   ;; Log a summary describing a bunch of errors.
-  (dired-log (concat "\n" string))
+  (dired-log (concat "\n" string "\n"))
   (dired-log t))
 \f
 ;;; Sorting
@@ -2641,7 +2754,7 @@ With a prefix argument you can edit the current listing switches instead."
          (if (string-match " " dired-actual-switches)
              ;; New toggle scheme: add/remove a trailing " -t"
              (if (string-match " -t\\'" dired-actual-switches)
-                 (dired-replace-in-string " -t\\'" "" dired-actual-switches)
+                 (substring dired-actual-switches 0 (match-beginning 0))
                (concat dired-actual-switches " -t"))
            ;; old toggle scheme: look for some 't' switch and add/remove it
            (concat
@@ -2768,18 +2881,33 @@ If no files are marked or a specific numeric prefix arg is given,
 the next ARG files are used.  Just \\[universal-argument] means the current file.
 The prompt mentions the file(s) or the marker, as appropriate.
 
-If there is output, it goes to a separate buffer.
+If there is a `*' in COMMAND, surrounded by whitespace, this runs
+COMMAND just once with the entire file list substituted there.
 
-Normally the command is run on each file individually.
-However, if there is a `*' in the command then it is run
-just once with the entire file list substituted there.
+If there is no `*', but there is a `?' in COMMAND, surrounded by
+whitespace, this runs COMMAND on each file individually with the
+file name substituted for `?'.
 
-No automatic redisplay of dired buffers is attempted, as there's no
-telling what files the command may have changed.  Type
-\\[dired-do-redisplay] to redisplay the marked files.
+Otherwise, this runs COMMAND on each file individually with the
+file name added at the end of COMMAND (separated by a space).
 
-The shell command has the top level directory as working directory, so
-output files usually are created there instead of in a subdir."
+`*' and `?' when not surrounded by whitespace have no special
+significance for `dired-do-shell-command', and are passed through
+normally to the shell, but you must confirm first.  To pass `*' by
+itself to the shell as a wildcard, type `*\"\"'.
+
+If COMMAND produces output, it goes to a separate buffer.
+
+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.
+
+In a noninteractive call (from Lisp code), you must specify
+the list of file names explicitly with the FILE-LIST argument."
   t)
 
 (autoload 'dired-do-kill-lines "dired-aux"
@@ -2930,6 +3058,10 @@ Use \\[dired-hide-subdir] to (un)hide a particular subdirectory."
 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." 
   t)
+
+(autoload 'dired-run-shell-command "dired-aux")
+
+(autoload 'dired-query "dired-aux")
 \f
 (if (eq system-type 'vax-vms)
     (load "dired-vms"))