Merge from emacs-23
[bpt/emacs.git] / lisp / dired.el
index 3f16581..56030fe 100644 (file)
@@ -1,12 +1,13 @@
 ;;; dired.el --- directory-browsing commands
 
 ;; Copyright (C) 1985, 1986, 1992, 1993, 1994, 1995, 1996, 1997, 2000,
-;;   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+;;   2001, 2002, 2003, 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.
 
@@ -72,15 +73,18 @@ If nil, `dired-listing-switches' is used.")
 ;;;###autoload
 (defvar dired-chown-program
   (purecopy
-  (if (memq system-type '(hpux usg-unix-v irix linux gnu/linux cygwin))
+  (if (memq system-type '(hpux usg-unix-v irix gnu/linux cygwin))
       "chown"
     (if (file-exists-p "/usr/sbin/chown")
        "/usr/sbin/chown"
       "/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-use-ls-dired 'unspecified
+  "Non-nil means Dired should use \"ls --dired\".
+The special value of `unspecified' means to check explicitly, and
+save the result in this variable.  This is performed the first
+time `dired-insert-directory' is called.")
 
 (defvar dired-chmod-program "chmod"
   "Name of chmod command (usually `chmod').")
@@ -1056,7 +1060,14 @@ 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))
+    (if (or (if (eq dired-use-ls-dired 'unspecified)
+               ;; Check whether "ls --dired" gives exit code 0, and
+               ;; save the answer in `dired-use-ls-dired'.
+               (setq dired-use-ls-dired
+                     (eq (call-process insert-directory-program nil nil nil "--dired")
+                         0))
+             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,
@@ -1144,8 +1155,12 @@ Preserves old cursor, marks/flags, hidden-p."
     (setq mark-alist;; only after dired-remember-hidden since this unhides:
          (dired-remember-marks (point-min) (point-max)))
     ;; treat top level dir extra (it may contain wildcards)
-    (dired-uncache
-     (if (consp dired-directory) (car dired-directory) dired-directory))
+    (if (not (consp dired-directory))
+       (dired-uncache dired-directory)
+      (dired-uncache (car dired-directory))
+      (dolist (dir (cdr dired-directory))
+       (if (file-name-absolute-p dir)
+           (dired-uncache dir))))
     ;; Run dired-after-readin-hook just once, below.
     (let ((dired-after-readin-hook nil))
       (dired-readin)
@@ -1173,7 +1188,7 @@ Preserves old cursor, marks/flags, hidden-p."
 The positions have the form (BUFFER-POSITION WINDOW-POSITIONS).
 
 BUFFER-POSITION is the point position in the current dired buffer.
-The buffer position have the form (BUFFER DIRED-FILENAME BUFFER-POINT).
+It has the form (BUFFER DIRED-FILENAME BUFFER-POINT).
 
 WINDOW-POSITIONS are current positions in all windows displaying
 this dired buffer.  The window positions have the form (WINDOW
@@ -1376,10 +1391,8 @@ Do so according to the former subdir alist OLD-SUBDIR-ALIST."
     (define-key map ">" 'dired-next-dirline)
     (define-key map "^" 'dired-up-directory)
     (define-key map " "  'dired-next-line)
-    (define-key map "\C-n" 'dired-next-line)
-    (define-key map "\C-p" 'dired-previous-line)
-    (define-key map [down] 'dired-next-line)
-    (define-key map [up] 'dired-previous-line)
+    (define-key map [remap next-line] 'dired-next-line)
+    (define-key map [remap previous-line] 'dired-previous-line)
     ;; hiding
     (define-key map "$" 'dired-hide-subdir)
     (define-key map "\M-$" 'dired-hide-all)
@@ -1389,7 +1402,7 @@ Do so according to the former subdir alist OLD-SUBDIR-ALIST."
     (define-key map (kbd "M-s f C-s")   'dired-isearch-filenames)
     (define-key map (kbd "M-s f M-C-s") 'dired-isearch-filenames-regexp)
     ;; misc
-    (define-key map "\C-x\C-q" 'dired-toggle-read-only)
+    (define-key map [remap toggle-read-only] 'dired-toggle-read-only)
     (define-key map "?" 'dired-summary)
     (define-key map "\177" 'dired-unmark-backward)
     (define-key map [remap undo] 'dired-undo)
@@ -1405,7 +1418,7 @@ Do so according to the former subdir alist OLD-SUBDIR-ALIST."
     (define-key map "\C-t." 'image-dired-display-thumb)
     (define-key map "\C-tc" 'image-dired-dired-comment-files)
     (define-key map "\C-tf" 'image-dired-mark-tagged-files)
-    (define-key map "\C-t\C-t" 'image-dired-dired-insert-marked-thumbs)
+    (define-key map "\C-t\C-t" 'image-dired-dired-toggle-marked-thumbs)
     (define-key map "\C-te" 'image-dired-dired-edit-comment-and-tags)
     ;; encryption and decryption (epa-dired)
     (define-key map ":d" 'epa-dired-do-decrypt)
@@ -2008,6 +2021,14 @@ Otherwise, an error occurs in these cases."
           ;; with quotation marks in their names.
          (while (string-match "\\(?:[^\\]\\|\\`\\)\\(\"\\)" file)
            (setq file (replace-match "\\\"" nil t file 1)))
+         
+         (when (eq system-type 'windows-nt)
+           (save-match-data
+             (let ((start 0))
+               (while (string-match "\\\\" file start)
+                 (aset file (match-beginning 0) ?/)
+                 (setq start (match-end 0))))))
+
           (setq file (read (concat "\"" file "\"")))
          ;; The above `read' will return a unibyte string if FILE
          ;; contains eight-bit-control/graphic characters.
@@ -2135,7 +2156,7 @@ Return the position of the beginning of the filename, or nil if none found."
       ;; 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))
+           eol (line-end-position)
            hidden (and selective-display
                        (save-excursion (search-forward "\r" eol t))))
       (if hidden
@@ -2223,31 +2244,33 @@ You can then feed the file name(s) to other commands with \\[yank]."
 ;; Keeping Dired buffers in sync with the filesystem and with each other
 
 (defun dired-buffers-for-dir (dir &optional file)
-;; Return a list of buffers that dired DIR (top level or in-situ subdir).
+;; Return a list of buffers for DIR (top level or in-situ subdir).
 ;; If FILE is non-nil, include only those whose wildcard pattern (if any)
 ;; matches FILE.
 ;; The list is in reverse order of buffer creation, most recent last.
 ;; As a side effect, killed dired buffers for DIR are removed from
 ;; dired-buffers.
   (setq dir (file-name-as-directory dir))
-  (let ((alist dired-buffers) result elt buf)
-    (while alist
-      (setq elt (car alist)
-           buf (cdr elt))
-      (if (buffer-name buf)
-         (if (dired-in-this-tree dir (car elt))
-             (with-current-buffer buf
-               (and (assoc dir dired-subdir-alist)
-                    (or (null file)
-                        (let ((wildcards
-                               (file-name-nondirectory dired-directory)))
-                          (or (= 0 (length wildcards))
-                              (string-match (dired-glob-regexp wildcards)
-                                            file))))
-                    (setq result (cons buf result)))))
-       ;; else buffer is killed - clean up:
+  (let (result buf)
+    (dolist (elt dired-buffers)
+      (setq buf (cdr elt))
+      (cond
+       ((null (buffer-name buf))
+       ;; Buffer is killed - clean up:
        (setq dired-buffers (delq elt dired-buffers)))
-      (setq alist (cdr alist)))
+       ((dired-in-this-tree dir (car elt))
+       (with-current-buffer buf
+         (and (assoc dir dired-subdir-alist)
+              (or (null file)
+                  (if (stringp dired-directory)
+                      (let ((wildcards (file-name-nondirectory
+                                        dired-directory)))
+                        (or (= 0 (length wildcards))
+                            (string-match (dired-glob-regexp wildcards)
+                                          file)))
+                    (member (expand-file-name file dir)
+                            (cdr dired-directory))))
+              (setq result (cons buf result)))))))
     result))
 
 (defun dired-glob-regexp (pattern)
@@ -2575,7 +2598,7 @@ Anything else means ask for each directory."
 ;; Delete file, possibly delete a directory and all its files.
 ;; This function is usefull outside of dired.  One could change it's name
 ;; to e.g. recursive-delete-file and put it somewhere else.
-(defun dired-delete-file (file &optional recursive) "\
+(defun dired-delete-file (file &optional recursive trash) "\
 Delete FILE or directory (possibly recursively if optional RECURSIVE is true.)
 RECURSIVE determines what to do with a non-empty directory.  If RECURSIVE is:
 nil, do not delete.
@@ -2586,15 +2609,19 @@ Anything else, ask for each sub-directory."
   ;; (and (file-directory-p fn) (not (file-symlink-p fn)))
   ;; but more efficient
   (if (not (eq t (car (file-attributes file))))
-      (delete-file file)
+      (delete-file file trash)
     (if (and recursive
             (directory-files file t dired-re-no-dot) ; Not empty.
             (or (eq recursive 'always)
-                (yes-or-no-p (format "Recursive delete of %s? "
+                (yes-or-no-p (format "Recursively %s %s? "
+                                     (if (and trash
+                                              delete-by-moving-to-trash)
+                                         "trash"
+                                       "delete")
                                      (dired-make-relative file)))))
        (if (eq recursive 'top) (setq recursive 'always)) ; Don't ask again.
       (setq recursive nil))
-    (delete-directory file recursive)))
+    (delete-directory file recursive trash)))
 
 (defun dired-do-flagged-delete (&optional nomessage)
   "In Dired, delete the files flagged for deletion.
@@ -2612,7 +2639,7 @@ non-empty directories is allowed."
         ;; this can't move point since ARG is nil
         (dired-map-over-marks (cons (dired-get-filename) (point))
                               nil)
-        nil)
+        nil t)
       (or nomessage
          (message "(No deletions requested)")))))
 
@@ -2627,11 +2654,11 @@ non-empty directories is allowed."
    ;; this may move point if ARG is an integer
    (dired-map-over-marks (cons (dired-get-filename) (point))
                         arg)
-   arg))
+   arg t))
 
 (defvar dired-deletion-confirmer 'yes-or-no-p) ; or y-or-n-p?
 
-(defun dired-internal-do-deletions (l arg)
+(defun dired-internal-do-deletions (l arg &optional trash)
   ;; L is an alist of files to delete, with their buffer positions.
   ;; ARG is the prefix arg.
   ;; Filenames are absolute.
@@ -2640,14 +2667,21 @@ non-empty directories is allowed."
   ;; lines still to be changed, so the (point) values in L stay valid.
   ;; Also, for subdirs in natural order, a subdir's files are deleted
   ;; before the subdir itself - the other way around would not work.
-  (let ((files (mapcar (function car) l))
-       (count (length l))
-       (succ 0))
+  (let* ((files (mapcar (function car) l))
+        (count (length l))
+        (succ 0)
+        (trashing (and trash delete-by-moving-to-trash))
+        (progress-reporter
+         (make-progress-reporter
+          (if trashing "Trashing..." "Deleting...")
+          succ count)))
     ;; canonicalize file list for pop up
     (setq files (nreverse (mapcar (function dired-make-relative) files)))
     (if (dired-mark-pop-up
         " *Deletions*" 'delete files dired-deletion-confirmer
-        (format "Delete %s " (dired-mark-prompt arg files)))
+        (format "%s %s "
+                (if trashing "Trash" "Delete")
+                (dired-mark-prompt arg files)))
        (save-excursion
          (let (failures);; files better be in reverse order for this loop!
            (while l
@@ -2655,10 +2689,10 @@ non-empty directories is allowed."
              (let ((inhibit-read-only t))
                (condition-case err
                    (let ((fn (car (car l))))
-                     (dired-delete-file fn dired-recursive-deletes)
+                     (dired-delete-file fn dired-recursive-deletes trash)
                      ;; if we get here, removing worked
                      (setq succ (1+ succ))
-                     (message "%s of %s deletions" succ count)
+                     (progress-reporter-update progress-reporter succ)
                      (dired-fun-in-all-buffers
                       (file-name-directory fn) (file-name-nondirectory fn)
                       (function dired-delete-entry) fn))
@@ -2667,7 +2701,7 @@ non-empty directories is allowed."
                   (setq failures (cons (car (car l)) failures)))))
              (setq l (cdr l)))
            (if (not failures)
-               (message "%d deletion%s done" count (dired-plural-s count))
+               (progress-reporter-done progress-reporter)
              (dired-log-summary
               (format "%d of %d deletion%s failed"
                       (length failures) count
@@ -2741,7 +2775,8 @@ name, or the marker and a count of marked files."
                    ;; that's possible.  (Bug#1806)
                    (split-window-vertically))
               ;; Otherwise, try to split WINDOW sensibly.
-              (split-window-sensibly window)))))
+              (split-window-sensibly window))))
+       pop-up-frames)
     (pop-to-buffer (get-buffer-create buf)))
   ;; If dired-shrink-to-fit is t, make its window fit its contents.
   (when dired-shrink-to-fit
@@ -2750,17 +2785,19 @@ name, or the marker and a count of marked files."
     (fit-window-to-buffer (get-buffer-window buf) nil 1)))
 
 (defcustom dired-no-confirm nil
-  "A list of symbols for commands Dired should not confirm.
+  "A list of symbols for commands Dired should not confirm, or t.
 Command symbols are `byte-compile', `chgrp', `chmod', `chown', `compress',
 `copy', `delete', `hardlink', `load', `move', `print', `shell', `symlink',
-`touch' and `uncompress'."
+`touch' and `uncompress'.
+If t, confirmation is never needed."
   :group 'dired
-  :type '(set (const byte-compile) (const chgrp)
-             (const chmod) (const chown) (const compress)
-             (const copy) (const delete) (const hardlink)
-             (const load) (const move) (const print)
-             (const shell) (const symlink) (const touch)
-             (const uncompress)))
+  :type '(choice (const :tag "Confirmation never needed" t)
+                (set (const byte-compile) (const chgrp)
+                     (const chmod) (const chown) (const compress)
+                     (const copy) (const delete) (const hardlink)
+                     (const load) (const move) (const print)
+                     (const shell) (const symlink) (const touch)
+                     (const uncompress))))
 
 (defun dired-mark-pop-up (bufname op-symbol files function &rest args)
   "Return FUNCTION's result on ARGS after showing which files are marked.
@@ -3231,12 +3268,16 @@ variable `dired-listing-switches'.  To temporarily override the listing
 format, use `\\[universal-argument] \\[dired]'.")
 
 (defvar dired-sort-by-date-regexp
-  (concat "^-[^" dired-ls-sorting-switches
-         "]*t[^" dired-ls-sorting-switches "]*$")
+  (concat "\\(\\`\\| \\)-[^- ]*t"
+         ;; `dired-ls-sorting-switches' after -t overrides -t.
+         "[^ " dired-ls-sorting-switches "]*"
+         "\\(\\(\\`\\| +\\)\\(--[^ ]+\\|-[^- t"
+         dired-ls-sorting-switches "]+\\)\\)* *$")
   "Regexp recognized by Dired to set `by date' mode.")
 
 (defvar dired-sort-by-name-regexp
-  (concat "^-[^t" dired-ls-sorting-switches "]+$")
+  (concat "\\`\\(\\(\\`\\| +\\)\\(--[^ ]+\\|"
+         "-[^- t" dired-ls-sorting-switches "]+\\)\\)* *$")
   "Regexp recognized by Dired to set `by name' mode.")
 
 (defvar dired-sort-inhibit nil
@@ -3262,8 +3303,8 @@ The idea is to set this buffer-locally in special dired buffers.")
     (force-mode-line-update)))
 
 (defun dired-sort-toggle-or-edit (&optional arg)
-  "Toggle between sort by date/name and refresh the dired buffer.
-With a prefix argument you can edit the current listing switches instead."
+  "Toggle sorting by date, and refresh the Dired buffer.
+With a prefix argument, edit the current listing switches instead."
   (interactive "P")
   (when dired-sort-inhibit
     (error "Cannot sort this dired buffer"))
@@ -3274,24 +3315,24 @@ With a prefix argument you can edit the current listing switches instead."
 
 (defun dired-sort-toggle ()
   ;; Toggle between sort by date/name.  Reverts the buffer.
-  (setq dired-actual-switches
-       (let (case-fold-search)
-         (if (string-match " " dired-actual-switches)
-             ;; New toggle scheme: add/remove a trailing " -t"
-             (if (string-match " -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
-            "-l"
-            (dired-replace-in-string (concat "[-lt"
-                                             dired-ls-sorting-switches "]")
-                                     ""
-                                     dired-actual-switches)
-            (if (string-match (concat "[t" dired-ls-sorting-switches "]")
-                              dired-actual-switches)
-                ""
-              "t")))))
+  (let ((sorting-by-date (string-match dired-sort-by-date-regexp
+                                      dired-actual-switches))
+       ;; Regexp for finding (possibly embedded) -t switches.
+       (switch-regexp "\\(\\`\\| \\)-\\([a-su-zA-Z]*\\)\\(t\\)\\([^ ]*\\)")
+       case-fold-search)
+    ;; Remove the -t switch.
+    (while (string-match switch-regexp dired-actual-switches)
+      (if (and (equal (match-string 2 dired-actual-switches) "")
+              (equal (match-string 4 dired-actual-switches) ""))
+         ;; Remove a stand-alone -t switch.
+         (setq dired-actual-switches
+               (replace-match "" t t dired-actual-switches))
+       ;; Remove a switch of the form -XtY for some X and Y.
+       (setq dired-actual-switches
+             (replace-match "" t t dired-actual-switches 3))))
+    ;; Now, if we weren't sorting by date before, add the -t switch.
+    (unless sorting-by-date
+      (setq dired-actual-switches (concat dired-actual-switches " -t"))))
   (dired-sort-set-modeline)
   (revert-buffer))
 
@@ -3517,7 +3558,7 @@ Ask means pop up a menu for the user to select one of copy, move or link."
 ;;;;;;  dired-run-shell-command dired-do-shell-command dired-do-async-shell-command
 ;;;;;;  dired-clean-directory dired-do-print dired-do-touch dired-do-chown
 ;;;;;;  dired-do-chgrp dired-do-chmod dired-compare-directories dired-backup-diff
-;;;;;;  dired-diff) "dired-aux" "dired-aux.el" "20e28554da832d93358ff94eca6aa687")
+;;;;;;  dired-diff) "dired-aux" "dired-aux.el" "2e8658304f56098052e312d01c8763a2")
 ;;; Generated autoloads from dired-aux.el
 
 (autoload 'dired-diff "dired-aux" "\
@@ -3917,7 +3958,7 @@ 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.
 
-\(fn ARG)" t nil)
+\(fn &optional IGNORED)" t nil)
 
 (autoload 'dired-isearch-filenames-setup "dired-aux" "\
 Set up isearch to search in Dired file names.
@@ -3970,7 +4011,7 @@ true then the type of the file linked to by FILE is printed instead.
 ;;;***
 \f
 ;;;### (autoloads (dired-do-relsymlink dired-jump) "dired-x" "dired-x.el"
-;;;;;;  "c1bb83404017aa89655222b2b50471ed")
+;;;;;;  "27c312d6d5d40d8cb4ef8d62e30d5f4a")
 ;;; Generated autoloads from dired-x.el
 
 (autoload 'dired-jump "dired-x" "\
@@ -3979,8 +4020,11 @@ 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
 buffer and try again.
+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.
 
-\(fn &optional OTHER-WINDOW)" t nil)
+\(fn &optional OTHER-WINDOW FILE-NAME)" t nil)
 
 (autoload 'dired-do-relsymlink "dired-x" "\
 Relative symlink all marked (or next ARG) files into a directory.
@@ -4005,5 +4049,4 @@ For absolute symlinks, use \\[dired-do-symlink].
 
 (run-hooks 'dired-load-hook)           ; for your customizations
 
-;; arch-tag: e1af7a8f-691c-41a0-aac1-ddd4d3c87517
 ;;; dired.el ends here