(compilation-error-regexp-alist): Fix previous change.
[bpt/emacs.git] / lisp / dired.el
index ee1d5ab..705c1b8 100644 (file)
@@ -1,9 +1,9 @@
 ;;; dired.el --- directory-browsing commands
 
-;; Copyright (C) 1985, 1986, 1992, 1993 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1992, 1993, 1994 Free Software Foundation, Inc.
 
-;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>.
-;; Version: 6
+;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>
+;; Maintainer: FSF
 
 ;; This file is part of GNU Emacs.
 
@@ -38,7 +38,8 @@
 (defvar dired-listing-switches "-al"
   "*Switches passed to `ls' for dired.  MUST contain the `l' option.
 May contain all other options that don't contradict `-l';
-may contain even `F', `b', `i' and `s'.")
+may contain even `F', `b', `i' and `s'.  See also the variable
+`dired-ls-F-marks-symlinks' concerning the `F' switch.")
 
 ; Don't use absolute paths as /bin should be in any PATH and people
 ; may prefer /usr/local/gnu/bin or whatever.  However, chown is
@@ -46,7 +47,7 @@ may contain even `F', `b', `i' and `s'.")
 
 ;;;###autoload
 (defvar dired-chown-program
-  (if (memq system-type '(hpux dgux usg-unix-v silicon-graphics-unix))
+  (if (memq system-type '(hpux dgux usg-unix-v irix linux))
       "chown" "/etc/chown")
   "Name of chown command (usually `chown' or `/etc/chown').")
 
@@ -184,6 +185,7 @@ directory name and the cdr is the actual files to list.")
               "-[-r][-w].[-r][-w][xs][-r][-w]."
               "-[-r][-w].[-r][-w].[-r][-w][xst]")
             "\\|"))
+(defvar dired-re-perms "-[-r][-w].[-r][-w].[-r][-w].")
 (defvar dired-re-dot "^.* \\.\\.?$")
 
 (defvar dired-subdir-alist nil
@@ -192,7 +194,7 @@ Each subdirectory has an element: (DIRNAME . STARTMARKER).
 The order of elements is the reverse of the order in the buffer.
 In simple cases, this list contains one element.")
 
-(defvar dired-subdir-regexp "^. \\([^ \n\r]+\\)\\(:\\)[\n\r]"
+(defvar dired-subdir-regexp "^. \\([^\n\r]+\\)\\(:\\)[\n\r]"
   "Regexp matching a maybe hidden subdirectory line in `ls -lR' output.
 Subexpression 1 is the subdirectory proper, no trailing colon.
 The match starts at the beginning of the line and ends after the end
@@ -363,7 +365,8 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
     (if (consp dir-or-list)
        (setq dirname (car dir-or-list))
       (setq dirname dir-or-list))
-    (setq dirname (expand-file-name (directory-file-name dirname)))
+    (setq dirname (abbreviate-file-name
+                  (expand-file-name (directory-file-name dirname))))
     (if (file-directory-p dirname)
        (setq dirname (file-name-as-directory dirname)))
     (if (consp dir-or-list)
@@ -396,11 +399,21 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
     (set-buffer buffer)
     (if (not new-buffer-p)             ; existing buffer ...
        (if switches                    ; ... but new switches
-           (dired-sort-other switches))        ; this calls dired-revert
+           (dired-sort-other switches) ; this calls dired-revert
+         ;; If directory has changed on disk, offer to revert.
+         (if (let ((attributes (file-attributes dirname))
+                   (modtime (visited-file-modtime)))
+               (or (eq modtime 0)
+                   (not (eq (car attributes) t))
+                   (and (= (car (nth 5 attributes)) (car modtime))
+                        (= (nth 1 (nth 5 attributes)) (cdr modtime)))))
+             nil
+           (message "Directory has changed on disk; type `g' to update Dired")))
       ;; Else a new buffer
-      (setq default-directory (if (file-directory-p dirname)
-                                 dirname
-                               (file-name-directory dirname)))
+      (setq default-directory
+           (if (file-directory-p dirname)
+               dirname
+             (file-name-directory dirname)))
       (or switches (setq switches dired-listing-switches))
       (dired-mode dirname switches)
       ;; default-directory and dired-actual-switches are set now
@@ -474,11 +487,14 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
        ;; alist to be OK.
        )
       (message "Reading directory %s...done" dirname)
-      (set-buffer-modified-p nil)
       ;; Must first make alist buffer local and set it to nil because
       ;; dired-build-subdir-alist will call dired-clear-alist first
       (set (make-local-variable 'dired-subdir-alist) nil)
-      (dired-build-subdir-alist))))
+      (dired-build-subdir-alist)
+      (let ((attributes (file-attributes dirname)))
+       (if (eq (car attributes) t)
+           (set-visited-file-modtime (nth 5 attributes))))
+      (set-buffer-modified-p nil))))
 
 ;; Subroutines of dired-readin
 
