]> code.delx.au - gnu-emacs/blobdiff - lisp/dired.el
*** empty log message ***
[gnu-emacs] / lisp / dired.el
index 864d1b6f876d5299e8c282bf7c29f6f6978efd45..895c95fc78e5f4076ee530bed4999831abc0fea8 100644 (file)
@@ -152,6 +152,21 @@ The target is used in the prompt for file copy, rename etc."
   :type 'boolean
   :group 'dired)
 
+(defcustom dired-free-space-program "df"
+  "*Program to get the amount of free space on a file system.
+We assume the output has the format of `df'.
+The value of this variable must be just a command name or file name;
+if you want to specify options, use `dired-free-space-args'.
+
+A value of nil disables this feature."
+  :type '(choice (string :tag "Program") (const :tag "None" nil))
+  :group 'dired)
+
+(defcustom dired-free-space-args "-Pk"
+  "*Options to use when running `dired-free-space-program'."
+  :type 'string
+  :group 'dired)
+
 ;;; Hook variables
 
 (defvar dired-load-hook nil
@@ -217,8 +232,10 @@ directory name and the cdr is the actual files to list.")
 ;; "Regexp matching a marked line.
 ;; Important: the match ends just after the marker."
 (defvar dired-re-maybe-mark "^. ")
-(defvar dired-re-dir (concat dired-re-maybe-mark dired-re-inode-size "d"))
-(defvar dired-re-sym (concat dired-re-maybe-mark dired-re-inode-size "l"))
+;; The [^:] part after "d" and "l" is to avoid confusion with the
+;; DOS/Windows-style drive letters in directory names, like in "d:/foo".
+(defvar dired-re-dir (concat dired-re-maybe-mark dired-re-inode-size "d[^:]"))
+(defvar dired-re-sym (concat dired-re-maybe-mark dired-re-inode-size "l[^:]"))
 (defvar dired-re-exe;; match ls permission string of an executable file
   (mapconcat (function
              (lambda (x)
@@ -597,7 +614,8 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
        ;; We need this to make the root dir have a header line as all
        ;; other subdirs have:
        (goto-char (point-min))
-       (dired-insert-headerline default-directory)
+        (if (not (looking-at "^  /.*:$"))
+            (dired-insert-headerline default-directory))
        ;; can't run dired-after-readin-hook here, it may depend on the subdir
        ;; alist to be OK.
        )
@@ -655,7 +673,25 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
         (cdr dir-or-list))
       ;; Expand the file name here because it may have been abbreviated
       ;; in dired-noselect.
-      (insert-directory (expand-file-name dir-or-list) switches wildcard full-p))
+      (insert-directory (expand-file-name dir-or-list) switches wildcard full-p)
+      (when (and full-p dired-free-space-program)
+       (save-excursion
+         (goto-char (point-min))
+         (when (re-search-forward "total [0-9]+$" nil t)
+           (insert "  free ")
+           (let ((beg (point)))
+             (call-process dired-free-space-program nil t nil
+                           dired-free-space-args
+                           (expand-file-name dir-or-list))
+             (goto-char beg)
+             (forward-line 1)
+             (skip-chars-forward "^ \t")
+             (forward-word 2)
+             (skip-chars-forward " \t")
+             (delete-region beg (point))
+             (forward-word 1)
+             (delete-region (point)
+                            (progn (forward-line 1) (point))))))))
     ;; Quote certain characters, unless ls quoted them for us.
     (if (not (string-match "b" dired-actual-switches))
        (save-excursion
@@ -988,7 +1024,7 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
       '("Flag..." . dired-flag-files-regexp))
     (define-key map [menu-bar regexp mark]
       '("Mark..." . dired-mark-files-regexp))
-    (define-key map [menu-bar regexp mark]
+    (define-key map [menu-bar regexp mark-cont]
       '("Mark Containing..." . dired-mark-files-containing-regexp))
 
     (define-key map [menu-bar mark]
@@ -1314,12 +1350,12 @@ If it does not match, nil is returned instead of the new string.
 Optional arg LITERAL means to take NEWTEXT literally.
 Optional arg GLOBAL means to replace all matches."
   (if global
-      (let ((start 0))
+      (let ((start 0) ret)
        (while (string-match regexp string start)
          (let ((from-end (- (length string) (match-end 0))))
-           (setq string (replace-match newtext t literal string))
+           (setq ret (setq string (replace-match newtext t literal string)))
            (setq start (- (length string) from-end))))
-         string)
+         ret)
     (if (not (string-match regexp string 0))
        nil
       (replace-match newtext t literal string))))
@@ -1355,7 +1391,9 @@ DIR must be a directory name, not a file name."
   (let* ((l "\\([A-Za-z]\\|[^\0-\177]\\)")
         ;; In some locales, month abbreviations are as short as 2 letters,
         ;; and they can be padded on the right with spaces.
-        (month (concat l l "+ *"))
+        ;; weiand: changed: month ends potentially with . or , or .,
+;;old   (month (concat l l "+ *"))
+        (month (concat l l "+[.]?,? *"))
         ;; Recognize any non-ASCII character.  
         ;; The purpose is to match a Kanji character.
         (k "[^\0-\177]")
@@ -1363,15 +1401,22 @@ DIR must be a directory name, not a file name."
         (s " ")
         (yyyy "[0-9][0-9][0-9][0-9]")
         (mm "[ 0-1][0-9]")
-        (dd "[ 0-3][0-9]")
+;;old   (dd "[ 0-3][0-9]")
+        (dd "[ 0-3][0-9][.]?")
         (HH:MM "[ 0-2][0-9]:[0-5][0-9]")
         (western (concat "\\(" month s dd "\\|" dd s month "\\)"
-                         s "\\(" HH:MM "\\|" s yyyy "\\|" yyyy s "\\)"))
+         ;; weiand: changed: year potentially unaligned
+;;old                    s "\\(" HH:MM "\\|" s yyyy "\\|" yyyy s "\\)"))
+                         s "\\(" HH:MM "\\|" s "?" yyyy "\\|" yyyy s
+"\\)"))
         (japanese (concat mm k s dd k s "\\(" s HH:MM "\\|" yyyy k "\\)")))
-        ;; Require the previous column to end in a digit.
+        ;; The "[0-9]" below requires the previous column to end in a digit.
         ;; This avoids recognizing `1 may 1997' as a date in the line:
         ;; -r--r--r--   1 may      1997        1168 Oct 19 16:49 README
-    (concat "[0-9]" s "\\(" western "\\|" japanese "\\)" s))
+        ;; The ".*" below finds the last match if there are multiple matches.
+        ;; This avoids recognizing `jservice  10  1024' as a date in the line:
+        ;; drwxr-xr-x  3 jservice  10  1024 Jul  2  1997 esg-host
+    (concat ".*[0-9]" s "\\(" western "\\|" japanese "\\)" s))
   "Regular expression to match up to the file name in a directory listing.
 The default value is designed to recognize dates and times
 regardless of the language.")
@@ -1774,6 +1819,50 @@ Optional argument means return a file name relative to `default-directory'."
 \f
 ;; Deleting files
 
+(defcustom dired-recursive-deletes nil ; Default only delete empty directories.
+  "*Decide whether recursive deletes are allowed.
+Nil means no recursive deletes.
+`always' means delete recursively without asking.  This is DANGEROUS!
+`top' means ask for each directory at top level, but delete its subdirectories
+without asking.
+Anything else means ask for each directory."
+  :type '(choice :tag "Delete not empty directory"
+                (const :tag "No. Only empty directories" nil)
+                (const :tag "Ask for each directory" t)
+                (const :tag "Ask for each top directory only" top))
+  :group 'dired)
+
+;; Match anything but `.' and `..'. 
+(defvar dired-re-no-dot "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*")
+
+;; 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) "\
+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.
+`always', delete recursively without asking.
+`top', ask for each directory at top level.
+Anything else, ask for each sub-directory."
+  (let (files)
+     ;; This test is equivalent to
+     ;; (and (file-directory-p fn) (not (file-symlink-p fn)))
+     ;; but more efficient
+    (if (not (eq t (car (file-attributes file))))
+       (delete-file file)
+      (when (and recursive
+              (setq files
+                    (directory-files file t dired-re-no-dot)) ; Not empty.
+              (or (eq recursive 'always)
+                  (yes-or-no-p (format "Recursive delete of %s "
+                                       (dired-make-relative file)))))
+       (if (eq recursive 'top) (setq recursive 'always)) ; Don't ask again.
+       (while files            ; Recursively delete (possibly asking).
+           (dired-delete-file (car files) recursive)
+           (setq files (cdr files))))
+      (delete-directory file))))
+
 (defun dired-do-flagged-delete (&optional nomessage)
   "In dired, delete the files flagged for deletion.
 If NOMESSAGE is non-nil, we don't display any message
@@ -1829,12 +1918,7 @@ if there are no flagged files."
              (let (buffer-read-only)
                (condition-case err
                    (let ((fn (car (car l))))
-                     ;; This test is equivalent to
-                     ;; (and (file-directory-p fn) (not (file-symlink-p fn)))
-                     ;; but more efficient
-                     (if (eq t (car (file-attributes fn)))
-                         (delete-directory fn)
-                       (delete-file fn))
+                     (dired-delete-file fn dired-recursive-deletes)
                      ;; if we get here, removing worked
                      (setq succ (1+ succ))
                      (message "%s of %s deletions" succ count)
@@ -2164,17 +2248,22 @@ A prefix argument means to unmark them instead.
      (and (not (looking-at dired-re-dot))
          (not (eolp))                  ; empty line
          (let ((fn (dired-get-filename nil t)))
-           (and fn (save-excursion
-                     ;; For now we do it inside emacs
-                     ;; Grep might be better if there are a lot of files
-                     (message "Checking %s" fn)
-                     (let* ((prebuf (get-file-buffer fn)))
-                       (find-file fn)
+           (when (and fn (file-readable-p fn)
+                      (not (file-directory-p fn)))
+             (let ((prebuf (get-file-buffer fn)))
+               (message "Checking %s" fn)
+               ;; For now we do it inside emacs
+               ;; Grep might be better if there are a lot of files
+               (if prebuf
+                   (with-current-buffer prebuf
+                     (save-excursion
                        (goto-char (point-min))
-                       (prog1 
-                           (re-search-forward regexp nil t)
-                         (if (not prebuf) (kill-buffer nil))))
-                     ))))
+                       (re-search-forward regexp nil t)))
+                 (with-temp-buffer
+                   (insert-file-contents fn)
+                   (goto-char (point-min))
+                   (re-search-forward regexp nil t))))
+                     )))
      "matching file")))
 
 (defun dired-flag-files-regexp (regexp)
@@ -2237,7 +2326,7 @@ A prefix argument says to unflag those files instead."
      "auto save file")))
 
 (defvar dired-garbage-files-regexp
-  "\\.log$\\|\\.toc$\\|.dvi$|\\.bak$\\|\\.orig$\\|\\.rej$" 
+  "\\.log$\\|\\.toc$\\|\\.dvi$\\|\\.bak$\\|\\.orig$\\|\\.rej$" 
   "*Regular expression to match \"garbage\" files for `dired-flag-garbage-files'.")
 
 (defun dired-flag-garbage-files ()
@@ -2592,17 +2681,17 @@ With a zero prefix arg, renaming by regexp affects the complete
 
 (autoload 'dired-do-copy-regexp "dired-aux"
   "Copy all marked files containing REGEXP to NEWNAME.
-See function `dired-rename-regexp' for more info."
+See function `dired-do-rename-regexp' for more info."
   t)
 
 (autoload 'dired-do-hardlink-regexp "dired-aux"
   "Hardlink all marked files containing REGEXP to NEWNAME.
-See function `dired-rename-regexp' for more info."
+See function `dired-do-rename-regexp' for more info."
   t)
 
 (autoload 'dired-do-symlink-regexp "dired-aux"
   "Symlink all marked files containing REGEXP to NEWNAME.
-See function `dired-rename-regexp' for more info."
+See function `dired-do-rename-regexp' for more info."
   t)
 
 (autoload 'dired-upcase "dired-aux"