(compilation-error-regexp-alist): Fix previous change.
[bpt/emacs.git] / lisp / dired.el
CommitLineData
c8472948 1;;; dired.el --- directory-browsing commands
52041219 2
d733c5ec 3;; Copyright (C) 1985, 1986, 1992, 1993, 1994 Free Software Foundation, Inc.
ab67260b 4
b36b40ae
RS
5;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>
6;; Maintainer: FSF
84fc2cfa
ER
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
52041219 12;; the Free Software Foundation; either version 2, or (at your option)
84fc2cfa
ER
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs; see the file COPYING. If not, write to
22;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
52041219
RS
24;;; Commentary:
25
e41b2db1
ER
26;; This is a major mode for directory browsing and editing. It is
27;; documented in the Emacs manual.
28
492d2437
RS
29;; Rewritten in 1990/1991 to add tree features, file marking and
30;; sorting by Sebastian Kremer <sk@thp.uni-koeln.de>.
31;; Finished up by rms in 1992.
32
52041219 33;;; Code:
492d2437 34
492d2437
RS
35;;; Customizable variables
36
84fc2cfa 37;;;###autoload
492d2437
RS
38(defvar dired-listing-switches "-al"
39 "*Switches passed to `ls' for dired. MUST contain the `l' option.
40May contain all other options that don't contradict `-l';
b36b40ae
RS
41may contain even `F', `b', `i' and `s'. See also the variable
42`dired-ls-F-marks-symlinks' concerning the `F' switch.")
84fc2cfa 43
492d2437
RS
44; Don't use absolute paths as /bin should be in any PATH and people
45; may prefer /usr/local/gnu/bin or whatever. However, chown is
46; usually not in PATH.
47
48;;;###autoload
84fc2cfa 49(defvar dired-chown-program
d43e0b16 50 (if (memq system-type '(hpux dgux usg-unix-v irix linux))
194ff7c1 51 "chown" "/etc/chown")
eb8c3be9 52 "Name of chown command (usually `chown' or `/etc/chown').")
492d2437 53
492d2437
RS
54;;;###autoload
55(defvar dired-ls-F-marks-symlinks nil
56 "*Informs dired about how `ls -lF' marks symbolic links.
c3554e95 57Set this to t if `insert-directory-program' with `-lF' marks the symbolic link
492d2437 58itself with a trailing @ (usually the case under Ultrix).
84fc2cfa 59
492d2437
RS
60Example: if `ln -s foo bar; ls -F bar' gives `bar -> foo', set it to
61nil (the default), if it gives `bar@ -> foo', set it to t.
62
63Dired checks if there is really a @ appended. Thus, if you have a
64marking `ls' program on one host and a non-marking on another host, and
65don't care about symbolic links which really end in a @, you can
66always set this variable to t.")
67
68;;;###autoload
69(defvar dired-trivial-filenames "^\\.\\.?$\\|^#"
70 "*Regexp of files to skip when finding first file of a directory.
71A value of nil means move to the subdir line.
72A value of t means move to first file.")
73
74;;;###autoload
75(defvar dired-keep-marker-rename t
76 ;; Use t as default so that moved files "take their markers with them".
77 "*Controls marking of renamed files.
78If t, files keep their previous marks when they are renamed.
79If a character, renamed files (whether previously marked or not)
80are afterward marked with that character.")
81
82;;;###autoload
83(defvar dired-keep-marker-copy ?C
84 "*Controls marking of copied files.
85If t, copied files are marked if and as the corresponding original files were.
86If a character, copied files are unconditionally marked with that character.")
87
88;;;###autoload
89(defvar dired-keep-marker-hardlink ?H
90 "*Controls marking of newly made hard links.
91If t, they are marked if and as the files linked to were marked.
92If a character, new links are unconditionally marked with that character.")
93
94;;;###autoload
95(defvar dired-keep-marker-symlink ?Y
96 "*Controls marking of newly made symbolic links.
97If t, they are marked if and as the files linked to were marked.
98If a character, new links are unconditionally marked with that character.")
99
100;;;###autoload
101(defvar dired-dwim-target nil
102 "*If non-nil, dired tries to guess a default target directory.
103This means: if there is a dired buffer displayed in the next window,
104use its current subdir, instead of the current subdir of this dired buffer.
105
106The target is used in the prompt for file copy, rename etc.")
107
108;;;###autoload
109(defvar dired-copy-preserve-time t
110 "*If non-nil, Dired preserves the last-modified time in a file copy.
111\(This works on only some systems.)")
112
113;;; Hook variables
114
115(defvar dired-load-hook nil
116 "Run after loading dired.
117You can customize key bindings or load extensions with this.")
118
119(defvar dired-mode-hook nil
120 "Run at the very end of dired-mode.")
121
122(defvar dired-before-readin-hook nil
123 "This hook is run before a dired buffer is read in (created or reverted).")
124
125(defvar dired-after-readin-hook nil
126 "Hook run after each time a file or directory is read by Dired.
127After each listing of a file or directory, this hook is run
128with the buffer narrowed to the listing.")
129;; Note this can't simply be run inside function `dired-ls' as the hook
130;; functions probably depend on the dired-subdir-alist to be OK.
131
132;;; Internal variables
133
134(defvar dired-marker-char ?* ; the answer is 42
135 ;; so that you can write things like
136 ;; (let ((dired-marker-char ?X))
137 ;; ;; great code using X markers ...
138 ;; )
139 ;; For example, commands operating on two sets of files, A and B.
140 ;; Or marking files with digits 0-9. This could implicate
141 ;; concentric sets or an order for the marked files.
142 ;; The code depends on dynamic scoping on the marker char.
143 "In Dired, the current mark character.
144This is what the `do' commands look for and what the `mark' commands store.")
145
146(defvar dired-del-marker ?D
147 "Character used to flag files for deletion.")
148
149(defvar dired-shrink-to-fit
ab67260b
RS
150 t
151;; I see no reason ever to make this nil -- rms.
152;; (> baud-rate search-slow-speed)
492d2437
RS
153 "Non-nil means Dired shrinks the display buffer to fit the marked files.")
154
155(defvar dired-flagging-regexp nil);; Last regexp used to flag files.
156
ab67260b
RS
157(defvar dired-file-version-alist)
158
492d2437
RS
159(defvar dired-directory nil
160 "The directory name or shell wildcard that was used as argument to `ls'.
8d23c16b
ER
161Local to each dired buffer. May be a list, in which case the car is the
162directory name and the cdr is the actual files to list.")
492d2437
RS
163
164(defvar dired-actual-switches nil
165 "The value of `dired-listing-switches' used to make this buffer's text.")
166
167(defvar dired-re-inode-size "[0-9 \t]*"
168 "Regexp for optional initial inode and file size as made by `ls -i -s'.")
169
170;; These regexps must be tested at beginning-of-line, but are also
171;; used to search for next matches, so neither omitting "^" nor
172;; replacing "^" by "\n" (to make it slightly faster) will work.
173
174(defvar dired-re-mark "^[^ \n]")
175;; "Regexp matching a marked line.
176;; Important: the match ends just after the marker."
177(defvar dired-re-maybe-mark "^. ")
178(defvar dired-re-dir (concat dired-re-maybe-mark dired-re-inode-size "d"))
179(defvar dired-re-sym (concat dired-re-maybe-mark dired-re-inode-size "l"))
180(defvar dired-re-exe;; match ls permission string of an executable file
181 (mapconcat (function
182 (lambda (x)
183 (concat dired-re-maybe-mark dired-re-inode-size x)))
184 '("-[-r][-w][xs][-r][-w].[-r][-w]."
185 "-[-r][-w].[-r][-w][xs][-r][-w]."
186 "-[-r][-w].[-r][-w].[-r][-w][xst]")
187 "\\|"))
acf310c9 188(defvar dired-re-perms "-[-r][-w].[-r][-w].[-r][-w].")
492d2437
RS
189(defvar dired-re-dot "^.* \\.\\.?$")
190
191(defvar dired-subdir-alist nil
192 "Association list of subdirectories and their buffer positions.
193Each subdirectory has an element: (DIRNAME . STARTMARKER).
7b2469ae
RS
194The order of elements is the reverse of the order in the buffer.
195In simple cases, this list contains one element.")
492d2437 196
cdf156a9 197(defvar dired-subdir-regexp "^. \\([^\n\r]+\\)\\(:\\)[\n\r]"
492d2437
RS
198 "Regexp matching a maybe hidden subdirectory line in `ls -lR' output.
199Subexpression 1 is the subdirectory proper, no trailing colon.
200The match starts at the beginning of the line and ends after the end
201of the line (\\n or \\r).
202Subexpression 2 must end right before the \\n or \\r.")
203
204\f
205;;; Macros must be defined before they are used, for the byte compiler.
206
207;; Mark all files for which CONDITION evals to non-nil.
208;; CONDITION is evaluated on each line, with point at beginning of line.
209;; MSG is a noun phrase for the type of files being marked.
210;; It should end with a noun that can be pluralized by adding `s'.
211;; Return value is the number of files marked, or nil if none were marked.
212(defmacro dired-mark-if (predicate msg)
213 (` (let (buffer-read-only count)
214 (save-excursion
215 (setq count 0)
216 (if (, msg) (message "Marking %ss..." (, msg)))
217 (goto-char (point-min))
218 (while (not (eobp))
219 (if (, predicate)
220 (progn
221 (delete-char 1)
222 (insert dired-marker-char)
223 (setq count (1+ count))))
224 (forward-line 1))
225 (if (, msg) (message "%s %s%s %s%s."
226 count
227 (, msg)
228 (dired-plural-s count)
229 (if (eq dired-marker-char ?\040) "un" "")
230 (if (eq dired-marker-char dired-del-marker)
231 "flagged" "marked"))))
232 (and (> count 0) count))))
233
234(defmacro dired-map-over-marks (body arg &optional show-progress)
235;; "Macro: Perform BODY with point somewhere on each marked line
236;;and return a list of BODY's results.
237;;If no marked file could be found, execute BODY on the current line.
238;; If ARG is an integer, use the next ARG (or previous -ARG, if ARG<0)
239;; files instead of the marked files.
240;; In that case point is dragged along. This is so that commands on
241;; the next ARG (instead of the marked) files can be chained easily.
242;; If ARG is otherwise non-nil, use current file instead.
243;;If optional third arg SHOW-PROGRESS evaluates to non-nil,
244;; redisplay the dired buffer after each file is processed.
245;;No guarantee is made about the position on the marked line.
246;; BODY must ensure this itself if it depends on this.
247;;Search starts at the beginning of the buffer, thus the car of the list
248;; corresponds to the line nearest to the buffer's bottom. This
249;; is also true for (positive and negative) integer values of ARG.
250;;BODY should not be too long as it is expanded four times."
251;;
252;;Warning: BODY must not add new lines before point - this may cause an
253;;endless loop.
254;;This warning should not apply any longer, sk 2-Sep-1991 14:10.
255 (` (prog1
256 (let (buffer-read-only case-fold-search found results)
257 (if (, arg)
258 (if (integerp (, arg))
259 (progn;; no save-excursion, want to move point.
260 (dired-repeat-over-lines
261 (, arg)
262 (function (lambda ()
263 (if (, show-progress) (sit-for 0))
264 (setq results (cons (, body) results)))))
265 (if (< (, arg) 0)
266 (nreverse results)
267 results))
268 ;; non-nil, non-integer ARG means use current file:
269 (list (, body)))
270 (let ((regexp (dired-marker-regexp)) next-position)
271 (save-excursion
272 (goto-char (point-min))
273 ;; remember position of next marked file before BODY
274 ;; can insert lines before the just found file,
275 ;; confusing us by finding the same marked file again
276 ;; and again and...
277 (setq next-position (and (re-search-forward regexp nil t)
278 (point-marker))
279 found (not (null next-position)))
280 (while next-position
281 (goto-char next-position)
282 (if (, show-progress) (sit-for 0))
283 (setq results (cons (, body) results))
284 ;; move after last match
285 (goto-char next-position)
286 (forward-line 1)
287 (set-marker next-position nil)
288 (setq next-position (and (re-search-forward regexp nil t)
289 (point-marker)))))
290 (if found
291 results
292 (list (, body))))))
293 ;; save-excursion loses, again
294 (dired-move-to-filename))))
295
296(defun dired-get-marked-files (&optional localp arg)
297 "Return the marked files' names as list of strings.
298The list is in the same order as the buffer, that is, the car is the
299 first marked file.
300Values returned are normally absolute pathnames.
301Optional arg LOCALP as in `dired-get-filename'.
302Optional second argument ARG forces to use other files. If ARG is an
303 integer, use the next ARG files. If ARG is otherwise non-nil, use
304 current file. Usually ARG comes from the current prefix arg."
84fc2cfa 305 (save-excursion
492d2437 306 (nreverse (dired-map-over-marks (dired-get-filename localp) arg))))
84fc2cfa 307
492d2437
RS
308\f
309;; Function dired-ls is redefinable for VMS, ange-ftp, Prospero or
310;; other special applications.
492d2437
RS
311\f
312;; The dired command
313
314(defun dired-read-dir-and-switches (str)
315 ;; For use in interactive.
316 (reverse (list
317 (if current-prefix-arg
318 (read-string "Dired listing switches: "
319 dired-listing-switches))
320 (read-file-name (format "Dired %s(directory): " str)
321 nil default-directory nil))))
84fc2cfa 322
492d2437 323;;;###autoload (define-key ctl-x-map "d" 'dired)
84fc2cfa 324;;;###autoload
492d2437 325(defun dired (dirname &optional switches)
84fc2cfa 326 "\"Edit\" directory DIRNAME--delete, rename, print, etc. some files in it.
492d2437
RS
327Optional second argument SWITCHES specifies the `ls' options used.
328\(Interactively, use a prefix argument to be able to specify SWITCHES.)
329Dired displays a list of files in DIRNAME (which may also have
8d23c16b
ER
330shell wildcards appended to select certain files). If DIRNAME is a cons,
331its first element is taken as the directory name and the resr as an explicit
332list of files to make directory entries for.
52041219 333\\<dired-mode-map>\
492d2437 334You can move around in it with the usual commands.
8d23c16b
ER
335You can flag files for deletion with \\[dired-flag-file-deletion] and then
336delete them by typing \\[dired-do-flagged-delete].
492d2437 337Type \\[describe-mode] after entering dired for more info.
84fc2cfa 338
492d2437
RS
339If DIRNAME is already in a dired buffer, that buffer is used without refresh."
340 ;; Cannot use (interactive "D") because of wildcards.
341 (interactive (dired-read-dir-and-switches ""))
342 (switch-to-buffer (dired-noselect dirname switches)))
343
344;;;###autoload (define-key ctl-x-4-map "d" 'dired-other-window)
84fc2cfa 345;;;###autoload
492d2437 346(defun dired-other-window (dirname &optional switches)
84fc2cfa 347 "\"Edit\" directory DIRNAME. Like `dired' but selects in another window."
492d2437
RS
348 (interactive (dired-read-dir-and-switches "in other window "))
349 (switch-to-buffer-other-window (dired-noselect dirname switches)))
84fc2cfa 350
ec03e49c
RS
351;;;###autoload (define-key ctl-x-5-map "d" 'dired-other-frame)
352;;;###autoload
353(defun dired-other-frame (dirname &optional switches)
354 "\"Edit\" directory DIRNAME. Like `dired' but makes a new frame."
355 (interactive (dired-read-dir-and-switches "in other frame "))
356 (switch-to-buffer-other-frame (dired-noselect dirname switches)))
357
84fc2cfa 358;;;###autoload
8d23c16b 359(defun dired-noselect (dir-or-list &optional switches)
84fc2cfa 360 "Like `dired' but returns the dired buffer as value, does not select it."
8d23c16b 361 (or dir-or-list (setq dir-or-list default-directory))
492d2437
RS
362 ;; This loses the distinction between "/foo/*/" and "/foo/*" that
363 ;; some shells make:
8d23c16b
ER
364 (let (dirname)
365 (if (consp dir-or-list)
366 (setq dirname (car dir-or-list))
367 (setq dirname dir-or-list))
370b6149
RS
368 (setq dirname (abbreviate-file-name
369 (expand-file-name (directory-file-name dirname))))
8d23c16b
ER
370 (if (file-directory-p dirname)
371 (setq dirname (file-name-as-directory dirname)))
372 (if (consp dir-or-list)
373 (setq dir-or-list (cons dirname (cdr dir-or-list)))
374 (setq dir-or-list dirname))
375 (dired-internal-noselect dir-or-list switches)))
492d2437
RS
376
377;; Separate function from dired-noselect for the sake of dired-vms.el.
8d23c16b 378(defun dired-internal-noselect (dir-or-list &optional switches)
492d2437
RS
379 ;; If there is an existing dired buffer for DIRNAME, just leave
380 ;; buffer as it is (don't even call dired-revert).
381 ;; This saves time especially for deep trees or with ange-ftp.
382 ;; The user can type `g'easily, and it is more consistent with find-file.
383 ;; But if SWITCHES are given they are probably different from the
384 ;; buffer's old value, so call dired-sort-other, which does
385 ;; revert the buffer.
386 ;; A pity we can't possibly do "Directory has changed - refresh? "
387 ;; like find-file does.
8d23c16b
ER
388 (let* ((dirname (if (consp dir-or-list) (car dir-or-list) dir-or-list))
389 (buffer (dired-find-buffer-nocreate dir-or-list))
492d2437
RS
390 ;; note that buffer already is in dired-mode, if found
391 (new-buffer-p (not buffer))
392 (old-buf (current-buffer)))
393 (or buffer
394 (let ((default-major-mode 'fundamental-mode))
395 ;; We don't want default-major-mode to run hooks and set auto-fill
396 ;; or whatever, now that dired-mode does not
397 ;; kill-all-local-variables any longer.
398 (setq buffer (create-file-buffer (directory-file-name dirname)))))
399 (set-buffer buffer)
400 (if (not new-buffer-p) ; existing buffer ...
401 (if switches ; ... but new switches
fa562dd5
RS
402 (dired-sort-other switches) ; this calls dired-revert
403 ;; If directory has changed on disk, offer to revert.
404 (if (let ((attributes (file-attributes dirname))
405 (modtime (visited-file-modtime)))
e9ce5ade
RS
406 (or (eq modtime 0)
407 (not (eq (car attributes) t))
fa562dd5
RS
408 (and (= (car (nth 5 attributes)) (car modtime))
409 (= (nth 1 (nth 5 attributes)) (cdr modtime)))))
410 nil
a8004e4b 411 (message "Directory has changed on disk; type `g' to update Dired")))
492d2437 412 ;; Else a new buffer
847aabce 413 (setq default-directory
370b6149
RS
414 (if (file-directory-p dirname)
415 dirname
416 (file-name-directory dirname)))
492d2437
RS
417 (or switches (setq switches dired-listing-switches))
418 (dired-mode dirname switches)
419 ;; default-directory and dired-actual-switches are set now
420 ;; (buffer-local), so we can call dired-readin:
421 (let ((failed t))
422 (unwind-protect
8d23c16b 423 (progn (dired-readin dir-or-list buffer)
492d2437
RS
424 (setq failed nil))
425 ;; dired-readin can fail if parent directories are inaccessible.
426 ;; Don't leave an empty buffer around in that case.
427 (if failed (kill-buffer buffer))))
428 ;; No need to narrow since the whole buffer contains just
429 ;; dired-readin's output, nothing else. The hook can
430 ;; successfully use dired functions (e.g. dired-get-filename)
431 ;; as the subdir-alist has been built in dired-readin.
432 (run-hooks 'dired-after-readin-hook)
433 (goto-char (point-min))
434 (dired-initial-position dirname))
435 (set-buffer old-buf)
84fc2cfa
ER
436 buffer))
437
492d2437
RS
438;; This differs from dired-buffers-for-dir in that it does not consider
439;; subdirs of default-directory and searches for the first match only
440(defun dired-find-buffer-nocreate (dirname)
441 (let (found (blist (buffer-list)))
442 (while blist
443 (save-excursion
444 (set-buffer (car blist))
445 (if (and (eq major-mode 'dired-mode)
446 (equal dired-directory dirname))
447 (setq found (car blist)
448 blist nil)
449 (setq blist (cdr blist)))))
450 found))
451
452\f
453;; Read in a new dired buffer
454
455;; dired-readin differs from dired-insert-subdir in that it accepts
456;; wildcards, erases the buffer, and builds the subdir-alist anew
457;; (including making it buffer-local and clearing it first).
8d23c16b 458(defun dired-readin (dir-or-list buffer)
492d2437
RS
459 ;; default-directory and dired-actual-switches must be buffer-local
460 ;; and initialized by now.
461 ;; Thus we can test (equal default-directory dirname) instead of
462 ;; (file-directory-p dirname) and save a filesystem transaction.
463 ;; Also, we can run this hook which may want to modify the switches
464 ;; based on default-directory, e.g. with ange-ftp to a SysV host
465 ;; where ls won't understand -Al switches.
8d23c16b
ER
466 (let (dirname)
467 (if (consp dir-or-list)
468 (setq dirname (car dir-or-list))
469 (setq dirname dir-or-list))
470 (setq dirname (expand-file-name dirname))
471 (if (consp dir-or-list)
472 (setq dir-or-list (cons dirname (cdr dir-or-list))))
473 (run-hooks 'dired-before-readin-hook)
474 (save-excursion
475 (message "Reading directory %s..." dirname)
476 (set-buffer buffer)
477 (let (buffer-read-only (failed t))
478 (widen)
479 (erase-buffer)
480 (dired-readin-insert dir-or-list)
481 (indent-rigidly (point-min) (point-max) 2)
482 ;; We need this to make the root dir have a header line as all
483 ;; other subdirs have:
484 (goto-char (point-min))
485 (dired-insert-headerline default-directory)
486 ;; can't run dired-after-readin-hook here, it may depend on the subdir
487 ;; alist to be OK.
488 )
489 (message "Reading directory %s...done" dirname)
8d23c16b
ER
490 ;; Must first make alist buffer local and set it to nil because
491 ;; dired-build-subdir-alist will call dired-clear-alist first
492 (set (make-local-variable 'dired-subdir-alist) nil)
8197b8bf 493 (dired-build-subdir-alist)
fa562dd5
RS
494 (let ((attributes (file-attributes dirname)))
495 (if (eq (car attributes) t)
496 (set-visited-file-modtime (nth 5 attributes))))
8197b8bf 497 (set-buffer-modified-p nil))))
492d2437
RS
498
499;; Subroutines of dired-readin
500
8d23c16b
ER
501(defun dired-readin-insert (dir-or-list)
502 ;; Just insert listing for the passed-in directory or
503 ;; directory-and-file list, assuming a clean buffer.
504 (let (dirname)
505 (if (consp dir-or-list)
506 (setq dirname (car dir-or-list))
507 (setq dirname dir-or-list))
f45da5d1
RS
508 ;; Expand before comparing in case one or both have been abbreviated.
509 (if (and (equal (expand-file-name default-directory)
510 (expand-file-name dirname))
cf39fa9b
RS
511 (not (consp dir-or-list)))
512 ;; If we are reading a whole single directory...
8d23c16b
ER
513 (dired-insert-directory dir-or-list dired-actual-switches nil t)
514 (if (not (file-readable-p
515 (directory-file-name (file-name-directory dirname))))
516 (error "Directory %s inaccessible or nonexistent" dirname)
cf39fa9b
RS
517 ;; Else assume it contains wildcards,
518 ;; unless it is an explicit list of files.
519 (dired-insert-directory dir-or-list dired-actual-switches
520 (not (listp dir-or-list)))
8d23c16b
ER
521 (save-excursion ;; insert wildcard instead of total line:
522 (goto-char (point-min))
523 (insert "wildcard " (file-name-nondirectory dirname) "\n"))))))
524
525(defun dired-insert-directory (dir-or-list switches &optional wildcard full-p)
526 ;; Do the right thing whether dir-or-list is atomic or not. If it is,
527 ;; inset all files listed in the cdr (the car is the passed-in directory
f726257e 528 ;; list).
cb88a3db
RS
529 (let ((opoint (point)))
530 (if (consp dir-or-list)
531 (progn
532 (mapcar
533 (function (lambda (x) (insert-directory x switches wildcard full-p)))
534 (cdr dir-or-list)))
535 (insert-directory dir-or-list switches wildcard full-p))
536 (dired-insert-set-properties opoint (point)))
8d23c16b 537 (setq dired-directory dir-or-list))
492d2437 538
cb88a3db
RS
539(defun dired-insert-set-properties (beg end)
540 (save-excursion
541 (goto-char beg)
542 (while (< (point) end)
543 (if (dired-move-to-filename)
544 (put-text-property (point)
545 (save-excursion
546 (dired-move-to-end-of-filename)
547 (point))
548 'mouse-face 'highlight))
549 (forward-line 1))))
550
492d2437
RS
551(defun dired-insert-headerline (dir);; also used by dired-insert-subdir
552 ;; Insert DIR's headerline with no trailing slash, exactly like ls
553 ;; would, and put cursor where dired-build-subdir-alist puts subdir
554 ;; boundaries.
555 (save-excursion (insert " " (directory-file-name dir) ":\n")))
556
557\f
558;; Reverting a dired buffer
559
84fc2cfa 560(defun dired-revert (&optional arg noconfirm)
492d2437
RS
561 ;; Reread the dired buffer. Must also be called after
562 ;; dired-actual-switches have changed.
563 ;; Should not fail even on completely garbaged buffers.
564 ;; Preserves old cursor, marks/flags, hidden-p.
565 (widen) ; just in case user narrowed
84fc2cfa 566 (let ((opoint (point))
492d2437
RS
567 (ofile (dired-get-filename nil t))
568 (mark-alist nil) ; save marked files
569 (hidden-subdirs (dired-remember-hidden))
570 (old-subdir-alist (cdr (reverse dired-subdir-alist))) ; except pwd
571 (case-fold-search nil) ; we check for upper case ls flags
572 buffer-read-only)
573 (goto-char (point-min))
574 (setq mark-alist;; only after dired-remember-hidden since this unhides:
575 (dired-remember-marks (point-min) (point-max)))
576 ;; treat top level dir extra (it may contain wildcards)
8d23c16b
ER
577 (dired-uncache
578 (if (consp dired-directory) (car dired-directory) dired-directory))
84fc2cfa 579 (dired-readin dired-directory (current-buffer))
492d2437
RS
580 (let ((dired-after-readin-hook nil))
581 ;; don't run that hook for each subdir...
582 (dired-insert-old-subdirs old-subdir-alist))
583 (dired-mark-remembered mark-alist) ; mark files that were marked
584 ;; ... run the hook for the whole buffer, and only after markers
585 ;; have been reinserted (else omitting in dired-x would omit marked files)
586 (run-hooks 'dired-after-readin-hook) ; no need to narrow
587 (or (and ofile (dired-goto-file ofile)) ; move cursor to where it
588 (goto-char opoint)) ; was before
84fc2cfa 589 (dired-move-to-filename)
492d2437
RS
590 (save-excursion ; hide subdirs that were hidden
591 (mapcar (function (lambda (dir)
592 (if (dired-goto-subdir dir)
593 (dired-hide-subdir 1))))
594 hidden-subdirs)))
595 ;; outside of the let scope
596;;; Might as well not override the user if the user changed this.
597;;; (setq buffer-read-only t)
598 )
599
600;; Subroutines of dired-revert
601;; Some of these are also used when inserting subdirs.
602
603(defun dired-remember-marks (beg end)
604 ;; Return alist of files and their marks, from BEG to END.
605 (if selective-display ; must unhide to make this work.
606 (let (buffer-read-only)
607 (subst-char-in-region beg end ?\r ?\n)))
608 (let (fil chr alist)
609 (save-excursion
610 (goto-char beg)
611 (while (re-search-forward dired-re-mark end t)
612 (if (setq fil (dired-get-filename nil t))
613 (setq chr (preceding-char)
614 alist (cons (cons fil chr) alist)))))
615 alist))
616
617;; Mark all files remembered in ALIST.
618;; Each element of ALIST looks like (FILE . MARKERCHAR).
619(defun dired-mark-remembered (alist)
620 (let (elt fil chr)
621 (while alist
622 (setq elt (car alist)
623 alist (cdr alist)
624 fil (car elt)
625 chr (cdr elt))
626 (if (dired-goto-file fil)
627 (save-excursion
628 (beginning-of-line)
629 (delete-char 1)
630 (insert chr))))))
631
632;; Return a list of names of subdirs currently hidden.
633(defun dired-remember-hidden ()
634 (let ((l dired-subdir-alist) dir pos result)
635 (while l
636 (setq dir (car (car l))
637 pos (cdr (car l))
638 l (cdr l))
639 (goto-char pos)
640 (skip-chars-forward "^\r\n")
52041219 641 (if (eq (following-char) ?\r)
492d2437
RS
642 (setq result (cons dir result))))
643 result))
644
645;; Try to insert all subdirs that were displayed before,
646;; according to the former subdir alist OLD-SUBDIR-ALIST.
647(defun dired-insert-old-subdirs (old-subdir-alist)
648 (or (string-match "R" dired-actual-switches)
649 (let (elt dir)
650 (while old-subdir-alist
651 (setq elt (car old-subdir-alist)
652 old-subdir-alist (cdr old-subdir-alist)
653 dir (car elt))
654 (condition-case ()
715984d3
RS
655 (progn
656 (dired-uncache dir)
657 (dired-insert-subdir dir))
492d2437 658 (error nil))))))
715984d3
RS
659
660;; Remove directory DIR from any directory cache.
661(defun dired-uncache (dir)
6eaebaa2 662 (let ((handler (find-file-name-handler dir 'dired-uncache)))
715984d3
RS
663 (if handler
664 (funcall handler 'dired-uncache dir))))
492d2437
RS
665\f
666;; dired mode key bindings and initialization
84fc2cfa
ER
667
668(defvar dired-mode-map nil "Local keymap for dired-mode buffers.")
669(if dired-mode-map
670 nil
492d2437
RS
671 ;; This looks ugly when substitute-command-keys uses C-d instead d:
672 ;; (define-key dired-mode-map "\C-d" 'dired-flag-file-deletion)
673
84fc2cfa
ER
674 (setq dired-mode-map (make-keymap))
675 (suppress-keymap dired-mode-map)
dbcb9389 676 (define-key dired-mode-map [mouse-2] 'dired-mouse-find-file-other-window)
492d2437 677 ;; Commands to mark or flag certain categories of files
84fc2cfa 678 (define-key dired-mode-map "#" 'dired-flag-auto-save-files)
492d2437 679 (define-key dired-mode-map "*" 'dired-mark-executables)
84fc2cfa 680 (define-key dired-mode-map "." 'dired-clean-directory)
492d2437
RS
681 (define-key dired-mode-map "/" 'dired-mark-directories)
682 (define-key dired-mode-map "@" 'dired-mark-symlinks)
683 (define-key dired-mode-map "~" 'dired-flag-backup-files)
6482fcac 684 ;; Upper case keys (except !) for operating on the marked files
492d2437
RS
685 (define-key dired-mode-map "C" 'dired-do-copy)
686 (define-key dired-mode-map "B" 'dired-do-byte-compile)
687 (define-key dired-mode-map "D" 'dired-do-delete)
688 (define-key dired-mode-map "G" 'dired-do-chgrp)
689 (define-key dired-mode-map "H" 'dired-do-hardlink)
690 (define-key dired-mode-map "L" 'dired-do-load)
691 (define-key dired-mode-map "M" 'dired-do-chmod)
692 (define-key dired-mode-map "O" 'dired-do-chown)
693 (define-key dired-mode-map "P" 'dired-do-print)
694 (define-key dired-mode-map "R" 'dired-do-rename)
695 (define-key dired-mode-map "S" 'dired-do-symlink)
696 (define-key dired-mode-map "X" 'dired-do-shell-command)
697 (define-key dired-mode-map "Z" 'dired-do-compress)
698 (define-key dired-mode-map "!" 'dired-do-shell-command)
699 ;; Comparison commands
700 (define-key dired-mode-map "=" 'dired-diff)
701 (define-key dired-mode-map "\M-=" 'dired-backup-diff)
702 ;; Tree Dired commands
703 (define-key dired-mode-map "\M-\C-?" 'dired-unmark-all-files)
704 (define-key dired-mode-map "\M-\C-d" 'dired-tree-down)
705 (define-key dired-mode-map "\M-\C-u" 'dired-tree-up)
706 (define-key dired-mode-map "\M-\C-n" 'dired-next-subdir)
707 (define-key dired-mode-map "\M-\C-p" 'dired-prev-subdir)
708 ;; move to marked files
709 (define-key dired-mode-map "\M-{" 'dired-prev-marked-file)
710 (define-key dired-mode-map "\M-}" 'dired-next-marked-file)
492d2437 711 ;; Make all regexp commands share a `%' prefix:
767151e1
RS
712 ;; We used to get to the submap via a symbol dired-regexp-prefix,
713 ;; but that seems to serve little purpose, and copy-keymap
714 ;; does a better job without it.
715 (define-key dired-mode-map "%" nil)
492d2437
RS
716 (define-key dired-mode-map "%u" 'dired-upcase)
717 (define-key dired-mode-map "%l" 'dired-downcase)
718 (define-key dired-mode-map "%d" 'dired-flag-files-regexp)
719 (define-key dired-mode-map "%m" 'dired-mark-files-regexp)
720 (define-key dired-mode-map "%r" 'dired-do-rename-regexp)
721 (define-key dired-mode-map "%C" 'dired-do-copy-regexp)
722 (define-key dired-mode-map "%H" 'dired-do-hardlink-regexp)
723 (define-key dired-mode-map "%R" 'dired-do-rename-regexp)
724 (define-key dired-mode-map "%S" 'dired-do-symlink-regexp)
725 ;; Lower keys for commands not operating on all the marked files
6482fcac 726 (define-key dired-mode-map "c" 'dired-change-marks)
492d2437
RS
727 (define-key dired-mode-map "d" 'dired-flag-file-deletion)
728 (define-key dired-mode-map "e" 'dired-find-file)
729 (define-key dired-mode-map "f" 'dired-advertised-find-file)
730 (define-key dired-mode-map "g" 'revert-buffer)
84fc2cfa 731 (define-key dired-mode-map "h" 'describe-mode)
492d2437 732 (define-key dired-mode-map "i" 'dired-maybe-insert-subdir)
6482fcac 733 (define-key dired-mode-map "k" 'dired-do-kill-lines)
492d2437
RS
734 (define-key dired-mode-map "l" 'dired-do-redisplay)
735 (define-key dired-mode-map "m" 'dired-mark)
736 (define-key dired-mode-map "n" 'dired-next-line)
737 (define-key dired-mode-map "o" 'dired-find-file-other-window)
ab67260b 738 (define-key dired-mode-map "\C-o" 'dired-display-file)
492d2437
RS
739 (define-key dired-mode-map "p" 'dired-previous-line)
740 (define-key dired-mode-map "q" 'dired-quit)
741 (define-key dired-mode-map "s" 'dired-sort-toggle-or-edit)
742 (define-key dired-mode-map "u" 'dired-unmark)
743 (define-key dired-mode-map "v" 'dired-view-file)
744 (define-key dired-mode-map "x" 'dired-do-flagged-delete)
745 (define-key dired-mode-map "+" 'dired-create-directory)
746 ;; moving
747 (define-key dired-mode-map "<" 'dired-prev-dirline)
748 (define-key dired-mode-map ">" 'dired-next-dirline)
749 (define-key dired-mode-map "^" 'dired-up-directory)
84fc2cfa
ER
750 (define-key dired-mode-map " " 'dired-next-line)
751 (define-key dired-mode-map "\C-n" 'dired-next-line)
752 (define-key dired-mode-map "\C-p" 'dired-previous-line)
492d2437
RS
753 ;; hiding
754 (define-key dired-mode-map "$" 'dired-hide-subdir)
755 (define-key dired-mode-map "\M-$" 'dired-hide-all)
756 ;; misc
757 (define-key dired-mode-map "?" 'dired-summary)
758 (define-key dired-mode-map "\177" 'dired-unmark-backward)
759 (define-key dired-mode-map "\C-_" 'dired-undo)
760 (define-key dired-mode-map "\C-xu" 'dired-undo)
761 )
492d2437 762\f
fc53efda
RS
763;; Make menu bar items.
764
765;; Get rid of the Edit menu bar item to save space.
766(define-key dired-mode-map [menu-bar edit] 'undefined)
767
768(define-key dired-mode-map [menu-bar subdir]
769 (cons "Subdir" (make-sparse-keymap "Subdir")))
770
771(define-key dired-mode-map [menu-bar subdir hide-all]
772 '("Hide All" . dired-hide-all))
773(define-key dired-mode-map [menu-bar subdir hide-subdir]
774 '("Hide Subdir" . dired-hide-subdir))
775(define-key dired-mode-map [menu-bar subdir tree-down]
776 '("Tree Down" . dired-tree-down))
777(define-key dired-mode-map [menu-bar subdir tree-up]
778 '("Tree Up" . dired-tree-up))
779(define-key dired-mode-map [menu-bar subdir up]
780 '("Up Directory" . dired-up-directory))
781(define-key dired-mode-map [menu-bar subdir prev-subdir]
782 '("Prev Subdir" . dired-prev-subdir))
783(define-key dired-mode-map [menu-bar subdir next-subdir]
784 '("Next Subdir" . dired-next-subdir))
785(define-key dired-mode-map [menu-bar subdir prev-dirline]
786 '("Prev Dirline" . dired-prev-dirline))
787(define-key dired-mode-map [menu-bar subdir next-dirline]
788 '("Next Dirline" . dired-next-dirline))
789(define-key dired-mode-map [menu-bar subdir insert]
790 '("Insert This Subdir" . dired-maybe-insert-subdir))
791
792(define-key dired-mode-map [menu-bar immediate]
793 (cons "Immediate" (make-sparse-keymap "Immediate")))
794
795(define-key dired-mode-map [menu-bar immediate backup-diff]
796 '("Compare with Backup" . dired-backup-diff))
797(define-key dired-mode-map [menu-bar immediate diff]
798 '("Diff" . dired-diff))
799(define-key dired-mode-map [menu-bar immediate view]
800 '("View This File" . dired-view-file))
801(define-key dired-mode-map [menu-bar immediate display]
802 '("Display in Other Window" . dired-display-file))
803(define-key dired-mode-map [menu-bar immediate find-file-other-window]
804 '("Find in Other Window" . dired-find-file-other-window))
805(define-key dired-mode-map [menu-bar immediate find-file]
806 '("Find This File" . dired-find-file))
807(define-key dired-mode-map [menu-bar immediate create-directory]
808 '("Create Directory..." . dired-create-directory))
809
810(define-key dired-mode-map [menu-bar regexp]
811 (cons "Regexp" (make-sparse-keymap "Regexp")))
812
813(define-key dired-mode-map [menu-bar regexp downcase]
814 '("Downcase" . dired-downcase))
815(define-key dired-mode-map [menu-bar regexp upcase]
816 '("Upcase" . dired-upcase))
817(define-key dired-mode-map [menu-bar regexp hardlink]
818 '("Hardlink..." . dired-do-hardlink-regexp))
819(define-key dired-mode-map [menu-bar regexp symlink]
820 '("Symlink..." . dired-do-symlink-regexp))
821(define-key dired-mode-map [menu-bar regexp rename]
822 '("Rename..." . dired-do-rename-regexp))
823(define-key dired-mode-map [menu-bar regexp copy]
824 '("Copy..." . dired-do-copy-regexp))
825(define-key dired-mode-map [menu-bar regexp flag]
826 '("Flag..." . dired-flag-files-regexp))
827(define-key dired-mode-map [menu-bar regexp mark]
828 '("Mark..." . dired-mark-files-regexp))
829
830(define-key dired-mode-map [menu-bar mark]
831 (cons "Mark" (make-sparse-keymap "Mark")))
832
833(define-key dired-mode-map [menu-bar mark prev]
834 '("Previous Marked" . dired-prev-marked-file))
835(define-key dired-mode-map [menu-bar mark next]
836 '("Next Marked" . dired-next-marked-file))
837(define-key dired-mode-map [menu-bar mark marks]
838 '("Change Marks..." . dired-change-marks))
b1ecd9c6
RS
839(define-key dired-mode-map [menu-bar mark unmark-all]
840 '("Unmark All" . dired-unmark-all-files-no-query))
fc53efda
RS
841(define-key dired-mode-map [menu-bar mark symlinks]
842 '("Mark Symlinks" . dired-mark-symlinks))
843(define-key dired-mode-map [menu-bar mark directories]
844 '("Mark Directories" . dired-mark-directories))
845(define-key dired-mode-map [menu-bar mark directory]
846 '("Mark Old Backups" . dired-clean-directory))
847(define-key dired-mode-map [menu-bar mark executables]
848 '("Mark Executables" . dired-mark-executables))
b1ecd9c6 849(define-key dired-mode-map [menu-bar mark backup-files]
fc53efda 850 '("Flag Backup Files" . dired-flag-backup-files))
b1ecd9c6 851(define-key dired-mode-map [menu-bar mark auto-save-files]
fc53efda
RS
852 '("Flag Auto-save Files" . dired-flag-auto-save-files))
853(define-key dired-mode-map [menu-bar mark deletion]
854 '("Flag" . dired-flag-file-deletion))
855(define-key dired-mode-map [menu-bar mark unmark]
856 '("Unmark" . dired-unmark))
857(define-key dired-mode-map [menu-bar mark mark]
858 '("Mark" . dired-mark))
859
860(define-key dired-mode-map [menu-bar operate]
861 (cons "Operate" (make-sparse-keymap "Operate")))
862
863(define-key dired-mode-map [menu-bar operate chown]
864 '("Change Owner..." . dired-do-chown))
865(define-key dired-mode-map [menu-bar operate chgrp]
866 '("Change Group..." . dired-do-chgrp))
867(define-key dired-mode-map [menu-bar operate chmod]
868 '("Change Mode..." . dired-do-chmod))
869(define-key dired-mode-map [menu-bar operate load]
870 '("Load" . dired-do-load))
871(define-key dired-mode-map [menu-bar operate compile]
872 '("Byte-compile" . dired-do-byte-compile))
873(define-key dired-mode-map [menu-bar operate compress]
874 '("Compress" . dired-do-compress))
875(define-key dired-mode-map [menu-bar operate print]
876 '("Print" . dired-do-print))
877(define-key dired-mode-map [menu-bar operate hardlink]
878 '("Hardlink to..." . dired-do-hardlink))
879(define-key dired-mode-map [menu-bar operate symlink]
880 '("Symlink to..." . dired-do-symlink))
881(define-key dired-mode-map [menu-bar operate command]
882 '("Shell Command..." . dired-do-shell-command))
883(define-key dired-mode-map [menu-bar operate delete]
884 '("Delete" . dired-do-delete))
885(define-key dired-mode-map [menu-bar operate rename]
886 '("Rename to..." . dired-do-rename))
887(define-key dired-mode-map [menu-bar operate copy]
888 '("Copy to..." . dired-do-copy))
889\f
84fc2cfa
ER
890;; Dired mode is suitable only for specially formatted data.
891(put 'dired-mode 'mode-class 'special)
892
492d2437
RS
893(defun dired-mode (&optional dirname switches)
894 "\
895Mode for \"editing\" directory listings.
896In dired, you are \"editing\" a list of the files in a directory and
897 \(optionally) its subdirectories, in the format of `ls -lR'.
898 Each directory is a page: use \\[backward-page] and \\[forward-page] to move pagewise.
899\"Editing\" means that you can run shell commands on files, visit,
900 compress, load or byte-compile them, change their file attributes
901 and insert subdirectories into the same buffer. You can \"mark\"
902 files for later commands or \"flag\" them for deletion, either file
903 by file or all files matching certain criteria.
904You can move using the usual cursor motion commands.\\<dired-mode-map>
905Letters no longer insert themselves. Digits are prefix arguments.
906Instead, type \\[dired-flag-file-deletion] to flag a file for Deletion.
907Type \\[dired-mark] to Mark a file or subdirectory for later commands.
908 Most commands operate on the marked files and use the current file
909 if no files are marked. Use a numeric prefix argument to operate on
910 the next ARG (or previous -ARG if ARG<0) files, or just `1'
911 to operate on the current file only. Prefix arguments override marks.
912 Mark-using commands display a list of failures afterwards. Type \\[dired-summary]
913 to see why something went wrong.
914Type \\[dired-unmark] to Unmark a file or all files of a subdirectory.
915Type \\[dired-unmark-backward] to back up one line and unflag.
916Type \\[dired-do-flagged-delete] to eXecute the deletions requested.
917Type \\[dired-advertised-find-file] to Find the current line's file
918 (or dired it in another buffer, if it is a directory).
919Type \\[dired-find-file-other-window] to find file or dired directory in Other window.
920Type \\[dired-maybe-insert-subdir] to Insert a subdirectory in this buffer.
921Type \\[dired-do-rename] to Rename a file or move the marked files to another directory.
922Type \\[dired-do-copy] to Copy files.
923Type \\[dired-sort-toggle-or-edit] to toggle sorting by name/date or change the `ls' switches.
924Type \\[revert-buffer] to read all currently expanded directories again.
925 This retains all marks and hides subdirs again that were hidden before.
926SPC and DEL can be used to move down and up by lines.
927
928If dired ever gets confused, you can either type \\[revert-buffer] \
929to read the
930directories again, type \\[dired-do-redisplay] \
931to relist a single or the marked files or a
932subdirectory, or type \\[dired-build-subdir-alist] to parse the buffer
933again for the directory tree.
934
935Customization variables (rename this buffer and type \\[describe-variable] on each line
936for more info):
937
938 dired-listing-switches
939 dired-trivial-filenames
940 dired-shrink-to-fit
941 dired-marker-char
942 dired-del-marker
943 dired-keep-marker-rename
944 dired-keep-marker-copy
945 dired-keep-marker-hardlink
946 dired-keep-marker-symlink
947
948Hooks (use \\[describe-variable] to see their documentation):
949
950 dired-before-readin-hook
951 dired-after-readin-hook
952 dired-mode-hook
953 dired-load-hook
954
955Keybindings:
84fc2cfa 956\\{dired-mode-map}"
492d2437
RS
957 ;; Not to be called interactively (e.g. dired-directory will be set
958 ;; to default-directory, which is wrong with wildcards).
84fc2cfa 959 (kill-all-local-variables)
84fc2cfa 960 (use-local-map dired-mode-map)
492d2437
RS
961 (dired-advertise) ; default-directory is already set
962 (setq major-mode 'dired-mode
963 mode-name "Dired"
3222085e 964;; case-fold-search nil
492d2437
RS
965 buffer-read-only t
966 selective-display t ; for subdirectory hiding
967 mode-line-buffer-identification '("Dired: %17b"))
968 (set (make-local-variable 'revert-buffer-function)
969 (function dired-revert))
970 (set (make-local-variable 'page-delimiter)
971 "\n\n")
972 (set (make-local-variable 'dired-directory)
973 (or dirname default-directory))
974 ;; list-buffers uses this to display the dir being edited in this buffer.
975 (set (make-local-variable 'list-buffers-directory)
976 dired-directory)
977 (set (make-local-variable 'dired-actual-switches)
978 (or switches dired-listing-switches))
492d2437 979 (dired-sort-other dired-actual-switches t)
84fc2cfa
ER
980 (run-hooks 'dired-mode-hook))
981\f
eb8c3be9 982;; Idiosyncratic dired commands that don't deal with marks.
84fc2cfa 983
492d2437
RS
984(defun dired-quit ()
985 "Bury the current dired buffer."
986 (interactive)
987 (bury-buffer))
84fc2cfa
ER
988
989(defun dired-summary ()
492d2437 990 "Summarize basic Dired commands and show recent Dired errors."
84fc2cfa 991 (interactive)
492d2437 992 (dired-why)
84fc2cfa
ER
993 ;>> this should check the key-bindings and use substitute-command-keys if non-standard
994 (message
50f74744 995 "d-elete, u-ndelete, x-punge, f-ind, o-ther window, R-ename, C-opy, h-elp"))
84fc2cfa 996
492d2437
RS
997(defun dired-undo ()
998 "Undo in a dired buffer.
999This doesn't recover lost files, it just undoes changes in the buffer itself.
1000You can use it to recover marks, killed lines or subdirs.
1001In the latter case, you have to do \\[dired-build-subdir-alist] to
1002parse the buffer again."
1003 (interactive)
1004 (let (buffer-read-only)
1005 (undo)))
84fc2cfa
ER
1006
1007(defun dired-next-line (arg)
1008 "Move down lines then position at filename.
1009Optional prefix ARG says how many lines to move; default is one line."
1010 (interactive "p")
1011 (next-line arg)
1012 (dired-move-to-filename))
1013
1014(defun dired-previous-line (arg)
1015 "Move up lines then position at filename.
1016Optional prefix ARG says how many lines to move; default is one line."
1017 (interactive "p")
1018 (previous-line arg)
1019 (dired-move-to-filename))
1020
492d2437
RS
1021(defun dired-next-dirline (arg &optional opoint)
1022 "Goto ARG'th next directory file line."
1023 (interactive "p")
1024 (or opoint (setq opoint (point)))
1025 (if (if (> arg 0)
1026 (re-search-forward dired-re-dir nil t arg)
1027 (beginning-of-line)
1028 (re-search-backward dired-re-dir nil t (- arg)))
1029 (dired-move-to-filename) ; user may type `i' or `f'
1030 (goto-char opoint)
1031 (error "No more subdirectories")))
1032
1033(defun dired-prev-dirline (arg)
1034 "Goto ARG'th previous directory file line."
1035 (interactive "p")
1036 (dired-next-dirline (- arg)))
1037
84fc2cfa 1038(defun dired-up-directory ()
492d2437
RS
1039 "Run dired on parent directory of current directory.
1040Find the parent directory either in this buffer or another buffer.
1041Creates a buffer if necessary."
84fc2cfa 1042 (interactive)
492d2437
RS
1043 (let* ((dir (dired-current-directory))
1044 (up (file-name-directory (directory-file-name dir))))
1045 (or (dired-goto-file (directory-file-name dir))
7b2469ae
RS
1046 ;; Only try dired-goto-subdir if buffer has more than one dir.
1047 (and (cdr dired-subdir-alist)
492d2437
RS
1048 (dired-goto-subdir up))
1049 (progn
8d23c16b
ER
1050 (dired
1051up)
492d2437 1052 (dired-goto-file dir)))))
84fc2cfa 1053
dbcb9389
RS
1054;; Force `f' rather than `e' in the mode doc:
1055(defalias 'dired-advertised-find-file 'dired-find-file)
84fc2cfa
ER
1056(defun dired-find-file ()
1057 "In dired, visit the file or directory named on this line."
1058 (interactive)
c3554e95 1059 (find-file (file-name-sans-versions (dired-get-filename) t)))
84fc2cfa 1060
dbcb9389
RS
1061(defun dired-mouse-find-file-other-window (event)
1062 "In dired, visit the file or directory name you click on."
1063 (interactive "e")
1064 (let (file)
1065 (save-excursion
1066 (set-buffer (window-buffer (posn-window (event-end event))))
1067 (save-excursion
1068 (goto-char (posn-point (event-end event)))
1069 (setq file (dired-get-filename))))
1070 (select-window (posn-window (event-end event)))
1071 (find-file-other-window (file-name-sans-versions file t))))
1072
84fc2cfa 1073(defun dired-view-file ()
492d2437
RS
1074 "In dired, examine a file in view mode, returning to dired when done.
1075When file is a directory, show it in this buffer if it is inserted;
1076otherwise, display it in another buffer."
84fc2cfa
ER
1077 (interactive)
1078 (if (file-directory-p (dired-get-filename))
7b2469ae
RS
1079 (or (and (cdr dired-subdir-alist)
1080 (dired-goto-subdir (dired-get-filename)))
492d2437 1081 (dired (dired-get-filename)))
715984d3 1082 (view-file (dired-get-filename))))
84fc2cfa
ER
1083
1084(defun dired-find-file-other-window ()
1085 "In dired, visit this file or directory in another window."
1086 (interactive)
c3554e95 1087 (find-file-other-window (file-name-sans-versions (dired-get-filename) t)))
ab67260b
RS
1088
1089(defun dired-display-file ()
1090 "In dired, display this file or directory in another window."
1091 (interactive)
c3554e95
RS
1092 (let ((file (file-name-sans-versions (dired-get-filename) t)))
1093 (display-buffer (find-file-noselect file))))
492d2437
RS
1094\f
1095;;; Functions for extracting and manipulating file names in dired buffers.
84fc2cfa
ER
1096
1097(defun dired-get-filename (&optional localp no-error-if-not-filep)
1098 "In dired, return name of file mentioned on this line.
1099Value returned normally includes the directory name.
492d2437
RS
1100Optional arg LOCALP with value `no-dir' means don't include directory
1101 name in result. A value of t means construct name relative to
1102 `default-directory', which still may contain slashes if in a subdirectory.
1103Optional arg NO-ERROR-IF-NOT-FILEP means return nil if no filename on
1104 this line, otherwise an error occurs."
1105 (let (case-fold-search file p1 p2)
84fc2cfa 1106 (save-excursion
492d2437
RS
1107 (if (setq p1 (dired-move-to-filename (not no-error-if-not-filep)))
1108 (setq p2 (dired-move-to-end-of-filename no-error-if-not-filep))))
1109 ;; nil if no file on this line, but no-error-if-not-filep is t:
db07847f 1110 (if (setq file (and p1 p2 (format "%s" (buffer-substring p1 p2))))
492d2437
RS
1111 ;; Check if ls quoted the names, and unquote them.
1112 ;; Using read to unquote is much faster than substituting
1113 ;; \007 (4 chars) -> ^G (1 char) etc. in a lisp loop.
1114 (cond ((string-match "b" dired-actual-switches) ; System V ls
1115 ;; This case is about 20% slower than without -b.
1116 (setq file
1117 (read
1118 (concat "\""
1119 ;; some ls -b don't escape quotes, argh!
1120 ;; This is not needed for GNU ls, though.
1121 (or (dired-string-replace-match
1122 "\\([^\\]\\)\"" file "\\1\\\\\"")
1123 file)
1124 "\""))))
1125 ;; If you do this, update dired-insert-subdir-validate too
1126 ;; ((string-match "Q" dired-actual-switches) ; GNU ls
1127 ;; (setq file (read file)))
1128 ))
1129 (if (eq localp 'no-dir)
1130 file
1131 (and file (concat (dired-current-directory localp) file)))))
1132
1133(defun dired-make-absolute (file &optional dir)
1134 ;;"Convert FILE (a pathname relative to DIR) to an absolute pathname."
1135 ;; We can't always use expand-file-name as this would get rid of `.'
1136 ;; or expand in / instead default-directory if DIR=="".
1137 ;; This should be good enough for ange-ftp, but might easily be
1138 ;; redefined (for VMS?).
1139 ;; It should be reasonably fast, though, as it is called in
1140 ;; dired-get-filename.
1141 (concat (or dir default-directory) file))
1142
1143(defun dired-make-relative (file &optional dir no-error)
1144 ;;"Convert FILE (an absolute pathname) to a pathname relative to DIR.
1145 ;; Else error (unless NO-ERROR is non-nil, then FILE is returned unchanged)
1146 ;;DIR defaults to default-directory."
1147 ;; DIR must be file-name-as-directory, as with all directory args in
52041219 1148 ;; Emacs Lisp code.
492d2437 1149 (or dir (setq dir default-directory))
7425bbff
RS
1150 ;; This case comes into play if default-directory is set to
1151 ;; use ~.
1152 (if (and (> (length dir) 0) (= (aref dir 0) ?~))
1153 (setq dir (expand-file-name dir)))
492d2437
RS
1154 (if (string-match (concat "^" (regexp-quote dir)) file)
1155 (substring file (match-end 0))
1156 (if no-error
1157 file
1158 (error "%s: not in directory tree growing at %s" file dir))))
1159\f
1160;;; Functions for finding the file name in a dired buffer line.
1161
c4a7b2a4 1162(defvar dired-move-to-filename-regexp
d90490d8 1163 "\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|Jul\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\)[ ]+[0-9]+ [ 0-9][0-9][:0-9][0-9][ 0-9] "
c4a7b2a4
RS
1164 "Regular expression to match a month abbreviation followed by a number.")
1165
492d2437
RS
1166;; Move to first char of filename on this line.
1167;; Returns position (point) or nil if no filename on this line."
1168(defun dired-move-to-filename (&optional raise-error eol)
1169 ;; This is the UNIX version.
1170 (or eol (setq eol (progn (end-of-line) (point))))
1171 (beginning-of-line)
d90490d8
RS
1172 (if (re-search-forward dired-move-to-filename-regexp eol t)
1173 (goto-char (match-end 0))
1174 (if raise-error
1175 (error "No file on this line"))))
492d2437
RS
1176
1177(defun dired-move-to-end-of-filename (&optional no-error)
1178 ;; Assumes point is at beginning of filename,
1179 ;; thus the rwx bit re-search-backward below will succeed in *this*
1180 ;; line if at all. So, it should be called only after
1181 ;; (dired-move-to-filename t).
1182 ;; On failure, signals an error (with non-nil NO-ERROR just returns nil).
1183 ;; This is the UNIX version.
1184 (let (opoint file-type executable symlink hidden case-fold-search used-F eol)
1185 ;; case-fold-search is nil now, so we can test for capital F:
1186 (setq used-F (string-match "F" dired-actual-switches)
1187 opoint (point)
1188 eol (save-excursion (end-of-line) (point))
1189 hidden (and selective-display
1190 (save-excursion (search-forward "\r" eol t))))
1191 (if hidden
1192 nil
1193 (save-excursion;; Find out what kind of file this is:
1194 ;; Restrict perm bits to be non-blank,
1195 ;; otherwise this matches one char to early (looking backward):
1196 ;; "l---------" (some systems make symlinks that way)
1197 ;; "----------" (plain file with zero perms)
1198 (if (re-search-backward
1199 "\\([^ ]\\)[-r][-w]\\([^ ]\\)[-r][-w]\\([^ ]\\)[-r][-w]\\([^ ]\\)"
1200 nil t)
1201 (setq file-type (char-after (match-beginning 1))
1202 symlink (eq file-type ?l)
1203 ;; Only with -F we need to know whether it's an executable
1204 executable (and
1205 used-F
1206 (string-match
1207 "[xst]";; execute bit set anywhere?
1208 (concat
1209 (buffer-substring (match-beginning 2)
1210 (match-end 2))
1211 (buffer-substring (match-beginning 3)
1212 (match-end 3))
1213 (buffer-substring (match-beginning 4)
1214 (match-end 4))))))
1215 (or no-error (error "No file on this line"))))
1216 ;; Move point to end of name:
1217 (if symlink
1218 (if (search-forward " ->" eol t)
1219 (progn
1220 (forward-char -3)
1221 (and used-F
1222 dired-ls-F-marks-symlinks
1223 (eq (preceding-char) ?@);; did ls really mark the link?
1224 (forward-char -1))))
1225 (goto-char eol);; else not a symbolic link
1226 ;; ls -lF marks dirs, sockets and executables with exactly one
1227 ;; trailing character. (Executable bits on symlinks ain't mean
1228 ;; a thing, even to ls, but we know it's not a symlink.)
1229 (and used-F
1230 (or (memq file-type '(?d ?s))
1231 executable)
1232 (forward-char -1))))
1233 (or no-error
1234 (not (eq opoint (point)))
1235 (error (if hidden
1236 (substitute-command-keys
1237 "File line is hidden, type \\[dired-hide-subdir] to unhide")
1238 "No file on this line")))
1239 (if (eq opoint (point))
1240 nil
1241 (point))))
1242
1243\f
1244;; Keeping Dired buffers in sync with the filesystem and with each other
1245
1246(defvar dired-buffers nil
1247 ;; Enlarged by dired-advertise
1248 ;; Queried by function dired-buffers-for-dir. When this detects a
1249 ;; killed buffer, it is removed from this list.
1250 "Alist of directories and their associated dired buffers.")
1251
1252(defun dired-buffers-for-dir (dir)
1253;; Return a list of buffers that dired DIR (top level or in-situ subdir).
1254;; The list is in reverse order of buffer creation, most recent last.
1255;; As a side effect, killed dired buffers for DIR are removed from
1256;; dired-buffers.
1257 (setq dir (file-name-as-directory dir))
1258 (let ((alist dired-buffers) result elt)
1259 (while alist
1260 (setq elt (car alist))
1261 (if (dired-in-this-tree dir (car elt))
1262 (let ((buf (cdr elt)))
1263 (if (buffer-name buf)
1264 (if (assoc dir (save-excursion
1265 (set-buffer buf)
1266 dired-subdir-alist))
1267 (setq result (cons buf result)))
1268 ;; else buffer is killed - clean up:
1269 (setq dired-buffers (delq elt dired-buffers)))))
1270 (setq alist (cdr alist)))
1271 result))
1272
1273(defun dired-advertise ()
1274 ;;"Advertise in variable `dired-buffers' that we dired `default-directory'."
1275 ;; With wildcards we actually advertise too much.
1276 (if (memq (current-buffer) (dired-buffers-for-dir default-directory))
1277 t ; we have already advertised ourselves
1278 (setq dired-buffers
1279 (cons (cons default-directory (current-buffer))
1280 dired-buffers))))
1281
1282(defun dired-unadvertise (dir)
1283 ;; Remove DIR from the buffer alist in variable dired-buffers.
1284 ;; This has the effect of removing any buffer whose main directory is DIR.
1285 ;; It does not affect buffers in which DIR is a subdir.
1286 ;; Removing is also done as a side-effect in dired-buffer-for-dir.
1287 (setq dired-buffers
1288 (delq (assoc dir dired-buffers) dired-buffers)))
1289\f
1290;; Tree Dired
1291
1292;;; utility functions
1293
1294(defun dired-in-this-tree (file dir)
1295 ;;"Is FILE part of the directory tree starting at DIR?"
1296 (let (case-fold-search)
233993a3 1297 (string-match (concat "^" (regexp-quote (expand-file-name dir))) file)))
492d2437
RS
1298
1299(defun dired-normalize-subdir (dir)
1300 ;; Prepend default-directory to DIR if relative path name.
1301 ;; dired-get-filename must be able to make a valid filename from a
1302 ;; file and its directory DIR.
1303 (file-name-as-directory
1304 (if (file-name-absolute-p dir)
1305 dir
1306 (expand-file-name dir default-directory))))
1307
1308(defun dired-get-subdir ()
1309 ;;"Return the subdir name on this line, or nil if not on a headerline."
1310 ;; Look up in the alist whether this is a headerline.
1311 (save-excursion
1312 (let ((cur-dir (dired-current-directory)))
1313 (beginning-of-line) ; alist stores b-o-l positions
1314 (and (zerop (- (point)
1315 (dired-get-subdir-min (assoc cur-dir
1316 dired-subdir-alist))))
1317 cur-dir))))
1318
1319;(defun dired-get-subdir-min (elt)
1320; (cdr elt))
1321;; can't use macro, must be redefinable for other alist format in dired-nstd.
62f61df0 1322(defalias 'dired-get-subdir-min 'cdr)
492d2437
RS
1323
1324(defun dired-get-subdir-max (elt)
84fc2cfa 1325 (save-excursion
492d2437
RS
1326 (goto-char (dired-get-subdir-min elt))
1327 (dired-subdir-max)))
1328
1329(defun dired-clear-alist ()
1330 (while dired-subdir-alist
1331 (set-marker (dired-get-subdir-min (car dired-subdir-alist)) nil)
1332 (setq dired-subdir-alist (cdr dired-subdir-alist))))
1333
c9d59fc2
RS
1334(defun dired-subdir-index (dir)
1335 ;; Return an index into alist for use with nth
1336 ;; for the sake of subdir moving commands.
1337 (let (found (index 0) (alist dired-subdir-alist))
1338 (while alist
1339 (if (string= dir (car (car alist)))
1340 (setq alist nil found t)
1341 (setq alist (cdr alist) index (1+ index))))
1342 (if found index nil)))
1343
1344(defun dired-next-subdir (arg &optional no-error-if-not-found no-skip)
1345 "Go to next subdirectory, regardless of level."
1346 ;; Use 0 arg to go to this directory's header line.
1347 ;; NO-SKIP prevents moving to end of header line, returning whatever
1348 ;; position was found in dired-subdir-alist.
1349 (interactive "p")
1350 (let ((this-dir (dired-current-directory))
1351 pos index)
1352 ;; nth with negative arg does not return nil but the first element
1353 (setq index (- (dired-subdir-index this-dir) arg))
1354 (setq pos (if (>= index 0)
1355 (dired-get-subdir-min (nth index dired-subdir-alist))))
1356 (if pos
1357 (progn
1358 (goto-char pos)
1359 (or no-skip (skip-chars-forward "^\n\r"))
1360 (point))
1361 (if no-error-if-not-found
1362 nil ; return nil if not found
1363 (error "%s directory" (if (> arg 0) "Last" "First"))))))
1364
492d2437
RS
1365(defun dired-build-subdir-alist ()
1366 "Build `dired-subdir-alist' by parsing the buffer.
1367Returns the new value of the alist."
1368 (interactive)
1369 (dired-clear-alist)
1370 (save-excursion
3222085e
BF
1371 (let ((count 0)
1372 (buffer-read-only nil)
1373 new-dir-name)
84fc2cfa 1374 (goto-char (point-min))
492d2437 1375 (setq dired-subdir-alist nil)
acf310c9
RS
1376 (while (and (re-search-forward dired-subdir-regexp nil t)
1377 ;; Avoid taking a file name ending in a colon
1378 ;; as a subdir name.
1379 (not (save-excursion
1380 (goto-char (match-beginning 0))
1381 (beginning-of-line)
1382 (forward-char 2)
46680faf 1383 (save-match-data (looking-at dired-re-perms)))))
3222085e
BF
1384 (save-excursion
1385 (goto-char (match-beginning 1))
1386 (setq new-dir-name
1387 (expand-file-name (buffer-substring (point) (match-end 1))))
1388 (delete-region (point) (match-end 1))
1389 (insert new-dir-name))
492d2437 1390 (setq count (1+ count))
3222085e
BF
1391 (dired-alist-add-1 new-dir-name
1392 ;; Place a sub directory boundary between lines.
1393 (save-excursion
1394 (goto-char (match-beginning 0))
1395 (beginning-of-line)
1396 (point-marker))))
c9d59fc2
RS
1397 (if (> count 1)
1398 (message "Buffer includes %d directories" count))
492d2437
RS
1399 ;; We don't need to sort it because it is in buffer order per
1400 ;; constructionem. Return new alist:
1401 dired-subdir-alist)))
1402
1403(defun dired-alist-add-1 (dir new-marker)
1404 ;; Add new DIR at NEW-MARKER. Don't sort.
1405 (setq dired-subdir-alist
1406 (cons (cons (dired-normalize-subdir dir) new-marker)
1407 dired-subdir-alist)))
1408
1409(defun dired-goto-next-nontrivial-file ()
1410 ;; Position point on first nontrivial file after point.
1411 (dired-goto-next-file);; so there is a file to compare with
1412 (if (stringp dired-trivial-filenames)
1413 (while (and (not (eobp))
1414 (string-match dired-trivial-filenames
1415 (file-name-nondirectory
1416 (or (dired-get-filename nil t) ""))))
1417 (forward-line 1)
1418 (dired-move-to-filename))))
1419
1420(defun dired-goto-next-file ()
1421 (let ((max (1- (dired-subdir-max))))
1422 (while (and (not (dired-move-to-filename)) (< (point) max))
1423 (forward-line 1))))
1424
1425(defun dired-goto-file (file)
1426 "Go to file line of FILE in this dired buffer."
1427 ;; Return value of point on success, else nil.
1428 ;; FILE must be an absolute pathname.
1429 ;; Loses if FILE contains control chars like "\007" for which ls
1430 ;; either inserts "?" or "\\007" into the buffer, so we won't find
1431 ;; it in the buffer.
1432 (interactive
1433 (prog1 ; let push-mark display its message
1434 (list (expand-file-name
1435 (read-file-name "Goto file: "
1436 (dired-current-directory))))
1437 (push-mark)))
1438 (setq file (directory-file-name file)) ; does no harm if no directory
1439 (let (found case-fold-search dir)
1440 (setq dir (or (file-name-directory file)
1441 (error "Need absolute pathname for %s" file)))
1442 (save-excursion
1443 ;; The hair here is to get the result of dired-goto-subdir
1444 ;; without really calling it if we don't have any subdirs.
233993a3 1445 (if (if (string= dir (expand-file-name default-directory))
492d2437 1446 (goto-char (point-min))
7b2469ae 1447 (and (cdr dired-subdir-alist)
492d2437
RS
1448 (dired-goto-subdir dir)))
1449 (let ((base (file-name-nondirectory file))
1450 (boundary (dired-subdir-max)))
1451 (while (and (not found)
1452 ;; filenames are preceded by SPC, this makes
1453 ;; the search faster (e.g. for the filename "-"!).
1454 (search-forward (concat " " base) boundary 'move))
1455 ;; Match could have BASE just as initial substring or
1456 ;; or in permission bits or date or
1457 ;; not be a proper filename at all:
1458 (if (equal base (dired-get-filename 'no-dir t))
1459 ;; Must move to filename since an (actually
1460 ;; correct) match could have been elsewhere on the
1461 ;; ;; line (e.g. "-" would match somewhere in the
1462 ;; permission bits).
55e86af6
RS
1463 (setq found (dired-move-to-filename))
1464 ;; If this isn't the right line, move forward to avoid
1465 ;; trying this line again.
1466 (forward-line 1))))))
492d2437
RS
1467 (and found
1468 ;; return value of point (i.e., FOUND):
1469 (goto-char found))))
1470
1471(defun dired-initial-position (dirname)
1472 ;; Where point should go in a new listing of DIRNAME.
1473 ;; Point assumed at beginning of new subdir line.
1474 ;; You may redefine this function as you wish, e.g. like in dired-x.el.
1475 (end-of-line)
1476 (if dired-trivial-filenames (dired-goto-next-nontrivial-file)))
1477\f
1478;; These are hooks which make tree dired work.
1479;; They are in this file because other parts of dired need to call them.
1480;; But they don't call the rest of tree dired unless there are subdirs loaded.
1481
1482;; This function is called for each retrieved filename.
1483;; It could stand to be faster, though it's mostly function call
1484;; overhead. Avoiding the function call seems to save about 10% in
1485;; dired-get-filename. Make it a defsubst?
1486(defun dired-current-directory (&optional localp)
1487 "Return the name of the subdirectory to which this line belongs.
1488This returns a string with trailing slash, like `default-directory'.
1489Optional argument means return a file name relative to `default-directory'."
1490 (let ((here (point))
1491 (alist (or dired-subdir-alist
1492 ;; probably because called in a non-dired buffer
1493 (error "No subdir-alist in %s" (current-buffer))))
1494 elt dir)
1495 (while alist
1496 (setq elt (car alist)
1497 dir (car elt)
1498 ;; use `<=' (not `<') as subdir line is part of subdir
1499 alist (if (<= (dired-get-subdir-min elt) here)
1500 nil ; found
1501 (cdr alist))))
1502 (if localp
1503 (dired-make-relative dir default-directory)
1504 dir)))
1505
1506;; Subdirs start at the beginning of their header lines and end just
1507;; before the beginning of the next header line (or end of buffer).
1508
1509(defun dired-subdir-max ()
1510 (save-excursion
7b2469ae 1511 (if (or (null (cdr dired-subdir-alist)) (not (dired-next-subdir 1 t t)))
492d2437
RS
1512 (point-max)
1513 (point))))
1514\f
1515;; Deleting files
1516
1517(defun dired-do-flagged-delete ()
1518 "In dired, delete the files flagged for deletion."
1519 (interactive)
1520 (let* ((dired-marker-char dired-del-marker)
1521 (regexp (dired-marker-regexp))
1522 case-fold-search)
1523 (if (save-excursion (goto-char (point-min))
1524 (re-search-forward regexp nil t))
1525 (dired-internal-do-deletions
1526 ;; this can't move point since ARG is nil
1527 (dired-map-over-marks (cons (dired-get-filename) (point))
1528 nil)
1529 nil)
1530 (message "(No deletions requested)"))))
1531
1532(defun dired-do-delete (&optional arg)
1533 "Delete all marked (or next ARG) files."
1534 ;; This is more consistent with the file marking feature than
1535 ;; dired-do-flagged-delete.
1536 (interactive "P")
1537 (dired-internal-do-deletions
1538 ;; this may move point if ARG is an integer
1539 (dired-map-over-marks (cons (dired-get-filename) (point))
1540 arg)
1541 arg))
1542
1543(defvar dired-deletion-confirmer 'yes-or-no-p) ; or y-or-n-p?
1544
1545(defun dired-internal-do-deletions (l arg)
1546 ;; L is an alist of files to delete, with their buffer positions.
1547 ;; ARG is the prefix arg.
1548 ;; Filenames are absolute (VMS needs this for logical search paths).
1549 ;; (car L) *must* be the *last* (bottommost) file in the dired buffer.
1550 ;; That way as changes are made in the buffer they do not shift the
1551 ;; lines still to be changed, so the (point) values in L stay valid.
1552 ;; Also, for subdirs in natural order, a subdir's files are deleted
1553 ;; before the subdir itself - the other way around would not work.
1554 (let ((files (mapcar (function car) l))
1555 (count (length l))
1556 (succ 0))
1557 ;; canonicalize file list for pop up
1558 (setq files (nreverse (mapcar (function dired-make-relative) files)))
1559 (if (dired-mark-pop-up
1560 " *Deletions*" 'delete files dired-deletion-confirmer
1561 (format "Delete %s " (dired-mark-prompt arg files)))
84fc2cfa 1562 (save-excursion
492d2437
RS
1563 (let (failures);; files better be in reverse order for this loop!
1564 (while l
1565 (goto-char (cdr (car l)))
1566 (let (buffer-read-only)
1567 (condition-case err
1568 (let ((fn (car (car l))))
1569 ;; This test is equivalent to
1570 ;; (and (file-directory-p fn) (not (file-symlink-p fn)))
1571 ;; but more efficient
1572 (if (eq t (car (file-attributes fn)))
ab67260b 1573 (delete-directory fn)
492d2437
RS
1574 (delete-file fn))
1575 ;; if we get here, removing worked
1576 (setq succ (1+ succ))
1577 (message "%s of %s deletions" succ count)
1578 (delete-region (progn (beginning-of-line) (point))
1579 (progn (forward-line 1) (point)))
1580 (dired-clean-up-after-deletion fn))
1581 (error;; catch errors from failed deletions
1582 (dired-log "%s\n" err)
1583 (setq failures (cons (car (car l)) failures)))))
1584 (setq l (cdr l)))
1585 (if (not failures)
1586 (message "%d deletion%s done" count (dired-plural-s count))
1587 (dired-log-summary
1588 (format "%d of %d deletion%s failed"
1589 (length failures) count
1590 (dired-plural-s count))
1591 failures))))
1592 (message "(No deletions performed)")))
1593 (dired-move-to-filename))
1594
1595;; This is a separate function for the sake of dired-x.el.
1596(defun dired-clean-up-after-deletion (fn)
1597 ;; Clean up after a deleted file or directory FN.
7b2469ae
RS
1598 (save-excursion (and (cdr dired-subdir-alist)
1599 (dired-goto-subdir fn)
492d2437
RS
1600 (dired-kill-subdir))))
1601\f
1602;; Confirmation
1603
1604(defun dired-marker-regexp ()
1605 (concat "^" (regexp-quote (char-to-string dired-marker-char))))
1606
1607(defun dired-plural-s (count)
1608 (if (= 1 count) "" "s"))
1609
1610(defun dired-mark-prompt (arg files)
1611 ;; Return a string for use in a prompt, either the current file
1612 ;; name, or the marker and a count of marked files.
1613 (let ((count (length files)))
1614 (if (= count 1)
1615 (car files)
1616 ;; more than 1 file:
1617 (if (integerp arg)
1618 ;; abs(arg) = count
1619 ;; Perhaps this is nicer, but it also takes more screen space:
1620 ;;(format "[%s %d files]" (if (> arg 0) "next" "previous")
1621 ;; count)
1622 (format "[next %d files]" arg)
1623 (format "%c [%d files]" dired-marker-char count)))))
1624
1625(defun dired-pop-to-buffer (buf)
1626 ;; Pop up buffer BUF.
1627 ;; If dired-shrink-to-fit is t, make its window fit its contents.
1628 (if (not dired-shrink-to-fit)
1629 (pop-to-buffer (get-buffer-create buf))
1630 ;; let window shrink to fit:
1631 (let ((window (selected-window))
1632 target-lines w2)
1633 (cond ;; if split-window-threshold is enabled, use the largest window
1634 ((and (> (window-height (setq w2 (get-largest-window)))
1635 split-height-threshold)
f98955ea 1636 (= (frame-width) (window-width w2)))
492d2437
RS
1637 (setq window w2))
1638 ;; if the least-recently-used window is big enough, use it
1639 ((and (> (window-height (setq w2 (get-lru-window)))
1640 (* 2 window-min-height))
f98955ea 1641 (= (frame-width) (window-width w2)))
492d2437
RS
1642 (setq window w2)))
1643 (save-excursion
1644 (set-buffer buf)
1645 (goto-char (point-max))
1646 (skip-chars-backward "\n\r\t ")
63ea14a5
RS
1647 (setq target-lines (count-lines (point-min) (point)))
1648 ;; Don't forget to count the last line.
1649 (if (not (bolp))
1650 (setq target-lines (1+ target-lines))))
492d2437 1651 (if (<= (window-height window) (* 2 window-min-height))
f98955ea 1652 ;; At this point, every window on the frame is too small to split.
492d2437
RS
1653 (setq w2 (display-buffer buf))
1654 (setq w2 (split-window window
1655 (max window-min-height
1656 (- (window-height window)
1657 (1+ (max window-min-height target-lines)))))))
1658 (set-window-buffer w2 buf)
1659 (if (< (1- (window-height w2)) target-lines)
1660 (progn
1661 (select-window w2)
1662 (enlarge-window (- target-lines (1- (window-height w2))))))
1663 (set-window-start w2 1)
1664 )))
1665
1666(defvar dired-no-confirm nil
1667;; "If non-nil, list of symbols for commands dired should not confirm.
1668;;It can be a sublist of
1669;;
1670;; '(byte-compile chgrp chmod chown compress copy delete hardlink load
1671;; move print shell symlink uncompress)"
1672 )
1673
1674(defun dired-mark-pop-up (bufname op-symbol files function &rest args)
1675 ;;"Args BUFNAME OP-SYMBOL FILES FUNCTION &rest ARGS.
1676 ;;Return FUNCTION's result on ARGS after popping up a window (in a buffer
1677 ;;named BUFNAME, nil gives \" *Marked Files*\") showing the marked
1678 ;;files. Uses function `dired-pop-to-buffer' to do that.
1679 ;; FUNCTION should not manipulate files.
1680 ;; It should only read input (an argument or confirmation).
1681 ;;The window is not shown if there is just one file or
1682 ;; OP-SYMBOL is a member of the list in `dired-no-confirm'.
1683 ;;FILES is the list of marked files."
1684 (or bufname (setq bufname " *Marked Files*"))
1685 (if (or (memq op-symbol dired-no-confirm)
1686 (= (length files) 1))
1687 (apply function args)
1688 (save-excursion
1689 (set-buffer (get-buffer-create bufname))
1690 (erase-buffer)
a07e7c4a
RS
1691 (dired-format-columns-of-files files)
1692 (remove-text-properties (point-min) (point-max) '(mouse-face)))
492d2437
RS
1693 (save-window-excursion
1694 (dired-pop-to-buffer bufname)
1695 (apply function args))))
1696
1697(defun dired-format-columns-of-files (files)
1698 ;; Files should be in forward order for this loop.
1699 ;; i.e., (car files) = first file in buffer.
1700 ;; Returns the number of lines used.
1701 (let* ((maxlen (+ 2 (apply 'max (mapcar 'length files))))
1702 (width (- (window-width (selected-window)) 2))
1703 (columns (max 1 (/ width maxlen)))
1704 (nfiles (length files))
1705 (rows (+ (/ nfiles columns)
1706 (if (zerop (% nfiles columns)) 0 1)))
1707 (i 0)
1708 (j 0))
1709 (setq files (nconc (copy-sequence files) ; fill up with empty fns
1710 (make-list (- (* columns rows) nfiles) "")))
1711 (setcdr (nthcdr (1- (length files)) files) files) ; make circular
1712 (while (< j rows)
1713 (while (< i columns)
1714 (indent-to (* i maxlen))
1715 (insert (car files))
1716 (setq files (nthcdr rows files)
1717 i (1+ i)))
1718 (insert "\n")
1719 (setq i 0
1720 j (1+ j)
1721 files (cdr files)))
1722 rows))
1723\f
1724;; Commands to mark or flag file(s) at or near current line.
1725
1726(defun dired-repeat-over-lines (arg function)
1727 ;; This version skips non-file lines.
cfe89c4f 1728 (let ((pos (make-marker)))
492d2437 1729 (beginning-of-line)
cfe89c4f
RS
1730 (while (and (> arg 0) (not (eobp)))
1731 (setq arg (1- arg))
1732 (beginning-of-line)
1733 (while (and (not (eobp)) (dired-between-files)) (forward-line 1))
1734 (save-excursion
1735 (forward-line 1)
1736 (move-marker pos (1+ (point))))
1737 (save-excursion (funcall function))
1738 ;; Advance to the next line--actually, to the line that *was* next.
1739 ;; (If FUNCTION inserted some new lines in between, skip them.)
1740 (goto-char pos))
1741 (while (and (< arg 0) (not (bobp)))
1742 (setq arg (1+ arg))
1743 (forward-line -1)
1744 (while (and (not (bobp)) (dired-between-files)) (forward-line -1))
1745 (beginning-of-line)
1746 (save-excursion (funcall function)))
1747 (move-marker pos nil)
1748 (dired-move-to-filename)))
492d2437
RS
1749
1750(defun dired-between-files ()
1751 ;; Point must be at beginning of line
1752 ;; Should be equivalent to (save-excursion (not (dired-move-to-filename)))
1753 ;; but is about 1.5..2.0 times as fast. (Actually that's not worth it)
1754 (or (looking-at "^$\\|^. *$\\|^. total\\|^. wildcard")
a8004e4b
RS
1755 (and (looking-at dired-subdir-regexp)
1756 (save-excursion (not (dired-move-to-filename))))))
492d2437
RS
1757
1758(defun dired-next-marked-file (arg &optional wrap opoint)
1759 "Move to the next marked file, wrapping around the end of the buffer."
1760 (interactive "p\np")
1761 (or opoint (setq opoint (point)));; return to where interactively started
1762 (if (if (> arg 0)
1763 (re-search-forward dired-re-mark nil t arg)
1764 (beginning-of-line)
1765 (re-search-backward dired-re-mark nil t (- arg)))
1766 (dired-move-to-filename)
1767 (if (null wrap)
1768 (progn
1769 (goto-char opoint)
1770 (error "No next marked file"))
1771 (message "(Wraparound for next marked file)")
1772 (goto-char (if (> arg 0) (point-min) (point-max)))
1773 (dired-next-marked-file arg nil opoint))))
1774
1775(defun dired-prev-marked-file (arg &optional wrap)
1776 "Move to the previous marked file, wrapping around the end of the buffer."
1777 (interactive "p\np")
1778 (dired-next-marked-file (- arg) wrap))
1779
1780(defun dired-file-marker (file)
1781 ;; Return FILE's marker, or nil if unmarked.
1782 (save-excursion
1783 (and (dired-goto-file file)
1784 (progn
1785 (beginning-of-line)
1786 (if (not (equal ?\040 (following-char)))
1787 (following-char))))))
1788
1789(defun dired-mark-files-in-region (start end)
1790 (let (buffer-read-only)
1791 (if (> start end)
1792 (error "start > end"))
1793 (goto-char start) ; assumed at beginning of line
1794 (while (< (point) end)
1795 ;; Skip subdir line and following garbage like the `total' line:
1796 (while (and (< (point) end) (dired-between-files))
1797 (forward-line 1))
1798 (if (and (not (looking-at dired-re-dot))
1799 (dired-get-filename nil t))
1800 (progn
1801 (delete-char 1)
1802 (insert dired-marker-char)))
1803 (forward-line 1))))
1804
1805(defun dired-mark (arg)
1806 "Mark the current (or next ARG) files.
1807If on a subdir headerline, mark all its files except `.' and `..'.
1808
1809Use \\[dired-unmark-all-files] to remove all marks
1810and \\[dired-unmark] on a subdir to remove the marks in
1811this subdir."
1812 (interactive "P")
7b2469ae 1813 (if (and (cdr dired-subdir-alist) (dired-get-subdir))
492d2437
RS
1814 (save-excursion (dired-mark-subdir-files))
1815 (let (buffer-read-only)
1816 (dired-repeat-over-lines
52041219 1817 (prefix-numeric-value arg)
492d2437
RS
1818 (function (lambda () (delete-char 1) (insert dired-marker-char)))))))
1819
1820(defun dired-unmark (arg)
1821 "Unmark the current (or next ARG) files.
1822If looking at a subdir, unmark all its files except `.' and `..'."
1823 (interactive "P")
1824 (let ((dired-marker-char ?\040))
1825 (dired-mark arg)))
1826
1827(defun dired-flag-file-deletion (arg)
1828 "In dired, flag the current line's file for deletion.
1829With prefix arg, repeat over several lines.
1830
1831If on a subdir headerline, mark all its files except `.' and `..'."
1832 (interactive "P")
1833 (let ((dired-marker-char dired-del-marker))
1834 (dired-mark arg)))
1835
1836(defun dired-unmark-backward (arg)
1837 "In dired, move up lines and remove deletion flag there.
1838Optional prefix ARG says how many lines to unflag; default is one line."
1839 (interactive "p")
1840 (dired-unmark (- arg)))
84fc2cfa 1841\f
492d2437
RS
1842;;; Commands to mark or flag files based on their characteristics or names.
1843
d2cadc4b
RS
1844(defvar dired-regexp-history nil
1845 "History list of regular expressions used in Dired commands.")
1846
1847(defun dired-read-regexp (prompt)
1848 (read-from-minibuffer prompt nil nil nil 'dired-regexp-history))
492d2437
RS
1849
1850(defun dired-mark-files-regexp (regexp &optional marker-char)
1851 "Mark all files matching REGEXP for use in later commands.
1852A prefix argument means to unmark them instead.
1853`.' and `..' are never marked.
1854
1855REGEXP is an Emacs regexp, not a shell wildcard. Thus, use `\\.o$' for
1856object files--just `.o' will mark more than you might think."
1857 (interactive
1858 (list (dired-read-regexp (concat (if current-prefix-arg "Unmark" "Mark")
1859 " files (regexp): "))
1860 (if current-prefix-arg ?\040)))
1861 (let ((dired-marker-char (or marker-char dired-marker-char)))
1862 (dired-mark-if
1863 (and (not (looking-at dired-re-dot))
1864 (not (eolp)) ; empty line
1865 (let ((fn (dired-get-filename nil t)))
1866 (and fn (string-match regexp (file-name-nondirectory fn)))))
1867 "matching file")))
1868
1869(defun dired-flag-files-regexp (regexp)
1870 "In dired, flag all files containing the specified REGEXP for deletion.
1871The match is against the non-directory part of the filename. Use `^'
1872 and `$' to anchor matches. Exclude subdirs by hiding them.
1873`.' and `..' are never flagged."
1874 (interactive (list (dired-read-regexp "Flag for deletion (regexp): ")))
1875 (dired-mark-files-regexp regexp dired-del-marker))
1876
1877(defun dired-mark-symlinks (unflag-p)
1878 "Mark all symbolic links.
1879With prefix argument, unflag all those files."
1880 (interactive "P")
1881 (let ((dired-marker-char (if unflag-p ?\040 dired-marker-char)))
1882 (dired-mark-if (looking-at dired-re-sym) "symbolic link")))
1883
1884(defun dired-mark-directories (unflag-p)
1885 "Mark all directory file lines except `.' and `..'.
1886With prefix argument, unflag all those files."
1887 (interactive "P")
1888 (let ((dired-marker-char (if unflag-p ?\040 dired-marker-char)))
1889 (dired-mark-if (and (looking-at dired-re-dir)
1890 (not (looking-at dired-re-dot)))
1891 "directory file")))
1892
1893(defun dired-mark-executables (unflag-p)
1894 "Mark all executable files.
1895With prefix argument, unflag all those files."
1896 (interactive "P")
1897 (let ((dired-marker-char (if unflag-p ?\040 dired-marker-char)))
1898 (dired-mark-if (looking-at dired-re-exe) "executable file")))
1899
1900;; dired-x.el has a dired-mark-sexp interactive command: mark
1901;; files for which PREDICATE returns non-nil.
1902
1903(defun dired-flag-auto-save-files (&optional unflag-p)
84fc2cfa
ER
1904 "Flag for deletion files whose names suggest they are auto save files.
1905A prefix argument says to unflag those files instead."
1906 (interactive "P")
492d2437
RS
1907 (let ((dired-marker-char (if unflag-p ?\040 dired-del-marker)))
1908 (dired-mark-if
2a838614 1909 ;; It is less than general to check for # here,
a91526b9
RS
1910 ;; but it's the only way this runs fast enough.
1911 (and (save-excursion (end-of-line)
536ae2dd
RS
1912 (or
1913 (eq (preceding-char) ?#)
1914 ;; Handle executables in case of -F option.
1915 ;; We need not worry about the other kinds
1916 ;; of markings that -F makes, since they won't
1917 ;; appear on real auto-save files.
1918 (if (eq (preceding-char) ?*)
1919 (progn
1920 (forward-char -1)
1921 (eq (preceding-char) ?#)))))
a91526b9
RS
1922 (not (looking-at dired-re-dir))
1923 (let ((fn (dired-get-filename t t)))
1924 (if fn (auto-save-file-name-p
1925 (file-name-nondirectory fn)))))
1926 "auto save file")))
492d2437
RS
1927
1928(defun dired-flag-backup-files (&optional unflag-p)
1929 "Flag all backup files (names ending with `~') for deletion.
1930With prefix argument, unflag these files."
1931 (interactive "P")
1932 (let ((dired-marker-char (if unflag-p ?\040 dired-del-marker)))
1933 (dired-mark-if
a91526b9
RS
1934 ;; It is less than general to check for ~ here,
1935 ;; but it's the only way this runs fast enough.
1936 (and (save-excursion (end-of-line)
536ae2dd
RS
1937 (or
1938 (eq (preceding-char) ?~)
1939 ;; Handle executables in case of -F option.
1940 ;; We need not worry about the other kinds
1941 ;; of markings that -F makes, since they won't
1942 ;; appear on real backup files.
1943 (if (eq (preceding-char) ?*)
1944 (progn
1945 (forward-char -1)
1946 (eq (preceding-char) ?~)))))
a91526b9 1947 (not (looking-at dired-re-dir))
492d2437
RS
1948 (let ((fn (dired-get-filename t t)))
1949 (if fn (backup-file-name-p fn))))
1950 "backup file")))
1951
6482fcac
RS
1952(defun dired-change-marks (&optional old new)
1953 "Change all OLD marks to NEW marks.
1954OLD and NEW are both characters used to mark files."
1955 (interactive
1956 (let* ((cursor-in-echo-area t)
1957 (old (progn (message "Change (old mark): ") (read-char)))
1958 (new (progn (message "Change %c marks to (new mark): " old)
1959 (read-char))))
1960 (list old new)))
e4e02841
RS
1961 (if (or (eq old ?\r) (eq new ?\r))
1962 (ding)
1963 (let ((string (format "\n%c" old))
1964 (buffer-read-only))
1965 (save-excursion
1966 (goto-char (point-min))
1967 (while (search-forward string nil t)
1968 (subst-char-in-region (match-beginning 0)
1969 (match-end 0) old new))))))
6482fcac 1970
b1ecd9c6
RS
1971(defun dired-unmark-all-files-no-query ()
1972 "Remove all marks from all files in the Dired buffer."
1973 (interactive)
1974 (dired-unmark-all-files ?\r))
1975
8b87a301 1976(defun dired-unmark-all-files (mark &optional arg)
b602ba2f
RS
1977 "Remove a specific mark (or any mark) from every file.
1978After this command, type the mark character to remove,
1979or type RET to remove all marks.
3585916f 1980With prefix arg, query for each marked file.
492d2437 1981Type \\[help-command] at that time for help."
b602ba2f
RS
1982 (interactive "cRemove marks (RET means all): \nP")
1983 (save-excursion
1984 (let* ((count 0)
1985 buffer-read-only case-fold-search query
1986 (string (format "\n%c" mark))
1987 (help-form "\
8b87a301
RS
1988Type SPC or `y' to unmark one file, DEL or `n' to skip to next,
1989`!' to unmark all remaining files with no more questions."))
b602ba2f
RS
1990 (goto-char (point-min))
1991 (while (if (eq mark ?\r)
1992 (re-search-forward dired-re-mark nil t)
1993 (search-forward string nil t))
1994 (if (or (not arg)
1995 (dired-query 'query "Unmark file `%s'? "
1996 (dired-get-filename t)))
1997 (progn (subst-char-in-region (1- (point)) (point)
1998 (preceding-char) ?\ )
1999 (setq count (1+ count)))))
2000 (message (if (= count 1) "1 mark removed"
2001 "%d marks removed")
2002 count))))
492d2437 2003\f
492d2437 2004;; Logging failures operating on files, and showing the results.
84fc2cfa 2005
492d2437 2006(defvar dired-log-buffer "*Dired log*")
84fc2cfa 2007
492d2437
RS
2008(defun dired-why ()
2009 "Pop up a buffer with error log output from Dired.
2010A group of errors from a single command ends with a formfeed.
2011Thus, use \\[backward-page] to find the beginning of a group of errors."
2012 (interactive)
2013 (if (get-buffer dired-log-buffer)
2014 (let ((owindow (selected-window))
2015 (window (display-buffer (get-buffer dired-log-buffer))))
2016 (unwind-protect
6482fcac 2017 (progn
492d2437
RS
2018 (select-window window)
2019 (goto-char (point-max))
2020 (recenter -1))
2021 (select-window owindow)))))
2022
2023(defun dired-log (log &rest args)
2024 ;; Log a message or the contents of a buffer.
2025 ;; If LOG is a string and there are more args, it is formatted with
2026 ;; those ARGS. Usually the LOG string ends with a \n.
2027 ;; End each bunch of errors with (dired-log t): this inserts
2028 ;; current time and buffer, and a \f (formfeed).
2029 (let ((obuf (current-buffer)))
2030 (unwind-protect ; want to move point
2031 (progn
2032 (set-buffer (get-buffer-create dired-log-buffer))
2033 (goto-char (point-max))
2034 (let (buffer-read-only)
2035 (cond ((stringp log)
2036 (insert (if args
2037 (apply (function format) log args)
2038 log)))
2039 ((bufferp log)
2040 (insert-buffer log))
2041 ((eq t log)
2042 (insert "\n\t" (current-time-string)
2043 "\tBuffer `" (buffer-name obuf) "'\n\f\n")))))
2044 (set-buffer obuf))))
2045
2046(defun dired-log-summary (string failures)
2047 (message (if failures "%s--type ? for details (%s)"
2048 "%s--type ? for details")
2049 string failures)
2050 ;; Log a summary describing a bunch of errors.
2051 (dired-log (concat "\n" string))
2052 (dired-log t))
2053\f
2054;;; Sorting
2055
2056;; Most ls can only sort by name or by date (with -t), nothing else.
2057;; GNU ls sorts on size with -S, on extension with -X, and unsorted with -U.
2058;; So anything that does not contain these is sort "by name".
2059
2060(defvar dired-ls-sorting-switches "SXU"
2061 "String of `ls' switches (single letters) except `t' that influence sorting.")
2062
2063(defvar dired-sort-by-date-regexp
2064 (concat "^-[^" dired-ls-sorting-switches
2065 "]*t[^" dired-ls-sorting-switches "]*$")
2066 "Regexp recognized by dired to set `by date' mode.")
2067
2068(defvar dired-sort-by-name-regexp
2069 (concat "^-[^t" dired-ls-sorting-switches "]+$")
2070 "Regexp recognized by dired to set `by name' mode.")
2071
492d2437
RS
2072(defun dired-sort-set-modeline ()
2073 ;; Set modeline display according to dired-actual-switches.
2074 ;; Modeline display of "by name" or "by date" guarantees the user a
2075 ;; match with the corresponding regexps. Non-matching switches are
2076 ;; shown literally.
1d673d85 2077 (setq mode-name
492d2437
RS
2078 (let (case-fold-search)
2079 (cond ((string-match dired-sort-by-name-regexp dired-actual-switches)
1d673d85 2080 "Dired by name")
492d2437 2081 ((string-match dired-sort-by-date-regexp dired-actual-switches)
1d673d85 2082 "Dired by date")
492d2437 2083 (t
1d673d85 2084 (concat "Dired " dired-actual-switches)))))
492d2437
RS
2085 ;; update mode line:
2086 (set-buffer-modified-p (buffer-modified-p)))
2087
2088(defun dired-sort-toggle-or-edit (&optional arg)
2089 "Toggle between sort by date/name and refresh the dired buffer.
2090With a prefix argument you can edit the current listing switches instead."
84fc2cfa 2091 (interactive "P")
492d2437
RS
2092 (if arg
2093 (dired-sort-other
2094 (read-string "ls switches (must contain -l): " dired-actual-switches))
2095 (dired-sort-toggle)))
2096
2097(defun dired-sort-toggle ()
2098 ;; Toggle between sort by date/name. Reverts the buffer.
2099 (setq dired-actual-switches
2100 (let (case-fold-search)
2101 (concat
2102 "-l"
26add1bf 2103 (dired-replace-in-string (concat "[-lt"
492d2437
RS
2104 dired-ls-sorting-switches "]")
2105 ""
2106 dired-actual-switches)
2107 (if (string-match (concat "[t" dired-ls-sorting-switches "]")
2108 dired-actual-switches)
2109 ""
2110 "t"))))
2111 (dired-sort-set-modeline)
2112 (revert-buffer))
2113
2114(defun dired-replace-in-string (regexp newtext string)
2115 ;; Replace REGEXP with NEWTEXT everywhere in STRING and return result.
2116 ;; NEWTEXT is taken literally---no \\DIGIT escapes will be recognized.
2117 (let ((result "") (start 0) mb me)
2118 (while (string-match regexp string start)
2119 (setq mb (match-beginning 0)
2120 me (match-end 0)
2121 result (concat result (substring string start mb) newtext)
2122 start me))
2123 (concat result (substring string start))))
2124
2125(defun dired-sort-other (switches &optional no-revert)
2126 ;; Specify new ls SWITCHES for current dired buffer. Values matching
2127 ;; `dired-sort-by-date-regexp' or `dired-sort-by-name-regexp' set the
2128 ;; minor mode accordingly, others appear literally in the mode line.
2129 ;; With optional second arg NO-REVERT, don't refresh the listing afterwards.
2130 (setq dired-actual-switches switches)
2131 (dired-sort-set-modeline)
2132 (or no-revert (revert-buffer)))
84fc2cfa 2133\f
492d2437
RS
2134;; To make this file smaller, the less common commands
2135;; go in a separate file. But autoload them here
2136;; to make the separation invisible.
2137
2138(autoload 'dired-diff "dired-aux"
2139 "Compare file at point with file FILE using `diff'.
2140FILE defaults to the file at the mark.
ab67260b 2141The prompted-for file is the first file given to `diff'."
492d2437
RS
2142 t)
2143
2144(autoload 'dired-backup-diff "dired-aux"
2145 "Diff this file with its backup file or vice versa.
2146Uses the latest backup, if there are several numerical backups.
2147If this file is a backup, diff it with its original.
ab67260b 2148The backup file is the first file given to `diff'."
492d2437
RS
2149 t)
2150
2d051399
RS
2151(autoload 'dired-clean-directory "dired-aux"
2152 "Flag numerical backups for deletion.
2153Spares `dired-kept-versions' latest versions, and `kept-old-versions' oldest.
2154Positive prefix arg KEEP overrides `dired-kept-versions';
2155Negative prefix arg KEEP overrides `kept-old-versions' with KEEP made positive.
2156
2157To clear the flags on these files, you can use \\[dired-flag-backup-files]
2158with a prefix argument."
2159 t)
2160
492d2437
RS
2161(autoload 'dired-do-chmod "dired-aux"
2162 "Change the mode of the marked (or next ARG) files.
2163This calls chmod, thus symbolic modes like `g+w' are allowed."
2164 t)
2165
2166(autoload 'dired-do-chgrp "dired-aux"
2167 "Change the group of the marked (or next ARG) files."
2168 t)
2169
2170(autoload 'dired-do-chown "dired-aux"
2171 "Change the owner of the marked (or next ARG) files."
2172 t)
2173
2174(autoload 'dired-do-print "dired-aux"
2175 "Print the marked (or next ARG) files.
2176Uses the shell command coming from variables `lpr-command' and
2177`lpr-switches' as default."
2178 t)
2179
2180(autoload 'dired-do-shell-command "dired-aux"
6482fcac
RS
2181 "Run a shell command COMMAND on the marked files.
2182If no files are marked or a specific numeric prefix arg is given,
2183the next ARG files are used. Just \\[universal-argument] means the current file.
2184The prompt mentions the file(s) or the marker, as appropriate.
2185
492d2437 2186If there is output, it goes to a separate buffer.
6482fcac 2187
492d2437
RS
2188Normally the command is run on each file individually.
2189However, if there is a `*' in the command then it is run
2190just once with the entire file list substituted there.
2191
6482fcac
RS
2192No automatic redisplay of dired buffers is attempted, as there's no
2193telling what files the command may have changed. Type
2194\\[dired-do-redisplay] to redisplay the marked files.
492d2437
RS
2195
2196The shell command has the top level directory as working directory, so
2197output files usually are created there instead of in a subdir."
2198 t)
2199
492d2437
RS
2200(autoload 'dired-do-kill-lines "dired-aux"
2201 "Kill all marked lines (not the files).
2202With a prefix arg, kill all lines not marked or flagged."
2203 t)
2204
2205(autoload 'dired-do-compress "dired-aux"
2206 "Compress or uncompress marked (or next ARG) files."
2207 t)
2208
2209(autoload 'dired-do-byte-compile "dired-aux"
2210 "Byte compile marked (or next ARG) Emacs Lisp files."
2211 t)
2212
2213(autoload 'dired-do-load "dired-aux"
2214 "Load the marked (or next ARG) Emacs Lisp files."
2215 t)
2216
2217(autoload 'dired-do-redisplay "dired-aux"
2218 "Redisplay all marked (or next ARG) files.
2219If on a subdir line, redisplay that subdirectory. In that case,
2220a prefix arg lets you edit the `ls' switches used for the new listing."
2221 t)
2222
2223(autoload 'dired-string-replace-match "dired-aux"
2224 "Replace first match of REGEXP in STRING with NEWTEXT.
2225If it does not match, nil is returned instead of the new string.
2226Optional arg LITERAL means to take NEWTEXT literally.
2227Optional arg GLOBAL means to replace all matches."
2228 t)
2229
2230(autoload 'dired-create-directory "dired-aux"
84fc2cfa 2231 "Create a directory called DIRECTORY."
492d2437 2232 t)
84fc2cfa 2233
492d2437
RS
2234(autoload 'dired-do-copy "dired-aux"
2235 "Copy all marked (or next ARG) files, or copy the current file.
2236Thus, a zero prefix argument copies nothing. But it toggles the
2237variable `dired-copy-preserve-time' (which see)."
2238 t)
2239
2240(autoload 'dired-do-symlink "dired-aux"
2241 "Make symbolic links to current file or all marked (or next ARG) files.
2242When operating on just the current file, you specify the new name.
2243When operating on multiple or marked files, you specify a directory
2244and new symbolic links are made in that directory
2245with the same names that the files currently have."
2246 t)
2247
2248(autoload 'dired-do-hardlink "dired-aux"
2249 "Add names (hard links) current file or all marked (or next ARG) files.
2250When operating on just the current file, you specify the new name.
2251When operating on multiple or marked files, you specify a directory
2252and new hard links are made in that directory
2253with the same names that the files currently have."
2254 t)
2255
2256(autoload 'dired-do-rename "dired-aux"
2257 "Rename current file or all marked (or next ARG) files.
2258When renaming just the current file, you specify the new name.
2259When renaming multiple or marked files, you specify a directory."
2260 t)
2261
2262(autoload 'dired-do-rename-regexp "dired-aux"
2263 "Rename marked files containing REGEXP to NEWNAME.
2264As each match is found, the user must type a character saying
2265 what to do with it. For directions, type \\[help-command] at that time.
2266NEWNAME may contain \\=\\<n> or \\& as in `query-replace-regexp'.
2267REGEXP defaults to the last regexp used.
2268With a zero prefix arg, renaming by regexp affects the complete
2269 pathname - usually only the non-directory part of file names is used
2270 and changed."
2271 t)
2272
2273(autoload 'dired-do-copy-regexp "dired-aux"
2274 "Copy all marked files containing REGEXP to NEWNAME.
2275See function `dired-rename-regexp' for more info."
2276 t)
2277
2278(autoload 'dired-do-hardlink-regexp "dired-aux"
2279 "Hardlink all marked files containing REGEXP to NEWNAME.
2280See function `dired-rename-regexp' for more info."
2281 t)
2282
2283(autoload 'dired-do-symlink-regexp "dired-aux"
2284 "Symlink all marked files containing REGEXP to NEWNAME.
2285See function `dired-rename-regexp' for more info."
2286 t)
2287
2288(autoload 'dired-upcase "dired-aux"
2289 "Rename all marked (or next ARG) files to upper case."
2290 t)
2291
2292(autoload 'dired-downcase "dired-aux"
2293 "Rename all marked (or next ARG) files to lower case."
2294 t)
2295
2296(autoload 'dired-maybe-insert-subdir "dired-aux"
2297 "Insert this subdirectory into the same dired buffer.
2298If it is already present, just move to it (type \\[dired-do-redisplay] to refresh),
2299 else inserts it at its natural place (as `ls -lR' would have done).
2300With a prefix arg, you may edit the ls switches used for this listing.
2301 You can add `R' to the switches to expand the whole tree starting at
2302 this subdirectory.
2303This function takes some pains to conform to `ls -lR' output."
2304 t)
2305
2306(autoload 'dired-next-subdir "dired-aux"
2307 "Go to next subdirectory, regardless of level."
2308 t)
2309
2310(autoload 'dired-prev-subdir "dired-aux"
2311 "Go to previous subdirectory, regardless of level.
2312When called interactively and not on a subdir line, go to this subdir's line."
2313 t)
2314
2315(autoload 'dired-goto-subdir "dired-aux"
2316 "Go to end of header line of DIR in this dired buffer.
2317Return value of point on success, otherwise return nil.
2318The next char is either \\n, or \\r if DIR is hidden."
2319 t)
2320
2321(autoload 'dired-mark-subdir-files "dired-aux"
2322 "Mark all files except `.' and `..'."
2323 t)
2324
2325(autoload 'dired-kill-subdir "dired-aux"
2326 "Remove all lines of current subdirectory.
2327Lower levels are unaffected."
2328 t)
2329
2330(autoload 'dired-tree-up "dired-aux"
2331 "Go up ARG levels in the dired tree."
2332 t)
2333
2334(autoload 'dired-tree-down "dired-aux"
2335 "Go down in the dired tree."
2336 t)
2337
2338(autoload 'dired-hide-subdir "dired-aux"
2339 "Hide or unhide the current subdirectory and move to next directory.
2340Optional prefix arg is a repeat factor.
2341Use \\[dired-hide-all] to (un)hide all directories."
2342 t)
2343
2344(autoload 'dired-hide-all "dired-aux"
2345 "Hide all subdirectories, leaving only their header lines.
2346If there is already something hidden, make everything visible again.
2347Use \\[dired-hide-subdir] to (un)hide a particular subdirectory."
2348 t)
84fc2cfa 2349\f
492d2437
RS
2350(if (eq system-type 'vax-vms)
2351 (load "dired-vms"))
84fc2cfa 2352
52041219
RS
2353(provide 'dired)
2354
57e15005
BF
2355(run-hooks 'dired-load-hook) ; for your customizations
2356
52041219 2357;;; dired.el ends here