@@ -489,7 +505,9 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
     (if (consp dir-or-list)
        (setq dirname (car dir-or-list))
       (setq dirname dir-or-list))
-    (if (and (equal default-directory dirname)
+    ;; Expand before comparing in case one or both have been abbreviated.
+    (if (and (equal (expand-file-name default-directory)
+                   (expand-file-name dirname))
             (not (consp dir-or-list)))
        ;; If we are reading a whole single directory...
        (dired-insert-directory dir-or-list dired-actual-switches nil t)
@@ -507,15 +525,29 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
 (defun dired-insert-directory (dir-or-list switches &optional wildcard full-p)
   ;; Do the right thing whether dir-or-list is atomic or not.  If it is,
   ;; inset all files listed in the cdr (the car is the passed-in directory
-  ;; list.
-  (if (consp dir-or-list)
-      (progn
-       (mapcar
-        (function (lambda (x) (insert-directory x switches wildcard full-p)))
-        (cdr dir-or-list)))
-    (insert-directory dir-or-list switches wildcard full-p))
+  ;; list).
+  (let ((opoint (point)))
+    (if (consp dir-or-list)
+       (progn
+         (mapcar
+          (function (lambda (x) (insert-directory x switches wildcard full-p)))
+          (cdr dir-or-list)))
+      (insert-directory dir-or-list switches wildcard full-p))
+    (dired-insert-set-properties opoint (point)))
   (setq dired-directory dir-or-list))
 
+(defun dired-insert-set-properties (beg end)
+  (save-excursion
+    (goto-char beg)
+    (while (< (point) end)
+      (if (dired-move-to-filename)
+         (put-text-property (point)
+                            (save-excursion
+                              (dired-move-to-end-of-filename)
+                              (point))
+                            'mouse-face 'highlight))
+      (forward-line 1))))
+
 (defun dired-insert-headerline (dir);; also used by dired-insert-subdir
   ;; Insert DIR's headerline with no trailing slash, exactly like ls
   ;; would, and put cursor where dired-build-subdir-alist puts subdir
@@ -627,7 +659,7 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
 
 ;; Remove directory DIR from any directory cache.
 (defun dired-uncache (dir)
-  (let ((handler (find-file-name-handler dir)))
+  (let ((handler (find-file-name-handler dir 'dired-uncache)))
     (if handler
        (funcall handler 'dired-uncache dir))))
 \f
@@ -636,13 +668,12 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
 (defvar dired-mode-map nil "Local keymap for dired-mode buffers.")
 (if dired-mode-map
     nil
-  ;; Force `f' rather than `e' in the mode doc:
-  (defalias 'dired-advertised-find-file 'dired-find-file)
   ;; This looks ugly when substitute-command-keys uses C-d instead d:
   ;;  (define-key dired-mode-map "\C-d" 'dired-flag-file-deletion)
 
   (setq dired-mode-map (make-keymap))
   (suppress-keymap dired-mode-map)
+  (define-key dired-mode-map [mouse-2] 'dired-mouse-find-file-other-window)
   ;; Commands to mark or flag certain categories of files
   (define-key dired-mode-map "#" 'dired-flag-auto-save-files)
   (define-key dired-mode-map "*" 'dired-mark-executables)
@@ -678,8 +709,10 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
   (define-key dired-mode-map "\M-{" 'dired-prev-marked-file)
   (define-key dired-mode-map "\M-}" 'dired-next-marked-file)
   ;; Make all regexp commands share a `%' prefix:
-  (defalias 'dired-regexp-prefix (make-sparse-keymap))
-  (define-key dired-mode-map "%" 'dired-regexp-prefix)
+  ;; We used to get to the submap via a symbol dired-regexp-prefix,
+  ;; but that seems to serve little purpose, and copy-keymap
+  ;; does a better job without it.
+  (define-key dired-mode-map "%" nil)
   (define-key dired-mode-map "%u" 'dired-upcase)
   (define-key dired-mode-map "%l" 'dired-downcase)
   (define-key dired-mode-map "%d" 'dired-flag-files-regexp)
@@ -726,14 +759,6 @@ If DIRNAME is already in a dired buffer, that buffer is used without refresh."
   (define-key dired-mode-map "\C-_" 'dired-undo)
   (define-key dired-mode-map "\C-xu" 'dired-undo)
   )
-
-(or (member '(dired-sort-mode dired-sort-mode) minor-mode-alist)
-    ;; Test whether this has already been done in case dired is reloaded
-    ;; There may be several elements with dired-sort-mode as car.
-    (setq minor-mode-alist
-         (cons '(dired-sort-mode dired-sort-mode)
-               ;; dired-sort-mode is nil outside dired
-               minor-mode-alist)))
 \f
 ;; Make menu bar items.
 
@@ -936,7 +961,7 @@ Keybindings:
   (dired-advertise)                    ; default-directory is already set
   (setq major-mode 'dired-mode
        mode-name "Dired"
-       case-fold-search nil
+;;     case-fold-search nil
        buffer-read-only t
        selective-display t             ; for subdirectory hiding
        mode-line-buffer-identification '("Dired: %17b"))
@@ -951,7 +976,6 @@ Keybindings:
        dired-directory)
   (set (make-local-variable 'dired-actual-switches)
        (or switches dired-listing-switches))
-  (make-local-variable 'dired-sort-mode)
   (dired-sort-other dired-actual-switches t)
   (run-hooks 'dired-mode-hook))
 \f
@@ -1027,11 +1051,25 @@ Creates a buffer if necessary."
 up)
          (dired-goto-file dir)))))
 
+;; Force `f' rather than `e' in the mode doc:
+(defalias 'dired-advertised-find-file 'dired-find-file)
 (defun dired-find-file ()
   "In dired, visit the file or directory named on this line."
   (interactive)
   (find-file (file-name-sans-versions (dired-get-filename) t)))
 
+(defun dired-mouse-find-file-other-window (event)
+  "In dired, visit the file or directory name you click on."
+  (interactive "e")
+  (let (file)
+    (save-excursion
+      (set-buffer (window-buffer (posn-window (event-end event))))
+      (save-excursion
+       (goto-char (posn-point (event-end event)))
+       (setq file (dired-get-filename))))
+    (select-window (posn-window (event-end event)))
+    (find-file-other-window (file-name-sans-versions file t))))
+
 (defun dired-view-file ()
   "In dired, examine a file in view mode, returning to dired when done.
 When file is a directory, show it in this buffer if it is inserted;
@@ -1069,7 +1107,7 @@ Optional arg NO-ERROR-IF-NOT-FILEP means return nil if no filename on
       (if (setq p1 (dired-move-to-filename (not no-error-if-not-filep)))
          (setq p2 (dired-move-to-end-of-filename no-error-if-not-filep))))
     ;; nil if no file on this line, but no-error-if-not-filep is t:
-    (if (setq file (and p1 p2 (buffer-substring p1 p2)))
+    (if (setq file (and p1 p2 (format "%s" (buffer-substring p1 p2))))
        ;; Check if ls quoted the names, and unquote them.
        ;; Using read to unquote is much faster than substituting
        ;; \007 (4 chars) -> ^G  (1 char) etc. in a lisp loop.
@@ -1109,6 +1147,10 @@ Optional arg NO-ERROR-IF-NOT-FILEP means return nil if no filename on
   ;; DIR must be file-name-as-directory, as with all directory args in
   ;; Emacs Lisp code.
   (or dir (setq dir default-directory))
+  ;; This case comes into play if default-directory is set to
+  ;; use ~.
+  (if (and (> (length dir) 0) (= (aref dir 0) ?~))
+      (setq dir (expand-file-name dir)))
   (if (string-match (concat "^" (regexp-quote dir)) file)
       (substring file (match-end 0))
     (if no-error
@@ -1117,28 +1159,20 @@ Optional arg NO-ERROR-IF-NOT-FILEP means return nil if no filename on
 \f
 ;;; Functions for finding the file name in a dired buffer line.
 
+(defvar dired-move-to-filename-regexp
+  "\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|Jul\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\)[ ]+[0-9]+ [ 0-9][0-9][:0-9][0-9][ 0-9] "
+  "Regular expression to match a month abbreviation followed by a number.")
+
 ;; Move to first char of filename on this line.
 ;; Returns position (point) or nil if no filename on this line."
 (defun dired-move-to-filename (&optional raise-error eol)
   ;; This is the UNIX version.
   (or eol (setq eol (progn (end-of-line) (point))))
   (beginning-of-line)
-  (if (re-search-forward
-       "\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|Jul\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\)[ ]+[0-9]+"
-       eol t)
-      (progn
-       (skip-chars-forward " ")        ; there is one SPC after day of month
-       (skip-chars-forward "^ " eol)   ; move after time of day (or year)
-       (skip-chars-forward " " eol)    ; there is space before the file name
-       ;; Actually, if the year instead of clock time is displayed,
-       ;; there are (only for some ls programs?) two spaces instead
-       ;; of one before the name.
-       ;; If we could depend on ls inserting exactly one SPC we
-       ;; would not bomb on names _starting_ with SPC.
-       (point))
+  (if (re-search-forward dired-move-to-filename-regexp eol t)
+      (goto-char (match-end 0))
     (if raise-error
-       (error "No file on this line")
-      nil)))
+       (error "No file on this line"))))
 
 (defun dired-move-to-end-of-filename (&optional no-error)
   ;; Assumes point is at beginning of filename,
@@ -1260,7 +1294,7 @@ Optional arg NO-ERROR-IF-NOT-FILEP means return nil if no filename on
 (defun dired-in-this-tree (file dir)
   ;;"Is FILE part of the directory tree starting at DIR?"
   (let (case-fold-search)
-    (string-match (concat "^" (regexp-quote dir)) file)))
+    (string-match (concat "^" (regexp-quote (expand-file-name dir))) file)))
 
 (defun dired-normalize-subdir (dir)
   ;; Prepend default-directory to DIR if relative path name.
@@ -1334,18 +1368,32 @@ Returns the new value of the alist."
   (interactive)
   (dired-clear-alist)
   (save-excursion
-    (let ((count 0))
+    (let ((count 0)
+         (buffer-read-only nil)
+         new-dir-name)
       (goto-char (point-min))
       (setq dired-subdir-alist nil)
-      (while (re-search-forward dired-subdir-regexp nil t)
+      (while (and (re-search-forward dired-subdir-regexp nil t)
+                 ;; Avoid taking a file name ending in a colon
+                 ;; as a subdir name.
+                 (not (save-excursion
+                        (goto-char (match-beginning 0))
+                        (beginning-of-line)
+                        (forward-char 2)
+                        (save-match-data (looking-at dired-re-perms)))))
+       (save-excursion
+         (goto-char (match-beginning 1))
+         (setq new-dir-name
+               (expand-file-name (buffer-substring (point) (match-end 1))))
+         (delete-region (point) (match-end 1))
+         (insert new-dir-name))
        (setq count (1+ count))
-       (dired-alist-add-1 (buffer-substring (match-beginning 1)
-                                            (match-end 1))
-                        ;; Put subdir boundary between lines:
-                        (save-excursion
-                          (goto-char (match-beginning 0))
-                          (beginning-of-line)
-                          (point-marker))))
+       (dired-alist-add-1 new-dir-name
+                          ;; Place a sub directory boundary between lines.
+                          (save-excursion
+                            (goto-char (match-beginning 0))
+                            (beginning-of-line)
+                            (point-marker))))
       (if (> count 1)
          (message "Buffer includes %d directories" count))
       ;; We don't need to sort it because it is in buffer order per
@@ -1394,7 +1442,7 @@ Returns the new value of the alist."
     (save-excursion
       ;; The hair here is to get the result of dired-goto-subdir
       ;; without really calling it if we don't have any subdirs.
-      (if (if (string= dir default-directory)
+      (if (if (string= dir (expand-file-name default-directory))
              (goto-char (point-min))
            (and (cdr dired-subdir-alist)
                 (dired-goto-subdir dir)))
@@ -1412,7 +1460,10 @@ Returns the new value of the alist."
                    ;; correct) match could have been elsewhere on the
                    ;; ;; line (e.g. "-" would match somewhere in the
                    ;; permission bits).
-                 (setq found (dired-move-to-filename)))))))
+                 (setq found (dired-move-to-filename))
+               ;; If this isn't the right line, move forward to avoid
+               ;; trying this line again.
+               (forward-line 1))))))
     (and found
         ;; return value of point (i.e., FOUND):
         (goto-char found))))
@@ -1637,7 +1688,8 @@ Optional argument means return a file name relative to `default-directory'."
     (save-excursion
       (set-buffer (get-buffer-create bufname))
       (erase-buffer)
-      (dired-format-columns-of-files files))
+      (dired-format-columns-of-files files)
+      (remove-text-properties (point-min) (point-max) '(mouse-face)))
     (save-window-excursion
       (dired-pop-to-buffer bufname)
       (apply function args))))
@@ -1700,7 +1752,8 @@ Optional argument means return a file name relative to `default-directory'."
   ;; Should be equivalent to (save-excursion (not (dired-move-to-filename)))
   ;; but is about 1.5..2.0 times as fast. (Actually that's not worth it)
   (or (looking-at "^$\\|^. *$\\|^. total\\|^. wildcard")
-      (looking-at dired-subdir-regexp)))
+      (and (looking-at dired-subdir-regexp)
+          (save-excursion (not (dired-move-to-filename))))))
 
 (defun dired-next-marked-file (arg &optional wrap opoint)
   "Move to the next marked file, wrapping around the end of the buffer."
@@ -2016,23 +2069,19 @@ Thus, use \\[backward-page] to find the beginning of a group of errors."
   (concat "^-[^t" dired-ls-sorting-switches "]+$")
   "Regexp recognized by dired to set `by name' mode.")
 
-(defvar dired-sort-mode nil
-  "Whether Dired sorts by name, date etc. (buffer-local).")
-;; This is nil outside dired buffers so it can be used in the modeline
-
 (defun dired-sort-set-modeline ()
   ;; Set modeline display according to dired-actual-switches.
   ;; Modeline display of "by name" or "by date" guarantees the user a
   ;; match with the corresponding regexps.  Non-matching switches are
   ;; shown literally.
-  (setq dired-sort-mode
+  (setq mode-name
        (let (case-fold-search)
          (cond ((string-match dired-sort-by-name-regexp dired-actual-switches)
-                " by name")
+                "Dired by name")
                ((string-match dired-sort-by-date-regexp dired-actual-switches)
-                " by date")
+                "Dired by date")
                (t
-                (concat " " dired-actual-switches)))))
+                (concat "Dired " dired-actual-switches)))))
   ;; update mode line:
   (set-buffer-modified-p (buffer-modified-p)))
 
@@ -2051,7 +2100,7 @@ With a prefix argument you can edit the current listing switches instead."
        (let (case-fold-search)
          (concat
           "-l"
-          (dired-replace-in-string (concat "[---lt"
+          (dired-replace-in-string (concat "[-lt"
                                            dired-ls-sorting-switches "]")
                                    ""
                                    dired-actual-switches)
@@ -2301,8 +2350,8 @@ Use \\[dired-hide-subdir] to (un)hide a particular subdirectory."
 (if (eq system-type 'vax-vms)
     (load "dired-vms"))
 
-(run-hooks 'dired-load-hook)           ; for your customizations
-
 (provide 'dired)
 
+(run-hooks 'dired-load-hook)           ; for your customizations
+
 ;;; dired.el ends here