]> code.delx.au - gnu-emacs/blobdiff - lisp/dired-x.el
Merge from origin/emacs-25
[gnu-emacs] / lisp / dired-x.el
index dcf8906976b8172cfa93022802dbb5d595fd924e..053b3cb9738f519c0b19624b8cca959fdfe66938 100644 (file)
@@ -1,6 +1,7 @@
-;;; dired-x.el --- extra Dired functionality
+;;; dired-x.el --- extra Dired functionality  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1993-1994, 1997, 2001-2011 Free Software Foundation, Inc.
+;; Copyright (C) 1993-1994, 1997, 2001-2016 Free Software Foundation,
+;; Inc.
 
 ;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>
 ;;     Lawrence R. Dodd <dodd@roebling.poly.edu>
@@ -85,16 +86,16 @@ use \\[customize]."
   :set (lambda (sym val)
          (if (set sym val)
              (progn
-               (define-key global-map "\C-x\C-j" 'dired-jump)
-               (define-key global-map "\C-x4\C-j" 'dired-jump-other-window))
-           (if (eq 'dired-jump (lookup-key global-map "\C-x\C-j"))
-               (define-key global-map "\C-x\C-j" nil))
-           (if (eq 'dired-jump-other-window (lookup-key global-map "\C-x4\C-j"))
-               (define-key global-map "\C-x4\C-j" nil))))
+               (define-key ctl-x-map "\C-j" 'dired-jump)
+               (define-key ctl-x-4-map "\C-j" 'dired-jump-other-window))
+           (if (eq 'dired-jump (lookup-key ctl-x-map "\C-j"))
+               (define-key ctl-x-map "\C-j" nil))
+           (if (eq 'dired-jump-other-window (lookup-key ctl-x-4-map "\C-j"))
+               (define-key ctl-x-4-map "\C-j" nil))))
   :group 'dired-keys)
 
 (defcustom dired-bind-man t
-  "Non-nil means bind `dired-man' to \"N\" in dired-mode, otherwise do not.
+  "Non-nil means bind `dired-man' to \"N\" in Dired, otherwise do not.
 Setting this variable directly after dired-x is loaded has no effect -
 use \\[customize]."
   :type 'boolean
@@ -106,7 +107,7 @@ use \\[customize]."
   :group 'dired-keys)
 
 (defcustom dired-bind-info t
-  "Non-nil means bind `dired-info' to \"I\" in dired-mode, otherwise do not.
+  "Non-nil means bind `dired-info' to \"I\" in Dired, otherwise do not.
 Setting this variable directly after dired-x is loaded has no effect -
 use \\[customize]."
   :type 'boolean
@@ -126,17 +127,29 @@ files not writable by you are visited read-only."
                 (other :tag "non-writable only" if-file-read-only))
   :group 'dired-x)
 
+(defcustom dired-omit-size-limit 30000
+  "Maximum size for the \"omitting\" feature.
+If nil, there is no maximum size."
+  :type '(choice (const :tag "no maximum" nil) integer)
+  :group 'dired-x)
+
+;; For backward compatibility
+(define-obsolete-variable-alias 'dired-omit-files-p 'dired-omit-mode "22.1")
 (define-minor-mode dired-omit-mode
-  "Toggle Dired-Omit mode.
-With numeric ARG, enable Dired-Omit mode if ARG is positive, disable
-otherwise.  Enabling and disabling is buffer-local.
-If enabled, \"uninteresting\" files are not listed.
-Uninteresting files are those whose filenames match regexp `dired-omit-files',
-plus those ending with extensions in `dired-omit-extensions'.
+  "Toggle omission of uninteresting files in Dired (Dired-Omit mode).
+With a prefix argument ARG, enable Dired-Omit mode if ARG is
+positive, and disable it otherwise.  If called from Lisp, enable
+the mode if ARG is omitted or nil.
+
+Dired-Omit mode is a buffer-local minor mode.  When enabled in a
+Dired buffer, Dired does not list files whose filenames match
+regexp `dired-omit-files', nor files ending with extensions in
+`dired-omit-extensions'.
 
-To enable omitting in every Dired buffer, you can put in your ~/.emacs
+To enable omitting in every Dired buffer, you can put this in
+your init file:
 
-  (add-hook 'dired-mode-hook (lambda () (dired-omit-mode 1)))
+  (add-hook \\='dired-mode-hook (lambda () (dired-omit-mode)))
 
 See Info node `(dired-x) Omitting Variables' for more information."
   :group 'dired-x
@@ -147,13 +160,10 @@ See Info node `(dired-x) Omitting Variables' for more information."
 
 (put 'dired-omit-mode 'safe-local-variable 'booleanp)
 
-;; For backward compatibility
-(define-obsolete-variable-alias 'dired-omit-files-p 'dired-omit-mode "22.1")
-
 (defcustom dired-omit-files "^\\.?#\\|^\\.$\\|^\\.\\.$"
   "Filenames matching this regexp will not be displayed.
 This only has effect when `dired-omit-mode' is t.  See interactive function
-`dired-omit-mode' \(\\[dired-omit-mode]\) and variable
+`dired-omit-mode' (\\[dired-omit-mode]) and variable
 `dired-omit-extensions'.  The default is to omit  `.', `..', auto-save
 files and lock files."
   :type 'regexp
@@ -162,6 +172,7 @@ files and lock files."
 (defcustom dired-omit-verbose t
   "When non-nil, show messages when omitting files.
 When nil, don't show messages."
+  :version "24.1"
   :type 'boolean
   :group 'dired-x)
 
@@ -170,7 +181,7 @@ When nil, don't show messages."
 If nil, Dired finds the directory as a subdirectory in some other buffer
 if it is present as one.
 
-If there are several dired buffers for a directory, the most recently
+If there are several Dired buffers for a directory, the most recently
 used is chosen.
 
 Dired avoids switching to the current buffer, so that if you have
@@ -179,12 +190,6 @@ toggle between those two."
   :type 'boolean
   :group 'dired-x)
 
-(defcustom dired-omit-size-limit 30000
-  "Maximum size for the \"omitting\" feature.
-If nil, there is no maximum size."
-  :type '(choice (const :tag "no maximum" nil) integer)
-  :group 'dired-x)
-
 (defcustom dired-enable-local-variables t
   "Control use of local-variables lists in Dired.
 This temporarily overrides the value of `enable-local-variables' when
@@ -236,7 +241,7 @@ to nil: a pipe using `zcat' or `gunzip -c' will be used."
 
 ;;; KEY BINDINGS.
 
-(define-key dired-mode-map "\M-o" 'dired-omit-mode)
+(define-key dired-mode-map "\C-x\M-o" 'dired-omit-mode)
 (define-key dired-mode-map "*O" 'dired-mark-omitted)
 (define-key dired-mode-map "\M-(" 'dired-mark-sexp)
 (define-key dired-mode-map "*(" 'dired-mark-sexp)
@@ -326,9 +331,9 @@ See also the functions:
 ;; Mark files with some extension.
 (defun dired-mark-extension (extension &optional marker-char)
   "Mark all files with a certain EXTENSION for use in later commands.
-A `.' is *not* automatically prepended to the string entered."
-  ;; EXTENSION may also be a list of extensions instead of a single one.
-  ;; Optional MARKER-CHAR is marker to use.
+A `.' is *not* automatically prepended to the string entered.
+EXTENSION may also be a list of extensions instead of a single one.
+Optional MARKER-CHAR is marker to use."
   (interactive "sMarking extension: \nP")
   (or (listp extension)
       (setq extension (list extension)))
@@ -340,7 +345,7 @@ A `.' is *not* automatically prepended to the string entered."
    marker-char))
 
 (defun dired-flag-extension (extension)
-  "In dired, flag all files with a certain EXTENSION for deletion.
+  "In Dired, flag all files with a certain EXTENSION for deletion.
 A `.' is *not* automatically prepended to the string entered."
   (interactive "sFlagging extension: ")
   (dired-mark-extension extension dired-del-marker))
@@ -397,50 +402,54 @@ See variables `dired-texinfo-unclean-extensions',
                                 dired-tex-unclean-extensions
                                 (list ".dvi"))))
 \f
+(defvar tar-superior-buffer)
 ;;; JUMP.
 
 ;;;###autoload
 (defun dired-jump (&optional other-window file-name)
-  "Jump to dired buffer corresponding to current buffer.
-If in a file, dired the current directory and move to file's line.
+  "Jump to Dired buffer corresponding to current buffer.
+If in a file, Dired the current directory and move to file's line.
 If in Dired already, pop up a level and goto old directory's line.
-In case the proper dired file line cannot be found, refresh the dired
+In case the proper Dired file line cannot be found, refresh the dired
 buffer and try again.
-When OTHER-WINDOW is non-nil, jump to dired buffer in other window.
+When OTHER-WINDOW is non-nil, jump to Dired buffer in other window.
 Interactively with prefix argument, read FILE-NAME and
 move to its line in dired."
   (interactive
    (list nil (and current-prefix-arg
-                 (read-file-name "Jump to dired file: "))))
-  (let* ((file (or file-name buffer-file-name))
-         (dir (if file (file-name-directory file) default-directory)))
-    (if (and (eq major-mode 'dired-mode) (null file-name))
-        (progn
-          (setq dir (dired-current-directory))
-          (dired-up-directory other-window)
-          (unless (dired-goto-file dir)
-              ;; refresh and try again
-            (dired-insert-subdir (file-name-directory dir))
-            (dired-goto-file dir)))
-      (if other-window
-          (dired-other-window dir)
-        (dired dir))
-      (if file
-          (or (dired-goto-file file)
+                  (read-file-name "Jump to Dired file: "))))
+  (if (bound-and-true-p tar-subfile-mode)
+      (switch-to-buffer tar-superior-buffer)
+    (let* ((file (or file-name buffer-file-name))
+           (dir (if file (file-name-directory file) default-directory)))
+      (if (and (eq major-mode 'dired-mode) (null file-name))
+          (progn
+            (setq dir (dired-current-directory))
+            (dired-up-directory other-window)
+            (unless (dired-goto-file dir)
               ;; refresh and try again
-              (progn
-                (dired-insert-subdir (file-name-directory file))
-                (dired-goto-file file))
-              ;; Toggle omitting, if it is on, and try again.
-             (when dired-omit-mode
-                (dired-omit-mode)
-                (dired-goto-file file)))))))
+              (dired-insert-subdir (file-name-directory dir))
+              (dired-goto-file dir)))
+        (if other-window
+            (dired-other-window dir)
+          (dired dir))
+        (if file
+            (or (dired-goto-file file)
+                ;; refresh and try again
+                (progn
+                  (dired-insert-subdir (file-name-directory file))
+                  (dired-goto-file file))
+                ;; Toggle omitting, if it is on, and try again.
+                (when dired-omit-mode
+                  (dired-omit-mode)
+                  (dired-goto-file file))))))))
 
+;;;###autoload
 (defun dired-jump-other-window (&optional file-name)
   "Like \\[dired-jump] (`dired-jump') but in other window."
   (interactive
    (list (and current-prefix-arg
-             (read-file-name "Jump to dired file: "))))
+             (read-file-name "Jump to Dired file: "))))
   (dired-jump t file-name))
 \f
 ;;; OMITTING.
@@ -480,12 +489,12 @@ Should never be used as marker by the user or other packages.")
           dired-latex-unclean-extensions
           dired-bibtex-unclean-extensions
           dired-texinfo-unclean-extensions)
-  "If non-nil, a list of extensions \(strings\) to omit from Dired listings.
+  "If non-nil, a list of extensions (strings) to omit from Dired listings.
 Defaults to elements of `completion-ignored-extensions',
 `dired-latex-unclean-extensions', `dired-bibtex-unclean-extensions', and
 `dired-texinfo-unclean-extensions'.
 
-See interactive function `dired-omit-mode' \(\\[dired-omit-mode]\) and
+See interactive function `dired-omit-mode' (\\[dired-omit-mode]) and
 variables `dired-omit-mode' and `dired-omit-files'."
   :type '(repeat string)
   :group 'dired-x)
@@ -545,19 +554,23 @@ This functions works by temporarily binding `dired-marker-char' to
 ;; Returns t if any work was done, nil otherwise.
 (defun dired-mark-unmarked-files (regexp msg &optional unflag-p localp)
   "Mark unmarked files matching REGEXP, displaying MSG.
-REGEXP is matched against the entire file name.
-Does not re-mark files which already have a mark.
+REGEXP is matched against the entire file name.  When called
+interactively, prompt for REGEXP.
 With prefix argument, unflag all those files.
 Optional fourth argument LOCALP is as in `dired-get-filename'."
-  (interactive "P")
+  (interactive
+   (list (read-regexp
+         "Mark unmarked files matching regexp (default all): "
+          nil 'dired-regexp-history)
+        nil current-prefix-arg nil))
   (let ((dired-marker-char (if unflag-p ?\s dired-marker-char)))
     (dired-mark-if
      (and
       ;; not already marked
-      (looking-at " ")
+      (looking-at-p " ")
       ;; uninteresting
       (let ((fn (dired-get-filename localp t)))
-        (and fn (string-match regexp fn))))
+        (and fn (string-match-p regexp fn))))
      msg)))
 
 \f
@@ -574,8 +587,8 @@ filesystem will work.
 
 This is useful if you want to peruse and move around in an ls -lR
 output file, for example one you got from an ftp server.  With
-ange-ftp, you can even dired a directory containing an ls-lR file,
-visit that file and turn on virtual dired mode.  But don't try to save
+ange-ftp, you can even Dired a directory containing an ls-lR file,
+visit that file and turn on Virtual Dired mode.  But don't try to save
 this file, as dired-virtual indents the listing and thus changes the
 buffer.
 
@@ -584,7 +597,7 @@ resume it in a later session.
 
 Type \\<dired-mode-map>\\[revert-buffer] \
 in the Virtual Dired buffer and answer `y' to convert
-the virtual to a real dired buffer again.  You don't have to do this, though:
+the virtual to a real Dired buffer again.  You don't have to do this, though:
 you can relist single subdirs using \\[dired-do-redisplay]."
 
   ;; DIRNAME is the top level directory of the buffer.  It will become
@@ -601,7 +614,7 @@ you can relist single subdirs using \\[dired-do-redisplay]."
   (interactive
    (list (read-string "Virtual Dired directory: " (dired-virtual-guess-dir))))
   (goto-char (point-min))
-  (or (looking-at "  ")
+  (or (looking-at-p "  ")
       ;; if not already indented, do it now:
       (indent-region (point-min) (point-max) 2))
   (or dirname (setq dirname default-directory))
@@ -618,7 +631,7 @@ you can relist single subdirs using \\[dired-do-redisplay]."
   ;; If raw ls listing (not a saved old dired buffer), give it a
   ;; decent subdir headerline:
   (goto-char (point-min))
-  (or (looking-at dired-subdir-regexp)
+  (or (looking-at-p dired-subdir-regexp)
       (insert "  "
              (directory-file-name (file-name-directory default-directory))
              ":\n"))
@@ -658,7 +671,7 @@ nil."
            nil))))
 
 
-(defun dired-virtual-revert (&optional arg noconfirm)
+(defun dired-virtual-revert (&optional _arg _noconfirm)
   (if (not
        (y-or-n-p "Cannot revert a Virtual Dired buffer - switch to Real Dired mode? "))
       (error "Cannot revert a Virtual Dired buffer")
@@ -673,12 +686,12 @@ Useful on `magic-mode-alist' with the regexp
 
   \"^  \\\\(/[^ /]+\\\\)+/?:$\"
 
-to put saved dired buffers automatically into Virtual Dired mode.
+to put saved Dired buffers automatically into Virtual Dired mode.
 
 Also useful for `auto-mode-alist' like this:
 
-  (add-to-list 'auto-mode-alist
-               '(\"[^/]\\\\.dired\\\\'\" . dired-virtual-mode))"
+  (add-to-list \\='auto-mode-alist
+               \\='(\"[^/]\\\\.dired\\\\\\='\" . dired-virtual-mode))"
   (interactive)
   (dired-virtual (dired-virtual-guess-dir)))
 
@@ -704,12 +717,21 @@ Also useful for `auto-mode-alist' like this:
                       (dired-current-directory)
                     default-directory)))
   "Alist of major modes and their opinion on `default-directory'.
-This is given as a Lisp expression to evaluate.  A resulting value of
-nil is ignored in favor of `default-directory'.")
+Each element has the form (MAJOR . EXPRESSION).
+The function `dired-default-directory' evaluates EXPRESSION to
+determine a default directory.")
+
+(put 'dired-default-directory-alist 'risky-local-variable t) ; gets eval'd
+(make-obsolete-variable 'dired-default-directory-alist
+                        "this feature is due to be removed." "24.1")
 
 (defun dired-default-directory ()
-  "Usage like variable `default-directory'.
-Knows about the special cases in variable `dired-default-directory-alist'."
+  "Return the `dired-default-directory-alist' entry for the current major-mode.
+If none, return `default-directory'."
+  ;; It looks like this was intended to be something of a "general"
+  ;; feature, but it only ever seems to have been used in
+  ;; dired-smart-shell-command, and doesn't seem worth keeping around.
+  (declare (obsolete nil "24.1"))
   (or (eval (cdr (assq major-mode dired-default-directory-alist)))
       default-directory))
 
@@ -723,7 +745,9 @@ Knows about the special cases in variable `dired-default-directory-alist'."
                         ((eq major-mode 'dired-mode) (dired-get-filename t t))))
     current-prefix-arg
     shell-command-default-error-buffer))
-  (let ((default-directory (dired-default-directory)))
+  (let ((default-directory (or (and (eq major-mode 'dired-mode)
+                                    (dired-current-directory))
+                               default-directory)))
     (shell-command command output-buffer error-buffer)))
 
 \f
@@ -749,7 +773,7 @@ Knows about the special cases in variable `dired-default-directory-alist'."
 ;;   Dired Buffer.
 
 (defcustom dired-local-variables-file (convert-standard-filename ".dired")
-  "Filename, as string, containing local dired buffer variables to be hacked.
+  "Filename, as string, containing local Dired buffer variables to be hacked.
 If this file found in current directory, then it will be inserted into dired
 buffer and `hack-local-variables' will be run.  See Info node
 `(emacs)File Variables' for more information on local variables.
@@ -760,7 +784,8 @@ See also `dired-enable-local-variables'."
 (make-obsolete-variable 'dired-local-variables-file 'dir-locals-file "24.1")
 
 (defun dired-hack-local-variables ()
-  "Evaluate local variables in `dired-local-variables-file' for dired buffer."
+  "Evaluate local variables in `dired-local-variables-file' for Dired buffer."
+  (declare (obsolete hack-dir-local-variables-non-file-buffer "24.1"))
   (and (stringp dired-local-variables-file)
        (file-exists-p dired-local-variables-file)
        (let ((opoint (point-max))
@@ -774,20 +799,20 @@ See also `dired-enable-local-variables'."
            (insert "\^L\n")
            (insert-file-contents dired-local-variables-file))
          ;; Hack 'em.
-         (let ((buffer-file-name dired-local-variables-file))
-           (hack-local-variables))
-         ;; Make sure that the modeline shows the proper information.
-         (dired-sort-set-modeline)
-         ;; Delete this stuff: `eobp' is used to find last subdir by dired.el.
-         (delete-region opoint (point-max)))))
-
-(make-obsolete 'dired-hack-local-variables
-               'hack-dir-local-variables-non-file-buffer "24.1")
-
-;; Not sure this is worth having a dedicated command for...
+         (unwind-protect
+             (let ((buffer-file-name dired-local-variables-file))
+               (hack-local-variables))
+           ;; Delete this stuff: `eobp' is used to find last subdir by dired.el.
+           (delete-region opoint (point-max)))
+         ;; Make sure that the mode line shows the proper information.
+         (dired-sort-set-mode-line))))
+
+;; Does not seem worth a dedicated command.
+;; See the more general features in files-x.el.
 (defun dired-omit-here-always ()
   "Create `dir-locals-file' setting `dired-omit-mode' to t in `dired-mode'.
 If in a Dired buffer, reverts it."
+  (declare (obsolete add-dir-local-variable "24.1"))
   (interactive)
   (if (file-exists-p dired-local-variables-file)
       (error "Old-style dired-local-variables-file `./%s' found;
@@ -797,7 +822,9 @@ replace it with a dir-locals-file `./%s'"
   (if (file-exists-p dir-locals-file)
       (message "File `./%s' already exists." dir-locals-file)
     (with-temp-buffer
-      (insert "((dired-mode . ((dired-omit-mode . t))))\n")
+      (insert "\
+\((dired-mode . ((subdirs . nil)
+                (dired-omit-mode . t))))\n")
       (write-file dir-locals-file))
     ;; Run extra-hooks and revert directory.
     (when (derived-mode-p 'dired-mode)
@@ -840,11 +867,11 @@ replace it with a dir-locals-file `./%s'"
 ;; NOTE: Use `gunzip -c' instead of `zcat' on `.gz' files.  Some do not
 ;; install GNU zip's version of zcat.
 
-(declare-function Man-support-local-filenames "man" ())
+(autoload 'Man-support-local-filenames "man")
 
 (defvar dired-guess-shell-alist-default
   (list
-   (list "\\.tar$"
+   (list "\\.tar\\'"
         '(if dired-guess-shell-gnutar
              (concat dired-guess-shell-gnutar " xvf")
            "tar xvf")
@@ -862,7 +889,7 @@ replace it with a dir-locals-file `./%s'"
 
    ;; REGEXPS for compressed archives must come before the .Z rule to
    ;; be recognized:
-   (list "\\.tar\\.Z$"
+   (list "\\.tar\\.Z\\'"
         ;; Untar it.
         '(if dired-guess-shell-gnutar
              (concat dired-guess-shell-gnutar " zxvf")
@@ -872,7 +899,7 @@ replace it with a dir-locals-file `./%s'"
                  " " dired-guess-shell-znew-switches))
 
    ;; gzip'ed archives
-   (list "\\.t\\(ar\\.\\)?gz$"
+   (list "\\.t\\(ar\\.\\)?gz\\'"
         '(if dired-guess-shell-gnutar
              (concat dired-guess-shell-gnutar " zxvf")
            (concat "gunzip -qc * | tar xvf -"))
@@ -892,7 +919,7 @@ replace it with a dir-locals-file `./%s'"
            (concat "gunzip -qc * | tar tvf -")))
 
    ;; bzip2'ed archives
-   (list "\\.t\\(ar\\.bz2\\|bz\\)$"
+   (list "\\.t\\(ar\\.bz2\\|bz\\)\\'"
         "bunzip2 -c * | tar xvf -"
         ;; Extract files into a separate subdirectory
         '(concat "mkdir " (file-name-sans-extension file)
@@ -902,7 +929,7 @@ replace it with a dir-locals-file `./%s'"
         "bunzip2")
 
    ;; xz'ed archives
-   (list "\\.t\\(ar\\.\\)?xz$"
+   (list "\\.t\\(ar\\.\\)?xz\\'"
         "unxz -c * | tar xvf -"
         ;; Extract files into a separate subdirectory
         '(concat "mkdir " (file-name-sans-extension file)
@@ -911,94 +938,105 @@ replace it with a dir-locals-file `./%s'"
         ;; Optional decompression.
         "unxz")
 
-   '("\\.shar\\.Z$" "zcat * | unshar")
-   '("\\.shar\\.g?z$" "gunzip -qc * | unshar")
+   '("\\.shar\\.Z\\'" "zcat * | unshar")
+   '("\\.shar\\.g?z\\'" "gunzip -qc * | unshar")
 
-   '("\\.e?ps$" "ghostview" "xloadimage" "lpr")
-   (list "\\.e?ps\\.g?z$" "gunzip -qc * | ghostview -"
+   '("\\.e?ps\\'" "ghostview" "xloadimage" "lpr")
+   (list "\\.e?ps\\.g?z\\'" "gunzip -qc * | ghostview -"
         ;; Optional decompression.
         '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
-   (list "\\.e?ps\\.Z$" "zcat * | ghostview -"
+   (list "\\.e?ps\\.Z\\'" "zcat * | ghostview -"
         ;; Optional conversion to gzip format.
         '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
                  " " dired-guess-shell-znew-switches))
 
-   '("\\.patch$" "cat * | patch")
-   (list "\\.patch\\.g?z$" "gunzip -qc * | patch"
+   '("\\.patch\\'" "cat * | patch")
+   (list "\\.patch\\.g?z\\'" "gunzip -qc * | patch"
         ;; Optional decompression.
         '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
-   (list "\\.patch\\.Z$" "zcat * | patch"
+   (list "\\.patch\\.Z\\'" "zcat * | patch"
         ;; Optional conversion to gzip format.
         '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
                  " " dired-guess-shell-znew-switches))
 
    ;; The following four extensions are useful with dired-man ("N" key)
-   (list "\\.\\(?:[0-9]\\|man\\)$" '(progn (require 'man)
-                                          (if (Man-support-local-filenames)
-                                              "man -l"
-                                            "cat * | tbl | nroff -man -h")))
-   (list "\\.\\(?:[0-9]\\|man\\)\\.g?z$" '(progn (require 'man)
-                                                (if (Man-support-local-filenames)
-                                                    "man -l"
-                                                  "gunzip -qc * | tbl | nroff -man -h"))
+   ;; FIXME "man ./" does not work with dired-do-shell-command,
+   ;; because there seems to be no way for us to modify the filename,
+   ;; only the command.  Hmph.  `dired-man' works though.
+   (list "\\.\\(?:[0-9]\\|man\\)\\'"
+         '(let ((loc (Man-support-local-filenames)))
+            (cond ((eq loc 'man-db) "man -l")
+                  ((eq loc 'man) "man ./")
+                  (t
+                   "cat * | tbl | nroff -man -h | col -b"))))
+   (list "\\.\\(?:[0-9]\\|man\\)\\.g?z\\'"
+         '(let ((loc (Man-support-local-filenames)))
+            (cond ((eq loc 'man-db)
+                   "man -l")
+                  ((eq loc 'man)
+                   "man ./")
+                  (t "gunzip -qc * | tbl | nroff -man -h | col -b")))
         ;; Optional decompression.
         '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
-   (list "\\.[0-9]\\.Z$" '(progn (require 'man)
-                                (if (Man-support-local-filenames)
-                                    "man -l"
-                                  "zcat * | tbl | nroff -man -h"))
+   (list "\\.[0-9]\\.Z\\'"
+         '(let ((loc (Man-support-local-filenames)))
+            (cond ((eq loc 'man-db) "man -l")
+                  ((eq loc 'man) "man ./")
+                  (t "zcat * | tbl | nroff -man -h | col -b")))
         ;; Optional conversion to gzip format.
         '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
                  " " dired-guess-shell-znew-switches))
-   '("\\.pod$" "perldoc" "pod2man * | nroff -man")
-
-   '("\\.dvi$" "xdvi" "dvips")         ; preview and printing
-   '("\\.au$" "play")                  ; play Sun audiofiles
-   '("\\.mpe?g$\\|\\.avi$" "xine -p")
-   '("\\.ogg$" "ogg123")
-   '("\\.mp3$" "mpg123")
-   '("\\.wav$" "play")
-   '("\\.uu$" "uudecode")              ; for uudecoded files
-   '("\\.hqx$" "mcvert")
-   '("\\.sh$" "sh")                    ; execute shell scripts
-   '("\\.xbm$" "bitmap")               ; view X11 bitmaps
-   '("\\.gp$" "gnuplot")
-   '("\\.p[bgpn]m$" "xloadimage")
-   '("\\.gif$" "xloadimage")           ; view gif pictures
-   '("\\.tif$" "xloadimage")
-   '("\\.png$" "display")              ; xloadimage 4.1 doesn't grok PNG
-   '("\\.jpe?g$" "xloadimage")
-   '("\\.fig$" "xfig")                 ; edit fig pictures
-   '("\\.out$" "xgraph")               ; for plotting purposes.
-   '("\\.tex$" "latex" "tex")
-   '("\\.texi\\(nfo\\)?$" "makeinfo" "texi2dvi")
-   '("\\.pdf$" "xpdf")
-   '("\\.doc$" "antiword" "strings")
-   '("\\.rpm$" "rpm -qilp" "rpm -ivh")
-   '("\\.dia$" "dia")
-   '("\\.mgp$" "mgp")
+   '("\\.pod\\'" "perldoc" "pod2man * | nroff -man")
+
+   '("\\.dvi\\'" "xdvi" "dvips")       ; preview and printing
+   '("\\.au\\'" "play")                        ; play Sun audiofiles
+   '("\\.mpe?g\\'\\|\\.avi\\'" "xine -p")
+   '("\\.ogg\\'" "ogg123")
+   '("\\.mp3\\'" "mpg123")
+   '("\\.wav\\'" "play")
+   '("\\.uu\\'" "uudecode")            ; for uudecoded files
+   '("\\.hqx\\'" "mcvert")
+   '("\\.sh\\'" "sh")                  ; execute shell scripts
+   '("\\.xbm\\'" "bitmap")             ; view X11 bitmaps
+   '("\\.gp\\'" "gnuplot")
+   '("\\.p[bgpn]m\\'" "xloadimage")
+   '("\\.gif\\'" "xloadimage")         ; view gif pictures
+   '("\\.tif\\'" "xloadimage")
+   '("\\.png\\'" "display")            ; xloadimage 4.1 doesn't grok PNG
+   '("\\.jpe?g\\'" "xloadimage")
+   '("\\.fig\\'" "xfig")               ; edit fig pictures
+   '("\\.out\\'" "xgraph")             ; for plotting purposes.
+   '("\\.tex\\'" "latex" "tex")
+   '("\\.texi\\(nfo\\)?\\'" "makeinfo" "texi2dvi")
+   '("\\.pdf\\'" "xpdf")
+   '("\\.doc\\'" "antiword" "strings")
+   '("\\.rpm\\'" "rpm -qilp" "rpm -ivh")
+   '("\\.dia\\'" "dia")
+   '("\\.mgp\\'" "mgp")
 
    ;; Some other popular archivers.
-   (list "\\.zip$" "unzip" "unzip -l"
+   (list "\\.zip\\'" "unzip" "unzip -l"
         ;; Extract files into a separate subdirectory
         '(concat "unzip" (if dired-guess-shell-gzip-quiet " -q")
                  " -d " (file-name-sans-extension file)))
-   '("\\.zoo$" "zoo x//")
-   '("\\.lzh$" "lharc x")
-   '("\\.arc$" "arc x")
-   '("\\.shar$" "unshar")
+   '("\\.zoo\\'" "zoo x//")
+   '("\\.lzh\\'" "lharc x")
+   '("\\.arc\\'" "arc x")
+   '("\\.shar\\'" "unshar")
+   '("\\.rar\\'" "unrar x")
+   '("\\.7z\\'" "7z x")
 
    ;; Compression.
-   (list "\\.g?z$" '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
-   (list "\\.dz$" "dictunzip")
-   (list "\\.bz2$" "bunzip2")
-   (list "\\.xz$" "unxz")
-   (list "\\.Z$" "uncompress"
+   (list "\\.g?z\\'" '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
+   (list "\\.dz\\'" "dictunzip")
+   (list "\\.bz2\\'" "bunzip2")
+   (list "\\.xz\\'" "unxz")
+   (list "\\.Z\\'" "uncompress"
         ;; Optional conversion to gzip format.
         '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
                  " " dired-guess-shell-znew-switches))
 
-   '("\\.sign?$" "gpg --verify"))
+   '("\\.sign?\\'" "gpg --verify"))
 
   "Default alist used for shell command guessing.
 See `dired-guess-shell-alist-user'.")
@@ -1010,10 +1048,11 @@ These rules take precedence over the predefined rules in the variable
 
 Each element of this list looks like
 
-    \(REGEXP COMMAND...\)
+    (REGEXP COMMAND...)
 
 where each COMMAND can either be a string or a Lisp expression that evaluates
-to a string.  If several COMMANDs are given, the first one will be the default
+to a string.  This expression can access the file name as the variable `file'.
+If several COMMANDs are given, the first one will be the default
 and the rest will be added temporarily to the history and can be retrieved
 with \\[previous-history-element] (M-p) .
 
@@ -1023,13 +1062,12 @@ REGEXP is matched case-sensitively.
 You can set this variable in your ~/.emacs.  For example, to add rules for
 `.foo' and `.bar' files, write
 
- \(setq dired-guess-shell-alist-user
-       (list (list \"\\\\.foo\\\\'\" \"FOO-COMMAND\");; fixed rule
-              ;; possibly more rules ...
-              (list \"\\\\.bar\\\\'\";; rule with condition test
-                    '(if condition
-                          \"BAR-COMMAND-1\"
-                        \"BAR-COMMAND-2\")))\)"
+ (setq dired-guess-shell-alist-user
+        '((\"\\\\.foo\\\\'\" \"FOO-COMMAND\")
+          (\"\\\\.bar\\\\'\"
+           (if condition
+              \"BAR-COMMAND-1\"
+            \"BAR-COMMAND-2\"))))"
   :group 'dired-x
   :type '(alist :key-type regexp :value-type (repeat sexp)))
 
@@ -1040,7 +1078,7 @@ You can set this variable in your ~/.emacs.  For example, to add rules for
   :type 'boolean)
 
 (defun dired-guess-default (files)
-  "Guess a shell commands for FILES.  Return command or list of commands.
+  "Return a shell command, or a list of commands, appropriate for FILES.
 See `dired-guess-shell-alist-user'."
 
   (let* ((case-fold-search dired-guess-shell-case-fold-search)
@@ -1056,13 +1094,13 @@ See `dired-guess-shell-alist-user'."
       (setq elt (car alist)
             regexp (car elt)
             alist (cdr alist))
-      (if (string-match regexp file)
+      (if (string-match-p regexp file)
           (setq cmds (cdr elt)
                 alist nil)))
 
     ;; If more than one file, see if all of FILES match regular expression.
     (while (and flist
-                (string-match regexp (car flist)))
+                (string-match-p regexp (car flist)))
       (setq flist (cdr flist)))
 
     ;; If flist is still non-nil, then do not guess since this means that not
@@ -1072,8 +1110,8 @@ See `dired-guess-shell-alist-user'."
     ;; Return commands or nil if flist is still non-nil.
     ;; Evaluate the commands in order that any logical testing will be done.
     (if (cdr cmds)
-        (mapcar #'eval cmds)
-      (eval (car cmds))))) ; single command
+       (delete-dups (mapcar (lambda (cmd) (eval cmd `((file . ,file)))) cmds))
+      (eval (car cmds) `((file . ,file))))))           ; single command
 
 (defun dired-guess-shell-command (prompt files)
   "Ask user with PROMPT for a shell command, guessing a default from FILES."
@@ -1082,6 +1120,7 @@ See `dired-guess-shell-alist-user'."
     (if (null default)
         ;; Nothing to guess
         (read-shell-command prompt nil 'dired-shell-command-history)
+      (setq prompt (replace-regexp-in-string ": $" " " prompt))
       (if (listp default)
           ;; More than one guess
           (setq default-list default
@@ -1092,7 +1131,7 @@ See `dired-guess-shell-alist-user'."
         ;; Just one guess
         (setq default-list (list default)))
       ;; Put the first guess in the prompt but not in the initial value.
-      (setq prompt (concat prompt (format "[%s] " default)))
+      (setq prompt (concat prompt (format "[%s]: " default)))
       ;; All guesses can be retrieved with M-n
       (setq val (read-shell-command prompt nil
                                     'dired-shell-command-history
@@ -1151,7 +1190,7 @@ results in
           (setq count (1+ count)
                 start (1+ start)))
         ;; ... and prepend a "../" for each slash found:
-        (dotimes (n count)
+        (dotimes (_ count)
           (setq name1 (concat "../" name1)))))
     (make-symbolic-link
      (directory-file-name name1)        ; must not link to foo/
@@ -1224,7 +1263,7 @@ Remaining lines go to bottom-most window.  The number of files that can be
 displayed this way is restricted by the height of the current window and
 `window-min-height'.
 
-To keep dired buffer displayed, type \\[split-window-vertically] first.
+To keep Dired buffer displayed, type \\[split-window-below] first.
 To display just marked files, type \\[delete-other-windows] first."
   (interactive "P")
   (dired-simultaneous-find-file (dired-get-marked-files) noselect))
@@ -1264,6 +1303,8 @@ NOSELECT the files are merely found but not selected."
 
 (declare-function Man-getpage-in-background "man" (topic))
 
+(defvar manual-program) ; from man.el
+
 (defun dired-man ()
   "Run `man' on this file."
 ;; Used also to say: "Display old buffer if buffer name matches filename."
@@ -1308,13 +1349,20 @@ Otherwise obeys the value of `dired-vm-read-only-folders'."
   (rmail (dired-get-filename)))
 
 (defun dired-do-run-mail ()
-  "If `dired-bind-vm' is non-nil, call `dired-vm', else call `dired-rmail'."
+  "Visit the current file as a mailbox, using VM or RMAIL.
+Prompt for confirmation first; if the user says yes, call
+`dired-vm' if `dired-bind-vm' is non-nil, `dired-rmail'
+otherwise."
   (interactive)
-  (if dired-bind-vm
-      ;; Read mail folder using vm.
-      (dired-vm)
-    ;; Read mail folder using rmail.
-    (dired-rmail)))
+  (let ((file (dired-get-filename t)))
+    (if dired-bind-vm
+       (if (y-or-n-p (format-message
+                      "Visit `%s' as a mail folder with VM?" file))
+           (dired-vm))
+      ;; Read mail folder using rmail.
+      (if (y-or-n-p (format-message
+                    "Visit `%s' as a mailbox with RMAIL?" file))
+         (dired-rmail)))))
 
 \f
 ;;; MISCELLANEOUS INTERNAL FUNCTIONS.
@@ -1351,11 +1399,28 @@ Considers buffers closer to the car of `buffer-list' to be more recent."
 ;;     result))
 
 \f
+;; Needed if ls -lh is supported and also for GNU ls -ls.
+(defun dired-x--string-to-number (str)
+  "Like `string-to-number' but recognize a trailing unit prefix.
+For example, 2K is expanded to 2048.0.  The caller should make
+sure that a trailing letter in STR is one of BKkMGTPEZY."
+  (let* ((val (string-to-number str))
+         (u (unless (zerop val)
+              (aref str (1- (length str))))))
+    (when (and u (> u ?9))
+      (when (= u ?k)
+        (setq u ?K))
+      (let ((units '(?B ?K ?M ?G ?T ?P ?E ?Z ?Y)))
+        (while (and units (/= (pop units) u))
+          (setq val (* 1024.0 val)))))
+    val))
+
 ;; Does anyone use this? - lrd 6/29/93.
 ;; Apparently people do use it. - lrd 12/22/97.
+
 (defun dired-mark-sexp (predicate &optional unflag-p)
   "Mark files for which PREDICATE returns non-nil.
-With a prefix arg, unflag those files instead.
+With a prefix arg, unmark or unflag those files instead.
 
 PREDICATE is a lisp expression that can refer to the following symbols:
 
@@ -1376,7 +1441,19 @@ For example, use
 
         (equal 0 size)
 
-to mark all zero length files."
+to mark all zero length files.
+
+There's an ambiguity when a single integer not followed by a unit
+prefix precedes the file mode: It is then parsed as inode number
+and not as block size (this always works for GNU coreutils ls).
+
+Another limitation is that the uid field is needed for the
+function to work correctly.  In particular, the field is not
+present for some values of `ls-lisp-emulation'.
+
+This function operates only on the buffer content and does not
+refer at all to the underlying file system.  Contrast this with
+`find-dired', which might be preferable for the task at hand."
   ;; Using sym="" instead of nil avoids the trap of
   ;; (string-match "foo" sym) into which a user would soon fall.
   ;; Give `equal' instead of `=' in the example, as this works on
@@ -1396,56 +1473,96 @@ to mark all zero length files."
         ;; to nil or the appropriate value, so they need not be initialized.
         ;; Moves point within the current line.
         (dired-move-to-filename)
-        (let (pos
-              (mode-len 10) ; length of mode string
-              ;; like in dired.el, but with subexpressions \1=inode, \2=s:
-              (dired-re-inode-size "\\s *\\([0-9]*\\)\\s *\\([0-9]*\\) ?"))
-          (beginning-of-line)
-          (forward-char 2)
-          (if (looking-at dired-re-inode-size)
-              (progn
-                (goto-char (match-end 0))
-                (setq inode (string-to-number
-                             (buffer-substring (match-beginning 1)
-                                               (match-end 1)))
-                      s (string-to-number
-                         (buffer-substring (match-beginning 2)
-                                           (match-end 2)))))
-            (setq inode nil
-                  s nil))
+        (let ((mode-len 10) ; length of mode string
+             ;; like in dired.el, but with subexpressions \1=inode, \2=s:
+             ;; GNU ls -hs suffixes the block count with a unit and
+             ;; prints it as a float, FreeBSD does neither.
+             (dired-re-inode-size "\\=\\s *\\([0-9]+\\s +\\)?\
+\\(?:\\([0-9]+\\(?:\\.[0-9]*\\)?[BkKMGTPEZY]?\\)? ?\\)"))
+         (beginning-of-line)
+         (forward-char 2)
+         (search-forward-regexp dired-re-inode-size nil t)
+          ;; XXX Might be a size not followed by a unit prefix.
+          ;; We could set s to inode if it were otherwise nil,
+          ;; with a similar reasoning as below for setting gid to uid,
+          ;; but it would be even more whimsical.
+         (setq inode (when (match-string 1)
+                       (string-to-number (match-string 1))))
+         (setq s (when (match-string 2)
+                   (dired-x--string-to-number (match-string 2))))
           (setq mode (buffer-substring (point) (+ mode-len (point))))
           (forward-char mode-len)
+          ;; Skip any extended attributes marker ("." or "+").
+          (or (looking-at " ")
+              (forward-char 1))
           (setq nlink (read (current-buffer)))
           ;; Karsten Wenger <kw@cis.uni-muenchen.de> fixed uid.
-          (setq uid (buffer-substring (1+ (point))
-                                      (progn (forward-word 1) (point))))
-          (re-search-forward directory-listing-before-filename-regexp)
-          (goto-char (match-beginning 1))
-          (forward-char -1)
-          (setq size (string-to-number
-                      (buffer-substring (save-excursion
-                                          (backward-word 1)
-                                          (setq pos (point)))
+          ;; Another issue is that GNU ls -n right-justifies numerical
+          ;; UIDs and GIDs, while FreeBSD left-justifies them, so
+          ;; don't rely on a specific whitespace layout.  Both of them
+          ;; right-justify all other numbers, though.
+          ;; XXX Return a number if the uid or gid seems to be
+          ;; numerical?
+          (setq uid (buffer-substring (progn
+                                        (skip-chars-forward " \t")
+                                        (point))
+                                      (progn
+                                        (skip-chars-forward "^ \t")
                                         (point))))
-          (goto-char pos)
-          (backward-word 1)
-          ;; if no gid is displayed, gid will be set to uid
-          ;; but user will then not reference it anyway in PREDICATE.
-          (setq gid (buffer-substring (save-excursion
-                                        (forward-word 1) (point))
+         (dired-move-to-filename)
+          (save-excursion
+            (setq time
+                  ;; The regexp below tries to match from the last
+                  ;; digit of the size field through a space after the
+                  ;; date.  Also, dates may have different formats
+                  ;; depending on file age, so the date column need
+                  ;; not be aligned to the right.
+                  (buffer-substring (save-excursion
+                                      (skip-chars-backward " \t")
                                       (point))
-                time (buffer-substring (match-beginning 1)
-                                       (1- (dired-move-to-filename)))
-                name (buffer-substring (point)
-                                       (or
-                                        (dired-move-to-end-of-filename t)
-                                        (point)))
-                sym (if (looking-at " -> ")
-                        (buffer-substring (progn (forward-char 4) (point))
-                                          (line-end-position))
-                      ""))
+                                    (progn
+                                      (re-search-backward
+                                       directory-listing-before-filename-regexp)
+                                      (skip-chars-forward "^ \t")
+                                      (1+ (point))))
+                  size (dired-x--string-to-number
+                        ;; We know that there's some kind of number
+                        ;; before point because the regexp search
+                        ;; above succeeded.  I don't think it's worth
+                        ;; doing an extra check for leading garbage.
+                        (buffer-substring (point)
+                                          (progn
+                                            (skip-chars-backward "^ \t")
+                                            (point))))
+                  ;; If no gid is displayed, gid will be set to uid
+                  ;; but the user will then not reference it anyway in
+                  ;; PREDICATE.
+                  gid (buffer-substring (progn
+                                          (skip-chars-backward " \t")
+                                          (point))
+                                        (progn
+                                          (skip-chars-backward "^ \t")
+                                          (point)))))
+         (setq name (buffer-substring (point)
+                                      (or
+                                       (dired-move-to-end-of-filename t)
+                                       (point)))
+               sym (if (looking-at " -> ")
+                       (buffer-substring (progn (forward-char 4) (point))
+                                         (line-end-position))
+                     ""))
           t)
-        (eval predicate)))
+        (eval predicate
+              `((inode . ,inode)
+                (s . ,s)
+                (mode . ,mode)
+                (nlink . ,nlink)
+                (uid . ,uid)
+                (gid . ,gid)
+                (size . ,size)
+                (time . ,time)
+                (name . ,name)
+                (sym . ,sym)))))
      (format "'%s file" predicate))))
 
 \f
@@ -1458,8 +1575,8 @@ If you change this variable without using \\[customize] after `dired-x.el'
 is loaded then call \\[dired-x-bind-find-file]."
   :type 'boolean
   :initialize 'custom-initialize-default
-  :set (lambda (sym val)
-         (set sym val)
+  :set (lambda (symbol value)
+         (set symbol value)
          (dired-x-bind-find-file))
   :group 'dired-x)
 
@@ -1504,12 +1621,12 @@ Point should be in or after a filename."
   (save-excursion
     ;; First see if just past a filename.
     (or (eobp)                             ; why?
-        (when (looking-at "[] \t\n[{}()]") ; whitespace or some parens
+        (when (looking-at-p "[] \t\n[{}()]") ; whitespace or some parens
           (skip-chars-backward " \n\t\r({[]})")
           (or (bobp) (backward-char 1))))
     (let ((filename-chars "-.[:alnum:]_/:$+@")
           start prefix)
-      (if (looking-at (format "[%s]" filename-chars))
+      (if (looking-at-p (format "[%s]" filename-chars))
           (progn
             (skip-chars-backward filename-chars)
             (setq start (point)
@@ -1517,11 +1634,11 @@ Point should be in or after a filename."
                   ;; This is something to do with ange-ftp filenames.
                   ;; It convert foo@bar to /foo@bar.
                   ;; But when does the former occur in dired buffers?
-                 (and (string-match
+                 (and (string-match-p
                        "^\\w+@"
                        (buffer-substring start (line-end-position)))
                       "/"))
-            (if (string-match "[/~]" (char-to-string (preceding-char)))
+            (if (string-match-p "[/~]" (char-to-string (preceding-char)))
                 (setq start (1- start)))
             (skip-chars-forward filename-chars))
         (error "No file found around point!"))
@@ -1552,7 +1669,7 @@ If `current-prefix-arg' is non-nil, uses name at point as guess."
 
 ;; Local Variables:
 ;; byte-compile-dynamic: t
-;; generated-autoload-file: "dired.el"
+;; generated-autoload-file: "dired-loaddefs.el"
 ;; End:
 
 ;;; dired-x.el ends here