;;; 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, 2010
+;; Copyright (C) 1985-1986, 1992-1997, 2000-2011
;; Free Software Foundation, Inc.
;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>
;;; Commentary:
-;; This is a major mode for directory browsing and editing. It is
-;; documented in the Emacs manual.
+;; This is a major mode for directory browsing and editing.
+;; It is documented in the Emacs manual.
;; Rewritten in 1990/1991 to add tree features, file marking and
;; sorting by Sebastian Kremer <sk@thp.uni-koeln.de>.
:type 'string
:group 'dired)
-(defvar dired-subdir-switches nil
+(defcustom dired-subdir-switches nil
"If non-nil, switches passed to `ls' for inserting subdirectories.
-If nil, `dired-listing-switches' is used.")
-
-; Don't use absolute file names as /bin should be in any PATH and people
-; may prefer /usr/local/gnu/bin or whatever. However, chown is
-; usually not in PATH.
-
-;;;###autoload
-(defvar dired-chown-program
- (purecopy
- (if (memq system-type '(hpux usg-unix-v irix linux 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').")
+If nil, `dired-listing-switches' is used."
+ :group 'dired
+ :type '(choice (const :tag "Use dired-listing-switches" nil)
+ (string :tag "Switches")))
+
+(defcustom dired-chown-program
+ (purecopy (cond ((executable-find "chown") "chown")
+ ((file-executable-p "/usr/sbin/chown") "/usr/sbin/chown")
+ ((file-executable-p "/etc/chown") "/etc/chown")
+ (t "chown")))
+ "Name of chown command (usually `chown')."
+ :group 'dired
+ :type 'file)
-(defvar dired-use-ls-dired (not (not (string-match "gnu" system-configuration)))
- "Non-nil means Dired should use `ls --dired'.")
+(defcustom 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."
+ :group 'dired
+ :type '(choice (const :tag "Check for --dired support" unspecified)
+ (const :tag "Do not use --dired" nil)
+ (other :tag "Use --dired" t)))
-(defvar dired-chmod-program "chmod"
- "Name of chmod command (usually `chmod').")
+(defcustom dired-chmod-program "chmod"
+ "Name of chmod command (usually `chmod')."
+ :group 'dired
+ :type 'file)
-(defvar dired-touch-program "touch"
- "Name of touch command (usually `touch').")
+(defcustom dired-touch-program "touch"
+ "Name of touch command (usually `touch')."
+ :group 'dired
+ :type 'file)
(defcustom dired-ls-F-marks-symlinks nil
"Informs Dired about how `ls -lF' marks symbolic links.
:type 'boolean
:group 'dired-mark)
-;;;###autoload
(defcustom dired-trivial-filenames (purecopy "^\\.\\.?$\\|^#")
"Regexp of files to skip when finding first file of a directory.
A value of nil means move to the subdir line.
directory name and the cdr is the list of files to mention.
The directory name must be absolute, but need not be fully expanded.")
+;; Beware of "-l;reboot" etc. See bug#3230.
+(defun dired-safe-switches-p (switches)
+ "Return non-nil if string SWITCHES does not look risky for dired."
+ (or (not switches)
+ (and (stringp switches)
+ (< (length switches) 100) ; arbitrary
+ (string-match "\\` *-[- [:alnum:]]+\\'" switches))))
+
(defvar dired-actual-switches nil
"The value of `dired-listing-switches' used to make this buffer's text.")
+(put 'dired-actual-switches 'safe-local-variable 'dired-safe-switches-p)
+
(defvar dired-re-inode-size "[0-9 \t]*"
"Regexp for optional initial inode and file size as made by `ls -i -s'.")
(if current-prefix-arg
(read-string "Dired listing switches: "
dired-listing-switches))
- ;; If a dialog is about to be used, call read-directory-name so
- ;; the dialog code knows we want directories. Some dialogs can
- ;; only select directories or files when popped up, not both.
+ ;; If a dialog is used, call `read-directory-name' so the
+ ;; dialog code knows we want directories. Some dialogs
+ ;; can only select directories or files when popped up,
+ ;; not both. If no dialog is used, call `read-file-name'
+ ;; because the user may want completion of file names for
+ ;; use in a wildcard pattern.
(if (next-read-file-uses-dialog-p)
(read-directory-name (format "Dired %s(directory): " str)
nil default-directory nil)
buffer-read-only
(dired-directory-changed-p dirname))))
-;;;###autoload
(defcustom dired-auto-revert-buffer nil
"Automatically revert dired buffer on revisiting.
If t, revisiting an existing dired buffer automatically reverts it.
;; killed buffer, it is removed from this list.
"Alist of expanded directories and their associated dired buffers.")
+(defvar dired-find-subdir)
+
+;; FIXME add a doc-string, and document dired-x extensions.
(defun dired-find-buffer-nocreate (dirname &optional mode)
;; This differs from dired-buffers-for-dir in that it does not consider
;; subdirs of default-directory and searches for the first match only.
;; Also, the major mode must be MODE.
- (setq dirname (expand-file-name dirname))
- (let (found (blist dired-buffers)) ; was (buffer-list)
- (or mode (setq mode 'dired-mode))
- (while blist
- (if (null (buffer-name (cdr (car blist))))
- (setq blist (cdr blist))
- (with-current-buffer (cdr (car blist))
- (if (and (eq major-mode mode)
- dired-directory ;; nil during find-alternate-file
- (equal dirname
- (expand-file-name
- (if (consp dired-directory)
- (car dired-directory)
- dired-directory))))
- (setq found (cdr (car blist))
- blist nil)
- (setq blist (cdr blist))))))
- found))
+ (if (and (featurep 'dired-x)
+ dired-find-subdir
+ ;; Don't try to find a wildcard as a subdirectory.
+ (string-equal dirname (file-name-directory dirname)))
+ (let* ((cur-buf (current-buffer))
+ (buffers (nreverse
+ (dired-buffers-for-dir (expand-file-name dirname))))
+ (cur-buf-matches (and (memq cur-buf buffers)
+ ;; Wildcards must match, too:
+ (equal dired-directory dirname))))
+ ;; We don't want to switch to the same buffer---
+ (setq buffers (delq cur-buf buffers))
+ (or (car (sort buffers #'dired-buffer-more-recently-used-p))
+ ;; ---unless it's the only possibility:
+ (and cur-buf-matches cur-buf)))
+ ;; No dired-x, or dired-find-subdir nil.
+ (setq dirname (expand-file-name dirname))
+ (let (found (blist dired-buffers)) ; was (buffer-list)
+ (or mode (setq mode 'dired-mode))
+ (while blist
+ (if (null (buffer-name (cdr (car blist))))
+ (setq blist (cdr blist))
+ (with-current-buffer (cdr (car blist))
+ (if (and (eq major-mode mode)
+ dired-directory ;; nil during find-alternate-file
+ (equal dirname
+ (expand-file-name
+ (if (consp dired-directory)
+ (car dired-directory)
+ dired-directory))))
+ (setq found (cdr (car blist))
+ blist nil)
+ (setq blist (cdr blist))))))
+ found)))
\f
;; Read in a new dired buffer
(set-marker file nil)))))
+(defvar ls-lisp-use-insert-directory-program)
+
(defun dired-insert-directory (dir switches &optional file-list wildcard hdr)
"Insert a directory listing of DIR, Dired style.
Use SWITCHES to make the listings.
(let ((opoint (point))
(process-environment (copy-sequence process-environment))
end)
- (if (or dired-use-ls-dired (file-remote-p dir))
+ (if (and
+ ;; Don't try to invoke `ls' if we are on DOS/Windows where
+ ;; ls-lisp emulation is used, except if they want to use `ls'
+ ;; as indicated by `ls-lisp-use-insert-directory-program'.
+ (not (and (featurep 'ls-lisp)
+ (null ls-lisp-use-insert-directory-program)))
+ (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,
"Reread the dired buffer.
Must also be called after `dired-actual-switches' have changed.
Should not fail even on completely garbaged buffers.
-Preserves old cursor, marks/flags, hidden-p."
+Preserves old cursor, marks/flags, hidden-p.
+
+Dired sets `revert-buffer-function' to this function. The args
+ARG and NOCONFIRM, passed from `revert-buffer', are ignored."
(widen) ; just in case user narrowed
(let ((modflag (buffer-modified-p))
(positions (dired-save-positions))
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
;; This looks ugly when substitute-command-keys uses C-d instead d:
;; (define-key dired-mode-map "\C-d" 'dired-flag-file-deletion)
(let ((map (make-keymap)))
- (suppress-keymap map)
+ (set-keymap-parent map special-mode-map)
(define-key map [mouse-2] 'dired-mouse-find-file-other-window)
(define-key map [follow-link] 'mouse-face)
;; Commands to mark or flag certain categories of files
(define-key map "\C-m" 'dired-find-file)
(put 'dired-find-file :advertised-binding "\C-m")
(define-key map "g" 'revert-buffer)
- (define-key map "h" 'describe-mode)
(define-key map "i" 'dired-maybe-insert-subdir)
(define-key map "j" 'dired-goto-file)
(define-key map "k" 'dired-do-kill-lines)
(define-key map "o" 'dired-find-file-other-window)
(define-key map "\C-o" 'dired-display-file)
(define-key map "p" 'dired-previous-line)
- (define-key map "q" 'quit-window)
(define-key map "s" 'dired-sort-toggle-or-edit)
(define-key map "t" 'dired-toggle-marks)
(define-key map "u" 'dired-unmark)
(set (make-local-variable 'desktop-save-buffer)
'dired-desktop-buffer-misc-data)
(setq dired-switches-alist nil)
+ (hack-dir-local-variables-non-file-buffer) ; before sorting
(dired-sort-other dired-actual-switches t)
(when (featurep 'dnd)
(set (make-local-variable 'dnd-protocol-alist)
;; 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.
;; 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
;; return value of point (i.e., FOUND):
(goto-char found))))
+(defvar dired-find-subdir)
+
+;; FIXME document whatever dired-x is doing.
(defun dired-initial-position (dirname)
- ;; Where point should go in a new listing of DIRNAME.
- ;; Point assumed at beginning of new subdir line.
- ;; You may redefine this function as you wish, e.g. like in dired-x.el.
+ "Where point should go in a new listing of DIRNAME.
+Point assumed at beginning of new subdir line."
(end-of-line)
+ (and (featurep 'dired-x) dired-find-subdir
+ (dired-goto-subdir dirname))
(if dired-trivial-filenames (dired-goto-next-nontrivial-file)))
\f
;; These are hooks which make tree dired work.
(save-excursion (forward-line 1) (point))))))
(dired-clean-up-after-deletion file))
-;; This is a separate function for the sake of dired-x.el.
+(defvar dired-clean-up-buffers-too)
+
(defun dired-clean-up-after-deletion (fn)
- ;; Clean up after a deleted file or directory FN.
+ "Clean up after a deleted file or directory FN.
+Removes any expanded subdirectory of deleted directory.
+If `dired-x' is loaded and `dired-clean-up-buffers-too' is non-nil,
+also offers to kill buffers visiting deleted files and directories."
(save-excursion (and (cdr dired-subdir-alist)
(dired-goto-subdir fn)
- (dired-kill-subdir))))
+ (dired-kill-subdir)))
+ ;; Offer to kill buffer of deleted file FN.
+ (when (and (featurep 'dired-x) dired-clean-up-buffers-too)
+ (let ((buf (get-file-buffer fn)))
+ (and buf
+ (funcall #'y-or-n-p
+ (format "Kill buffer of %s, too? "
+ (file-name-nondirectory fn)))
+ (kill-buffer buf)))
+ (let ((buf-list (dired-buffers-for-dir (expand-file-name fn))))
+ (and buf-list
+ (y-or-n-p (format "Kill dired buffer%s of %s, too? "
+ (dired-plural-s (length buf-list))
+ (file-name-nondirectory fn)))
+ (dolist (buf buf-list)
+ (kill-buffer buf))))))
+
\f
;; Confirmation
;; 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
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
(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"))
(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))
;;;;;; 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" "416d272299fd4774c47c2f677ee640a4")
+;;;;;; dired-diff) "dired-aux" "dired-aux.el" "154cdfbf451aedec60c5012b625ff329")
;;; Generated autoloads from dired-aux.el
(autoload 'dired-diff "dired-aux" "\
\(fn FILE)" nil nil)
(autoload 'dired-query "dired-aux" "\
-Query user and return nil or t.
-Store answer in symbol VAR (which must initially be bound to nil).
-Format PROMPT with ARGS.
-Binding variable `help-form' will help the user who types the help key.
+Format PROMPT with ARGS, query user, and store the result in SYM.
+The return value is either nil or t.
+
+The user may type y or SPC to accept once; n or DEL to skip once;
+! to accept this and subsequent queries; or q or ESC to decline
+this and subsequent queries.
+
+If SYM is already bound to a non-nil value, this function may
+return automatically without querying the user. If SYM is !,
+return t; if SYM is q or ESC, return nil.
-\(fn QS-VAR QS-PROMPT &rest QS-ARGS)" nil nil)
+\(fn SYM PROMPT &rest ARGS)" nil nil)
(autoload 'dired-do-compress "dired-aux" "\
Compress or uncompress marked (or next ARG) files.
;;;***
\f
-;;;### (autoloads (dired-do-relsymlink dired-jump) "dired-x" "dired-x.el"
-;;;;;; "27c312d6d5d40d8cb4ef8d62e30d5f4a")
+;;;### (autoloads (dired-do-relsymlink dired-jump-other-window dired-jump)
+;;;;;; "dired-x" "dired-x.el" "87fd4ae2fdade7e0f11c4a0b1cfdeda2")
;;; Generated autoloads from dired-x.el
(autoload 'dired-jump "dired-x" "\
\(fn &optional OTHER-WINDOW FILE-NAME)" t nil)
+(autoload 'dired-jump-other-window "dired-x" "\
+Like \\[dired-jump] (`dired-jump') but in other window.
+
+\(fn &optional FILE-NAME)" t nil)
+
(autoload 'dired-do-relsymlink "dired-x" "\
Relative symlink all marked (or next ARG) files into a directory.
Otherwise make a relative symbolic link to the current file.
(run-hooks 'dired-load-hook) ; for your customizations
-;; arch-tag: e1af7a8f-691c-41a0-aac1-ddd4d3c87517
;;; dired.el ends here