]> code.delx.au - gnu-emacs/blobdiff - lisp/dired-aux.el
(add-log-buffer-file-name-function): Add defvar.
[gnu-emacs] / lisp / dired-aux.el
index d12410afae5073cfff6504ff559e5a9a0089b15c..0d3f6fe125b3df38cfa77f8d5de1c8aae915abd1 100644 (file)
@@ -1,7 +1,7 @@
 ;;; dired-aux.el --- less commonly used parts of dired  -*-byte-compile-dynamic: t;-*-
 
-;; Copyright (C) 1985, 1986, 1992, 1994, 1998, 2000, 2001
-;;   Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1992, 1994, 1998, 2000, 2001, 2002, 2003,
+;;   2004, 2005 Free Software Foundation, Inc.
 
 ;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>.
 ;; Maintainer: FSF
@@ -21,8 +21,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
@@ -64,7 +64,10 @@ With prefix arg, prompt for second argument SWITCHES,
                                   (if default
                                       (concat "(default " default ") ")
                                     ""))
-                          (dired-current-directory) default t)
+                          (if default
+                              (dired-current-directory)
+                            (dired-dwim-target-directory))
+                          default t)
           (if current-prefix-arg
               (read-string "Options for diff: "
                            (if (stringp diff-switches)
@@ -88,11 +91,14 @@ With prefix arg, prompt for argument SWITCHES which is options for `diff'."
       nil))
   (diff-backup (dired-get-filename) switches))
 
+;;;###autoload
 (defun dired-compare-directories (dir2 predicate)
   "Mark files with different file attributes in two dired buffers.
 Compare file attributes of files in the current directory
 with file attributes in directory DIR2 using PREDICATE on pairs of files
 with the same name.  Mark files for which PREDICATE returns non-nil.
+Mark files with different names if PREDICATE is nil (or interactively
+with empty input at the predicate prompt).
 
 PREDICATE is a Lisp expression that can refer to the following variables:
 
@@ -112,23 +118,29 @@ Examples of PREDICATE:
     (not (and (= (nth 2 fa1) (nth 2 fa2))   - mark files with different UID
               (= (nth 3 fa1) (nth 3 fa2))))   and GID."
   (interactive
-   (list (read-file-name (format "Compare %s with: "
-                                (dired-current-directory))
-                        (dired-dwim-target-directory))
-        (read-minibuffer "Mark if (lisp expr): ")))
+   (list (read-directory-name (format "Compare %s with: "
+                                     (dired-current-directory))
+                             (dired-dwim-target-directory)
+                             (dired-dwim-target-directory))
+         (read-from-minibuffer "Mark if (lisp expr or RET): " nil nil t nil "nil")))
   (let* ((dir1 (dired-current-directory))
          (file-alist1 (dired-files-attributes dir1))
          (file-alist2 (dired-files-attributes dir2))
-        (file-list1 (mapcar
+        file-list1 file-list2)
+    (setq file-alist1 (delq (assoc "." file-alist1) file-alist1))
+    (setq file-alist1 (delq (assoc ".." file-alist1) file-alist1))
+    (setq file-alist2 (delq (assoc "." file-alist2) file-alist2))
+    (setq file-alist2 (delq (assoc ".." file-alist2) file-alist2))
+    (setq file-list1 (mapcar
                      'cadr
                       (dired-file-set-difference
                        file-alist1 file-alist2
-                      predicate)))
-        (file-list2 (mapcar
+                      predicate))
+         file-list2 (mapcar
                      'cadr
                       (dired-file-set-difference
                        file-alist2 file-alist1
-                      predicate))))
+                      predicate)))
     (dired-fun-in-all-buffers
      dir1 nil
      (lambda ()
@@ -158,8 +170,8 @@ condition.  Two file items are considered to match if they are equal
        (unless (let ((list list2))
                  (while (and list
                              (not (let* ((file2 (car list))
-                                         (fa1 (caddr file1))
-                                         (fa2 (caddr file2))
+                                         (fa1 (car (cddr file1)))
+                                         (fa2 (car (cddr file2)))
                                          (size1 (nth 7 fa1))
                                          (size2 (nth 7 fa2))
                                          (mtime1 (float-time (nth 5 fa1)))
@@ -183,8 +195,20 @@ List has a form of (file-name full-file-name (attribute-list))"
              (file-attributes full-file-name))))
    (directory-files dir)))
 \f
+
+(defun dired-touch-initial (files)
+  "Create initial input value for `touch' command."
+  (let (initial)
+    (while files
+      (let ((current (nth 5 (file-attributes (car files)))))
+        (if (and initial (not (equal initial current)))
+            (setq initial (current-time) files nil)
+          (setq initial current))
+        (setq files (cdr files))))
+    (format-time-string "%Y%m%d%H%M.%S" initial)))
+
 (defun dired-do-chxxx (attribute-name program op-symbol arg)
-  ;; Change file attributes (mode, group, owner) of marked files and
+  ;; Change file attributes (mode, group, owner, timestamp) of marked files and
   ;; refresh their file lines.
   ;; ATTRIBUTE-NAME is a string describing the attribute to the user.
   ;; PROGRAM is the program used to change the attribute.
@@ -194,14 +218,18 @@ List has a form of (file-name full-file-name (attribute-list))"
         (new-attribute
          (dired-mark-read-string
           (concat "Change " attribute-name " of %s to: ")
-          nil op-symbol arg files))
+          (if (eq op-symbol 'touch) (dired-touch-initial files))
+          op-symbol arg files))
         (operation (concat program " " new-attribute))
         failures)
     (setq failures
          (dired-bunch-files 10000
                             (function dired-check-process)
                             (append
-                             (list operation program new-attribute)
+                             (list operation program)
+                             (if (eq op-symbol 'touch)
+                                 '("-t") nil)
+                             (list new-attribute)
                              (if (string-match "gnu" system-configuration)
                                  '("--") nil))
                             files))
@@ -234,6 +262,13 @@ This calls chmod, thus symbolic modes like `g+w' are allowed."
       (error "chown not supported on this system"))
   (dired-do-chxxx "Owner" dired-chown-program 'chown arg))
 
+;;;###autoload
+(defun dired-do-touch (&optional arg)
+  "Change the timestamp of the marked (or next ARG) files.
+This calls touch."
+  (interactive "P")
+  (dired-do-chxxx "Timestamp" dired-touch-program 'touch arg))
+
 ;; Process all the files in FILES in batches of a convenient size,
 ;; by means of (FUNCALL FUNCTION ARGS... SOME-FILES...).
 ;; Batches are chosen to need less than MAX chars for the file names,
@@ -315,6 +350,7 @@ Uses the shell command coming from variables `lpr-command' and
 
 (defvar dired-file-version-alist)
 
+;;;###autoload
 (defun dired-clean-directory (keep)
   "Flag numerical backups for deletion.
 Spares `dired-kept-versions' latest versions, and `kept-old-versions' oldest.
@@ -397,7 +433,7 @@ with a prefix argument."
         (setq base-version-list        ; there was a base version to which
               (assoc (substring fn 0 start-vn) ; this looks like a
                      dired-file-version-alist))        ; subversion
-        (not (memq (string-to-int (substring fn (+ 2 start-vn)))
+        (not (memq (string-to-number (substring fn (+ 2 start-vn)))
                    base-version-list)) ; this one doesn't make the cut
         (progn (beginning-of-line)
                (delete-char 1)
@@ -524,6 +560,7 @@ the list of file names explicitly with the FILE-LIST argument."
        (funcall stuff-it files)))))
 
 ;; This is an extra function so that it can be redefined by ange-ftp.
+;;;###autoload
 (defun dired-run-shell-command (command)
   (let ((handler
         (find-file-name-handler (directory-file-name default-directory)
@@ -561,8 +598,8 @@ the list of file names explicitly with the FILE-LIST argument."
       (set-buffer err-buffer)
       (erase-buffer)
       (setq default-directory dir      ; caller's default-directory
-           err (/= 0
-                (apply (function dired-call-process) program nil arguments)))
+           err (not (eq 0
+                (apply (function dired-call-process) program nil arguments))))
       (if err
          (progn
            (dired-log (concat program " " (prin1-to-string arguments) "\n"))
@@ -597,9 +634,14 @@ the list of file names explicitly with the FILE-LIST argument."
 (defun dired-do-kill-lines (&optional arg fmt)
   "Kill all marked lines (not the files).
 With a prefix argument, kill that many lines starting with the current line.
-\(A negative argument kills lines before the current line.)
-To kill an entire subdirectory, go to its directory header line
-and use this command with a prefix argument (the value does not matter)."
+\(A negative argument kills backward.)
+If you use this command with a prefix argument to kill the line
+for a file that is a directory, which you have inserted in the
+Dired buffer as a subdirectory, then it deletes that subdirectory
+from the buffer as well.
+To kill an entire subdirectory \(without killing its line in the
+parent directory), go to its directory header line and use this
+command with a prefix argument (the value does not matter)."
   ;; Returns count of killed lines.  FMT="" suppresses message.
   (interactive "P")
   (if arg
@@ -608,23 +650,14 @@ and use this command with a prefix argument (the value does not matter)."
        (dired-kill-line arg))
     (save-excursion
       (goto-char (point-min))
-      (let (buffer-read-only (count 0))
-       (if (not arg)                   ; kill marked lines
-           (let ((regexp (dired-marker-regexp)))
-             (while (and (not (eobp))
-                         (re-search-forward regexp nil t))
-               (setq count (1+ count))
-               (delete-region (progn (beginning-of-line) (point))
-                              (progn (forward-line 1) (point)))))
-         ;; else kill unmarked lines
-         (while (not (eobp))
-           (if (or (dired-between-files)
-                   (not (looking-at "^  ")))
-               (forward-line 1)
-             (setq count (1+ count))
-             (delete-region (point) (save-excursion
-                                      (forward-line 1)
-                                      (point))))))
+      (let (buffer-read-only
+           (count 0)
+           (regexp (dired-marker-regexp)))
+       (while (and (not (eobp))
+                   (re-search-forward regexp nil t))
+         (setq count (1+ count))
+         (delete-region (progn (beginning-of-line) (point))
+                        (progn (forward-line 1) (point))))
        (or (equal "" fmt)
            (message (or fmt "Killed %d line%s.") count (dired-plural-s count)))
        count))))
@@ -659,6 +692,8 @@ and use this command with a prefix argument (the value does not matter)."
     ;; For .z, try gunzip.  It might be an old gzip file,
     ;; or it might be from compact? pack? (which?) but gunzip handles both.
     ("\\.z\\'" "" "gunzip")
+    ("\\.dz\\'" "" "dictunzip")
+    ("\\.tbz\\'" ".tar" "bunzip2")
     ("\\.bz2\\'" "" "bunzip2")
     ;; This item controls naming for compression.
     ("\\.tar\\'" ".tgz" nil))
@@ -730,7 +765,10 @@ Otherwise, the rule is a compression rule, and compression is done with gzip.")
   ;; The files used are determined by ARG (as in dired-get-marked-files).
   (or (eq dired-no-confirm t)
       (memq op-symbol dired-no-confirm)
-      (let ((files (dired-get-marked-files t arg))
+      ;; Pass t for DISTINGUISH-ONE-MARKED so that a single file which
+      ;; is marked pops up a window.  That will help the user see
+      ;; it isn't the current line file.
+      (let ((files (dired-get-marked-files t arg nil t))
            (string (if (eq op-symbol 'compress) "Compress or uncompress"
                      (capitalize (symbol-name op-symbol)))))
        (dired-mark-pop-up nil op-symbol files (function y-or-n-p)
@@ -776,6 +814,7 @@ Otherwise, the rule is a compression rule, and compression is done with gzip.")
     ;; None of these keys quit - use C-g for that.
     ))
 
+;;;###autoload
 (defun dired-query (qs-var qs-prompt &rest qs-args)
   ;; Query user and return nil or t.
   ;; Store answer in symbol VAR (which must initially be bound to nil).
@@ -805,6 +844,9 @@ Otherwise, the rule is a compression rule, and compression is done with gzip.")
               (sit-for 1)
               (apply 'message qprompt qs-args)
               (setq char (set qs-var (read-char))))
+            ;; Display the question with the answer.
+            (message (concat (apply 'format qprompt qs-args)
+                             (char-to-string char)))
             (memq (cdr elt) '(t y yes)))))))
 \f
 ;;;###autoload
@@ -862,13 +904,27 @@ Otherwise, the rule is a compression rule, and compression is done with gzip.")
 (defun dired-do-redisplay (&optional arg test-for-subdir)
   "Redisplay all marked (or next ARG) files.
 If on a subdir line, redisplay that subdirectory.  In that case,
-a prefix arg lets you edit the `ls' switches used for the new listing."
+a prefix arg lets you edit the `ls' switches used for the new listing.
+
+Dired remembers switches specified with a prefix arg, so that reverting
+the buffer will not reset them.  However, using `dired-undo' to re-insert
+or delete subdirectories can bypass this machinery.  Hence, you sometimes
+may have to reset some subdirectory switches after a `dired-undo'.
+You can reset all subdirectory switches to the default using
+\\<dired-mode-map>\\[dired-reset-subdir-switches].
+See Info node `(emacs-xtra)Subdir switches' for more details."
   ;; Moves point if the next ARG files are redisplayed.
   (interactive "P\np")
   (if (and test-for-subdir (dired-get-subdir))
-      (dired-insert-subdir
-       (dired-get-subdir)
-       (if arg (read-string "Switches for listing: " dired-actual-switches)))
+      (let* ((dir (dired-get-subdir))
+            (switches (cdr (assoc-string dir dired-switches-alist))))
+       (dired-insert-subdir
+        dir
+        (when arg
+          (read-string "Switches for listing: "
+                       (or switches
+                           dired-subdir-switches
+                           dired-actual-switches)))))
     (message "Redisplaying...")
     ;; message much faster than making dired-map-over-marks show progress
     (dired-uncache
@@ -879,6 +935,12 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
                          arg)
     (dired-move-to-filename)
     (message "Redisplaying...done")))
+
+(defun dired-reset-subdir-switches ()
+  "Set `dired-switches-alist' to nil and revert dired buffer."
+  (interactive)
+  (setq dired-switches-alist nil)
+  (revert-buffer))
 \f
 (defun dired-update-file-line (file)
   ;; Delete the current line, and insert an entry for FILE.
@@ -1044,19 +1106,6 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
 \f
 ;;; Copy, move/rename, making hard and symbolic links
 
-(defcustom dired-recursive-copies nil
-  "*Decide whether recursive copies are allowed.
-nil means no recursive copies.
-`always' means copy recursively without asking.
-`top' means ask for each directory at top level.
-Anything else means ask for each directory."
-  :type '(choice :tag "Copy directories"
-                (const :tag "No recursive copies" nil)
-                (const :tag "Ask for each directory" t)
-                (const :tag "Ask for each top directory only" top)
-                (const :tag "Copy directories without asking" always))
-  :group 'dired)
-
 (defcustom dired-backup-overwrite nil
   "*Non-nil if Dired should ask about making backups before overwriting files.
 Special value `always' suppresses confirmation."
@@ -1094,23 +1143,29 @@ Special value `always' suppresses confirmation."
 
 (defun dired-copy-file-recursive (from to ok-flag &optional
                                       preserve-time top recursive)
-  (if (and recursive
-          (eq t (car (file-attributes from))) ; A directory, no symbolic link.
-          (or (eq recursive 'always)
-              (yes-or-no-p (format "Recursive copies of %s " from))))
-      (let ((files (directory-files from nil dired-re-no-dot)))
-       (if (eq recursive 'top) (setq recursive 'always)) ; Don't ask any more.
-       (if (file-exists-p to)
-           (or top (dired-handle-overwrite to))
-         (make-directory to))
-       (while files
-         (dired-copy-file-recursive
-          (expand-file-name (car files) from)
-          (expand-file-name (car files) to)
-          ok-flag preserve-time nil recursive)
-         (setq files (cdr files))))
-    (or top (dired-handle-overwrite to)) ; Just a file.
-    (copy-file from to ok-flag dired-copy-preserve-time)))
+  (let ((attrs (file-attributes from)))
+    (if (and recursive
+            (eq t (car attrs))
+            (or (eq recursive 'always)
+                (yes-or-no-p (format "Recursive copies of %s " from))))
+       ;; This is a directory.
+       (let ((files (directory-files from nil dired-re-no-dot)))
+         (if (eq recursive 'top) (setq recursive 'always)) ; Don't ask any more.
+         (if (file-exists-p to)
+             (or top (dired-handle-overwrite to))
+           (make-directory to))
+         (while files
+           (dired-copy-file-recursive
+            (expand-file-name (car files) from)
+            (expand-file-name (car files) to)
+            ok-flag preserve-time nil recursive)
+           (setq files (cdr files))))
+      ;; Not a directory.
+      (or top (dired-handle-overwrite to))
+      (if (stringp (car attrs))
+         ;; It is a symlink
+         (make-symbolic-link (car attrs) to ok-flag)
+       (copy-file from to ok-flag dired-copy-preserve-time)))))
 
 ;;;###autoload
 (defun dired-rename-file (file newname ok-if-already-exists)
@@ -1178,9 +1233,10 @@ Special value `always' suppresses confirmation."
          (dired-advertise)))))
 
 (defun dired-rename-subdir-2 (elt dir to)
-  ;; Update the headerline and dired-subdir-alist element of directory
-  ;; described by alist-element ELT to reflect the moving of DIR to TO.
-  ;; Thus, ELT describes either DIR itself or a subdir of DIR.
+  ;; Update the headerline and dired-subdir-alist element, as well as
+  ;; dired-switches-alist element, of directory described by
+  ;; alist-element ELT to reflect the moving of DIR to TO.  Thus, ELT
+  ;; describes either DIR itself or a subdir of DIR.
   (save-excursion
     (let ((regexp (regexp-quote (directory-file-name dir)))
          (newtext (directory-file-name to))
@@ -1194,10 +1250,12 @@ Special value `always' suppresses confirmation."
        (if (re-search-forward regexp (match-end 1) t)
            (replace-match newtext t t)
          (error "Expected to find `%s' in headerline of %s" dir (car elt))))
-      ;; Update buffer-local dired-subdir-alist
-      (setcar elt
-             (dired-normalize-subdir
-              (dired-replace-in-string regexp newtext (car elt)))))))
+      ;; Update buffer-local dired-subdir-alist and dired-switches-alist
+      (let ((cons (assoc-string (car elt) dired-switches-alist))
+           (cur-dir (dired-normalize-subdir
+                     (dired-replace-in-string regexp newtext (car elt)))))
+       (setcar elt cur-dir)
+       (when cons (setcar cons cur-dir))))))
 \f
 ;; The basic function for half a dozen variations on cp/mv/ln/ln -s.
 (defun dired-create-files (file-creator operation fn-list name-constructor
@@ -1459,7 +1517,7 @@ suggested for the target directory depends on the value of
   (interactive "P")
   (let ((dired-recursive-copies dired-recursive-copies))
     (dired-do-create-files 'copy (function dired-copy-file)
-                          (if dired-copy-preserve-time "Copy [-p]" "Copy")
+                          "Copy"
                           arg dired-keep-marker-copy
                           nil dired-copy-how-to-fn)))
 
@@ -1689,11 +1747,20 @@ If it is already present, just move to it (type \\[dired-do-redisplay] to refres
 With a prefix arg, you may edit the ls switches used for this listing.
   You can add `R' to the switches to expand the whole tree starting at
   this subdirectory.
-This function takes some pains to conform to `ls -lR' output."
+This function takes some pains to conform to `ls -lR' output.
+
+Dired remembers switches specified with a prefix arg, so that reverting
+the buffer will not reset them.  However, using `dired-undo' to re-insert
+or delete subdirectories can bypass this machinery.  Hence, you sometimes
+may have to reset some subdirectory switches after a `dired-undo'.
+You can reset all subdirectory switches to the default using
+\\<dired-mode-map>\\[dired-reset-subdir-switches].
+See Info node `(emacs-xtra)Subdir switches' for more details."
   (interactive
    (list (dired-get-filename)
         (if current-prefix-arg
-            (read-string "Switches for listing: " dired-actual-switches))))
+            (read-string "Switches for listing: "
+                         (or dired-subdir-switches dired-actual-switches)))))
   (let ((opoint (point)))
     ;; We don't need a marker for opoint as the subdir is always
     ;; inserted *after* opoint.
@@ -1720,14 +1787,19 @@ This function takes some pains to conform to `ls -lR' output."
   (interactive
    (list (dired-get-filename)
         (if current-prefix-arg
-            (read-string "Switches for listing: " dired-actual-switches))))
+            (read-string "Switches for listing: "
+                         (or dired-subdir-switches dired-actual-switches)))))
   (setq dirname (file-name-as-directory (expand-file-name dirname)))
-  (dired-insert-subdir-validate dirname switches)
   (or no-error-if-not-dir-p
       (file-directory-p dirname)
       (error  "Attempt to insert a non-directory: %s" dirname))
   (let ((elt (assoc dirname dired-subdir-alist))
-        switches-have-R mark-alist case-fold-search buffer-read-only)
+       (cons (assoc-string dirname dired-switches-alist))
+       (modflag (buffer-modified-p))
+       (old-switches switches)
+       switches-have-R mark-alist case-fold-search buffer-read-only)
+    (and (not switches) cons (setq switches (cdr cons)))
+    (dired-insert-subdir-validate dirname switches)
     ;; case-fold-search is nil now, so we can test for capital `R':
     (if (setq switches-have-R (and switches (string-match "R" switches)))
        ;; avoid duplicated subdirs
@@ -1738,9 +1810,23 @@ This function takes some pains to conform to `ls -lR' output."
       (dired-insert-subdir-newpos dirname)) ; else compute new position
     (dired-insert-subdir-doupdate
      dirname elt (dired-insert-subdir-doinsert dirname switches))
-    (if switches-have-R (dired-build-subdir-alist switches))
+    (when old-switches
+      (if cons
+         (setcdr cons switches)
+       (push (cons dirname switches) dired-switches-alist)))
+    (when switches-have-R
+      (dired-build-subdir-alist switches)
+      (setq switches (dired-replace-in-string "R" "" switches))
+      (dolist (cur-ass dired-subdir-alist)
+       (let ((cur-dir (car cur-ass)))
+         (and (dired-in-this-tree cur-dir dirname)
+              (let ((cur-cons (assoc-string cur-dir dired-switches-alist)))
+                (if cur-cons
+                    (setcdr cur-cons switches)
+                  (push (cons cur-dir switches) dired-switches-alist)))))))
     (dired-initial-position dirname)
-    (save-excursion (dired-mark-remembered mark-alist))))
+    (save-excursion (dired-mark-remembered mark-alist))
+    (restore-buffer-modified-p modflag)))
 
 ;; This is a separate function for dired-vms.
 (defun dired-insert-subdir-validate (dirname &optional switches)
@@ -1748,17 +1834,18 @@ This function takes some pains to conform to `ls -lR' output."
   ;; Signal an error if invalid (e.g. user typed `i' on `..').
   (or (dired-in-this-tree dirname (expand-file-name default-directory))
       (error  "%s: not in this directory tree" dirname))
-  (if switches
+  (let ((real-switches (or switches dired-subdir-switches)))
+    (when real-switches
       (let (case-fold-search)
        (mapcar
         (function
          (lambda (x)
-           (or (eq (null (string-match x switches))
+           (or (eq (null (string-match x real-switches))
                    (null (string-match x dired-actual-switches)))
-               (error "Can't have dirs with and without -%s switches together"
-                      x))))
+               (error
+                "Can't have dirs with and without -%s switches together" x))))
         ;; all switches that make a difference to dired-get-filename:
-        '("F" "b")))))
+        '("F" "b"))))))
 
 (defun dired-alist-add (dir new-marker)
   ;; Add new DIR at NEW-MARKER.  Sort alist.
@@ -1773,19 +1860,23 @@ This function takes some pains to conform to `ls -lR' output."
                          (> (dired-get-subdir-min elt1)
                             (dired-get-subdir-min elt2)))))))
 
-(defun dired-kill-tree (dirname &optional remember-marks)
+(defun dired-kill-tree (dirname &optional remember-marks kill-root)
   "Kill all proper subdirs of DIRNAME, excluding DIRNAME itself.
-With optional arg REMEMBER-MARKS, return an alist of marked files."
-  (interactive "DKill tree below directory: ")
-  (setq dirname (expand-file-name dirname))
+Interactively, you can kill DIRNAME as well by using a prefix argument.
+In interactive use, the command prompts for DIRNAME.
+
+When called from Lisp, if REMEMBER-MARKS is non-nil, return an alist
+of marked files.  If KILL-ROOT is non-nil, kill DIRNAME as well."
+  (interactive "DKill tree below directory: \ni\nP")
+  (setq dirname (file-name-as-directory (expand-file-name dirname)))
   (let ((s-alist dired-subdir-alist) dir m-alist)
     (while s-alist
       (setq dir (car (car s-alist))
            s-alist (cdr s-alist))
-      (if (and (not (string-equal dir dirname))
-              (dired-in-this-tree dir dirname)
-              (dired-goto-subdir dir))
-         (setq m-alist (nconc (dired-kill-subdir remember-marks) m-alist))))
+      (and (or kill-root (not (string-equal dir dirname)))
+          (dired-in-this-tree dir dirname)
+          (dired-goto-subdir dir)
+          (setq m-alist (nconc (dired-kill-subdir remember-marks) m-alist))))
     m-alist))
 
 (defun dired-insert-subdir-newpos (new-dir)
@@ -1826,16 +1917,15 @@ With optional arg REMEMBER-MARKS, return an alist of marked files."
   ;; Return the boundary of the inserted text (as list of BEG and END).
   (save-excursion
     (let ((begin (point)))
-      (message "Reading directory %s..." dirname)
       (let ((dired-actual-switches
             (or switches
+                dired-subdir-switches
                 (dired-replace-in-string "R" "" dired-actual-switches))))
        (if (equal dirname (car (car (last dired-subdir-alist))))
            ;; If doing the top level directory of the buffer,
            ;; redo it as specified in dired-directory.
            (dired-readin-insert)
          (dired-insert-directory dirname dired-actual-switches nil nil t)))
-      (message "Reading directory %s...done" dirname)
       (list begin (point)))))
 
 (defun dired-insert-subdir-doupdate (dirname elt beg-end)
@@ -1978,10 +2068,12 @@ marks the files listed in the subdirectory that point is in."
 Lower levels are unaffected."
   ;; With optional REMEMBER-MARKS, return a mark-alist.
   (interactive)
-  (let ((beg (dired-subdir-min))
-       (end (dired-subdir-max))
-       buffer-read-only cur-dir)
-    (setq cur-dir (dired-current-directory))
+  (let* ((beg (dired-subdir-min))
+        (end (dired-subdir-max))
+        (modflag (buffer-modified-p))
+        (cur-dir (dired-current-directory))
+        (cons (assoc-string cur-dir dired-switches-alist))
+        buffer-read-only)
     (if (equal cur-dir default-directory)
        (error "Attempt to kill top level directory"))
     (prog1
@@ -1989,7 +2081,10 @@ Lower levels are unaffected."
       (delete-region beg end)
       (if (eobp)                       ; don't leave final blank line
          (delete-char -1))
-      (dired-unsubdir cur-dir))))
+      (dired-unsubdir cur-dir)
+      (when cons
+       (setq dired-switches-alist (delete cons dired-switches-alist)))
+      (restore-buffer-modified-p modflag))))
 
 (defun dired-unsubdir (dir)
   ;; Remove DIR from the alist
@@ -2048,19 +2143,21 @@ Optional prefix arg is a repeat factor.
 Use \\[dired-hide-all] to (un)hide all directories."
   (interactive "p")
   (dired-hide-check)
-  (while (>=  (setq arg (1- arg)) 0)
-    (let* ((cur-dir (dired-current-directory))
-          (hidden-p (dired-subdir-hidden-p cur-dir))
-          (elt (assoc cur-dir dired-subdir-alist))
-          (end-pos (1- (dired-get-subdir-max elt)))
-          buffer-read-only)
-      ;; keep header line visible, hide rest
-      (goto-char (dired-get-subdir-min elt))
-      (skip-chars-forward "^\n\r")
-      (if hidden-p
-         (subst-char-in-region (point) end-pos ?\r ?\n)
-       (subst-char-in-region (point) end-pos ?\n ?\r)))
-    (dired-next-subdir 1 t)))
+  (let ((modflag (buffer-modified-p)))
+    (while (>=  (setq arg (1- arg)) 0)
+      (let* ((cur-dir (dired-current-directory))
+            (hidden-p (dired-subdir-hidden-p cur-dir))
+            (elt (assoc cur-dir dired-subdir-alist))
+            (end-pos (1- (dired-get-subdir-max elt)))
+            buffer-read-only)
+       ;; keep header line visible, hide rest
+       (goto-char (dired-get-subdir-min elt))
+       (skip-chars-forward "^\n\r")
+       (if hidden-p
+           (subst-char-in-region (point) end-pos ?\r ?\n)
+         (subst-char-in-region (point) end-pos ?\n ?\r)))
+      (dired-next-subdir 1 t))
+    (restore-buffer-modified-p modflag)))
 
 ;;;###autoload
 (defun dired-hide-all (arg)
@@ -2069,7 +2166,8 @@ If there is already something hidden, make everything visible again.
 Use \\[dired-hide-subdir] to (un)hide a particular subdirectory."
   (interactive "P")
   (dired-hide-check)
-  (let (buffer-read-only)
+  (let ((modflag (buffer-modified-p))
+       buffer-read-only)
     (if (save-excursion
          (goto-char (point-min))
          (search-forward "\r" nil t))
@@ -2078,7 +2176,7 @@ Use \\[dired-hide-subdir] to (un)hide a particular subdirectory."
       ;; hide
       (let ((pos (point-max))          ; pos of end of last directory
            (alist dired-subdir-alist))
-       (while alist                    ; while there are dirs before pos
+       (while alist                    ; while there are dirs before pos
          (subst-char-in-region (dired-get-subdir-min (car alist)) ; pos of prev dir
                                (save-excursion
                                  (goto-char pos) ; current dir
@@ -2087,7 +2185,8 @@ Use \\[dired-hide-subdir] to (un)hide a particular subdirectory."
                                  (point))
                                ?\n ?\r)
          (setq pos (dired-get-subdir-min (car alist))) ; prev dir gets current dir
-         (setq alist (cdr alist)))))))
+         (setq alist (cdr alist)))))
+    (restore-buffer-modified-p modflag)))
 
 ;;;###end dired-ins.el
 
@@ -2109,12 +2208,15 @@ Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
 If you exit (\\[keyboard-quit], RET or q), you can resume the query replace
 with the command \\[tags-loop-continue]."
   (interactive
-   "sQuery replace in marked files (regexp): \nsQuery replace %s by: \nP")
+   (let ((common
+         (query-replace-read-args
+          "Query replace regexp in marked files" t t)))
+     (list (nth 0 common) (nth 1 common) (nth 2 common))))
   (dolist (file (dired-get-marked-files nil nil 'dired-nondirectory-p))
     (let ((buffer (get-file-buffer file)))
       (if (and buffer (with-current-buffer buffer
                        buffer-read-only))
-         (error "File `%s' is visited read-only"))))
+         (error "File `%s' is visited read-only" file))))
   (tags-query-replace from to delimited
                      '(dired-get-marked-files nil nil 'dired-nondirectory-p)))