(dired-read-shell-command-default): Move it to
[bpt/emacs.git] / lisp / dired-x.el
CommitLineData
8c70a2de 1;;; dired-x.el --- extra Dired functionality -*-byte-compile-dynamic: t;-*-
cb3fe1f0 2
552939e4 3;; Copyright (C) 1993, 1994, 1997, 2001, 2002, 2003, 2004,
59ce725a 4;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
552939e4 5
cb3fe1f0
RS
6;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>
7;; Lawrence R. Dodd <dodd@roebling.poly.edu>
2d29381c 8;; Maintainer: Romain Francoise <rfrancoise@gnu.org>
a443d46e 9;; Keywords: dired extensions files
cb3fe1f0 10
cb3fe1f0
RS
11;; This file is part of GNU Emacs.
12
13;; GNU Emacs is free software; you can redistribute it and/or modify
14;; it under the terms of the GNU General Public License as published by
b4aa6026 15;; the Free Software Foundation; either version 3, or (at your option)
cb3fe1f0
RS
16;; any later version.
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
b578f267 24;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
25;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26;; Boston, MA 02110-1301, USA.
cb3fe1f0 27
9572a9dd 28;;; Commentary:
cb3fe1f0 29
b578f267 30;; This is Sebastian Kremer's excellent dired-x.el (Dired Extra), version
a443d46e
GM
31;; 1.191, hacked up for GNU Emacs. Redundant or conflicting material has
32;; been removed or renamed in order to work properly with dired of GNU
33;; Emacs. All suggestions or comments are most welcomed.
b578f267 34
71296446 35;;
b578f267 36;; Please, PLEASE, *PLEASE* see the info pages.
71296446 37;;
b578f267
EN
38
39;; BUGS: Type M-x dired-x-submit-report and a report will be generated.
40
41;; INSTALLATION: In your ~/.emacs,
42;;
43;; (add-hook 'dired-load-hook
44;; (function (lambda ()
45;; (load "dired-x")
d7af463c 46;; ;; Set global variables here. For example:
b578f267 47;; ;; (setq dired-guess-shell-gnutar "gtar")
d7af463c
RF
48;; )))
49;; (add-hook 'dired-mode-hook
50;; (function (lambda ()
51;; ;; Set buffer-local variables here. For example:
ce64e046 52;; ;; (dired-omit-mode 1)
b578f267
EN
53;; )))
54;;
55;; At load time dired-x.el will install itself, redefine some functions, and
56;; bind some dired keys. *Please* see the info pages for more details.
57
b847eb8c 58;; *Please* see the info pages for more details.
b578f267
EN
59
60;; User defined variables:
61;;
62;; dired-bind-vm
63;; dired-vm-read-only-folders
64;; dired-bind-jump
65;; dired-bind-info
66;; dired-bind-man
b847eb8c 67;; dired-x-hands-off-my-keys
b578f267
EN
68;; dired-find-subdir
69;; dired-enable-local-variables
70;; dired-local-variables-file
71;; dired-guess-shell-gnutar
72;; dired-guess-shell-gzip-quiet
73;; dired-guess-shell-znew-switches
74;; dired-guess-shell-alist-user
75;; dired-clean-up-buffers-too
ce64e046 76;; dired-omit-mode
b578f267
EN
77;; dired-omit-files
78;; dired-omit-extensions
ad8c4554 79;; dired-omit-size-limit
b578f267
EN
80;;
81;; To find out more about these variables, load this file, put your cursor at
82;; the end of any of the variable names, and hit C-h v [RET]. *Please* see
83;; the info pages for more details.
84
85;; When loaded this code redefines the following functions of GNU Emacs
86;;
87;; Function Found in this file of GNU Emacs
88;; -------- -------------------------------
89;; dired-clean-up-after-deletion ../lisp/dired.el
90;; dired-find-buffer-nocreate ../lisp/dired.el
91;; dired-initial-position ../lisp/dired.el
92;;
93;; dired-add-entry ../lisp/dired-aux.el
94;; dired-read-shell-command ../lisp/dired-aux.el
cb3fe1f0
RS
95
96\f
b578f267 97;;; Code:
cb3fe1f0 98
b578f267 99;; LOAD.
cb3fe1f0 100
b578f267
EN
101;; This is a no-op if dired-x is being loaded via `dired-load-hook'. It is
102;; here in case the user has autoloaded dired-x via the dired-jump key binding
103;; (instead of autoloading to dired as is suggested in the info-pages).
9572a9dd 104
d82cfc0c 105(require 'dired)
9572a9dd 106
b578f267
EN
107;; We will redefine some functions and also need some macros so we need to
108;; load dired stuff of GNU Emacs.
d82cfc0c
RS
109
110(require 'dired-aux)
9572a9dd 111
12ec3981 112(defvar vm-folder-directory)
670d3fce 113(eval-when-compile (require 'man))
12ec3981 114
b578f267 115;;; User-defined variables.
cb3fe1f0 116
286c247d
RS
117(defgroup dired-x nil
118 "Extended directory editing (dired-x)."
119 :group 'dired)
cb3fe1f0 120
286c247d
RS
121(defgroup dired-keys nil
122 "Dired keys customizations."
123 :prefix "dired-"
124 :group 'dired-x)
cb3fe1f0 125
286c247d 126(defcustom dired-bind-vm nil
b847eb8c 127 "*Non-nil means \"V\" runs `dired-vm', otherwise \"V\" runs `dired-rmail'.
286c247d
RS
128Also, RMAIL files contain -*- rmail -*- at the top so \"f\",
129`dired-advertised-find-file', will run rmail."
130 :type 'boolean
131 :group 'dired-keys)
132
133(defcustom dired-bind-jump t
b847eb8c 134 "*Non-nil means bind `dired-jump' to C-x C-j, otherwise do not."
286c247d
RS
135 :type 'boolean
136 :group 'dired-keys)
137
138(defcustom dired-bind-man t
b847eb8c 139 "*Non-nil means bind `dired-man' to \"N\" in dired-mode, otherwise do not."
286c247d
RS
140 :type 'boolean
141 :group 'dired-keys)
142
143(defcustom dired-bind-info t
b847eb8c 144 "*Non-nil means bind `dired-info' to \"I\" in dired-mode, otherwise do not."
286c247d
RS
145 :type 'boolean
146 :group 'dired-keys)
147
148(defcustom dired-vm-read-only-folders nil
b847eb8c 149 "*If non-nil, \\[dired-vm] will visit all folders read-only.
cb3fe1f0
RS
150If neither nil nor t, e.g. the symbol `if-file-read-only', only
151files not writable by you are visited read-only.
152
286c247d
RS
153Read-only folders only work in VM 5, not in VM 4."
154 :type '(choice (const :tag "off" nil)
155 (const :tag "on" t)
e2c146c1 156 (other :tag "non-writable only" if-file-read-only))
286c247d 157 :group 'dired-x)
cb3fe1f0 158
ce64e046
LH
159(define-minor-mode dired-omit-mode
160 "Toggle Dired-Omit mode.
161With numeric ARG, enable Dired-Omit mode if ARG is positive, disable
6fbad7af 162otherwise. Enabling and disabling is buffer-local.
ce64e046 163If enabled, \"uninteresting\" files are not listed.
cb3fe1f0 164Uninteresting files are those whose filenames match regexp `dired-omit-files',
286c247d 165plus those ending with extensions in `dired-omit-extensions'."
ce64e046
LH
166 :group 'dired-x
167 (if dired-omit-mode
168 ;; This will mention how many lines were omitted:
169 (let ((dired-omit-size-limit nil)) (dired-omit-expunge))
170 (revert-buffer)))
171
172;; For backward compatibility
cf24b82d 173(define-obsolete-variable-alias 'dired-omit-files-p 'dired-omit-mode "22.1")
cb3fe1f0 174
99358b97 175(defcustom dired-omit-files "^\\.?#\\|^\\.$\\|^\\.\\.$"
e2439696 176 "*Filenames matching this regexp will not be displayed.
ce64e046
LH
177This only has effect when `dired-omit-mode' is t. See interactive function
178`dired-omit-mode' \(\\[dired-omit-mode]\) and variable
99358b97
RS
179`dired-omit-extensions'. The default is to omit `.', `..', auto-save
180files and lock files."
286c247d
RS
181 :type 'regexp
182 :group 'dired-x)
cb3fe1f0 183
286c247d 184(defcustom dired-find-subdir nil ; t is pretty near to DWIM...
0a44133e
RS
185 "*If non-nil, Dired always finds a directory in a buffer of its own.
186If nil, Dired finds the directory as a subdirectory in some other buffer
187if it is present as one.
cb3fe1f0 188
6fbad7af 189If there are several dired buffers for a directory, the most recently
cb3fe1f0
RS
190used is chosen.
191
192Dired avoids switching to the current buffer, so that if you have
b847eb8c 193a normal and a wildcard buffer for the same directory, \\[dired] will
286c247d
RS
194toggle between those two."
195 :type 'boolean
196 :group 'dired-x)
197
8e458944 198(defcustom dired-omit-size-limit 30000
286c247d
RS
199 "*Maximum size for the \"omitting\" feature.
200If nil, there is no maximum size."
201 :type '(choice (const :tag "no maximum" nil) integer)
202 :group 'dired-x)
cb3fe1f0 203
286c247d 204(defcustom dired-enable-local-variables t
6fbad7af 205 "*Control use of local-variables lists in Dired.
cb3fe1f0
RS
206The value can be t, nil or something else.
207A value of t means local-variables lists are obeyed;
208nil means they are ignored; anything else means query.
209
210This temporarily overrides the value of `enable-local-variables' when listing
286c247d
RS
211a directory. See also `dired-local-variables-file'."
212 :type 'boolean
213 :group 'dired-x)
cb3fe1f0 214
3f8105a1
RF
215(defcustom dired-guess-shell-gnutar (when (or (eq system-type 'gnu)
216 (eq system-type 'gnu/linux))
217 "tar")
b847eb8c
DL
218 "*If non-nil, name of GNU tar executable.
219\(E.g., \"tar\" or \"gtar\"). The `z' switch will be used with it for
220compressed or gzip'ed tar files. If you don't have GNU tar, set this
286c247d 221to nil: a pipe using `zcat' or `gunzip -c' will be used."
b847eb8c
DL
222 :type '(choice (const :tag "Not GNU tar" nil)
223 (string :tag "Command name"))
286c247d
RS
224 :group 'dired-x)
225
226(defcustom dired-guess-shell-gzip-quiet t
b847eb8c 227 "*Non-nil says pass -q to gzip overriding verbose GZIP environment."
286c247d
RS
228 :type 'boolean
229 :group 'dired-x)
230
231(defcustom dired-guess-shell-znew-switches nil
b847eb8c
DL
232 "*If non-nil, then string of switches passed to `znew', example: \"-K\"."
233 :type '(choice (const :tag "None" nil)
234 (string :tag "Switches"))
286c247d
RS
235 :group 'dired-x)
236
237(defcustom dired-clean-up-buffers-too t
6fbad7af 238 "*Non-nil means offer to kill buffers visiting files and dirs deleted in Dired."
286c247d
RS
239 :type 'boolean
240 :group 'dired-x)
cb3fe1f0 241
b578f267 242;;; KEY BINDINGS.
cb3fe1f0 243
ce64e046 244(define-key dired-mode-map "\M-o" 'dired-omit-mode)
71326638 245(define-key dired-mode-map "*O" 'dired-mark-omitted)
cb3fe1f0 246(define-key dired-mode-map "\M-(" 'dired-mark-sexp)
582bd36a
RS
247(define-key dired-mode-map "*(" 'dired-mark-sexp)
248(define-key dired-mode-map "*." 'dired-mark-extension)
cb3fe1f0 249(define-key dired-mode-map "\M-!" 'dired-smart-shell-command)
cb3fe1f0 250(define-key dired-mode-map "w" 'dired-copy-filename-as-kill)
cb3fe1f0
RS
251(define-key dired-mode-map "\M-G" 'dired-goto-subdir)
252(define-key dired-mode-map "F" 'dired-do-find-marked-files)
253(define-key dired-mode-map "Y" 'dired-do-relsymlink)
254(define-key dired-mode-map "%Y" 'dired-do-relsymlink-regexp)
255(define-key dired-mode-map "V" 'dired-do-run-mail)
256
257(if dired-bind-man
258 (define-key dired-mode-map "N" 'dired-man))
259
260(if dired-bind-info
261 (define-key dired-mode-map "I" 'dired-info))
262
438fc253
LH
263;;; MENU BINDINGS
264
265(let ((menu-bar (lookup-key dired-mode-map [menu-bar])))
266 (let ((menu (lookup-key menu-bar [operate])))
267 (define-key-after
268 menu
269 [find-files]
270 '(menu-item
271 "Find files"
272 dired-do-find-marked-files
273 :help "Find current or marked files")
274 'delete)
275 (define-key-after
276 menu
277 [relsymlink]
278 '(menu-item
279 "Relative symlink to..."
280 dired-do-relsymlink
281 :visible (fboundp 'make-symbolic-link)
282 :help "Make relative symbolic links for current or marked files")
283 'symlink))
284 (let ((menu (lookup-key menu-bar [mark])))
285 (define-key-after
286 menu
287 [flag-extension]
288 '(menu-item
289 "Flag extension..."
290 dired-flag-extension
291 :help "Flag files with a certain extension for deletion")
292 'garbage-files)
293 (define-key-after
294 menu
295 [mark-extension]
296 '(menu-item
297 "Mark extension..."
298 dired-mark-extension
299 :help "Mark files with a certain extension")
300 'symlinks)
301 (define-key-after
302 menu
303 [mark-omitted]
304 '(menu-item
305 "Mark omitted"
306 dired-mark-omitted
307 :help "Mark files matching `dired-omit-files' and `dired-omit-extensions'")
308 'mark-extension))
309 (let ((menu (lookup-key menu-bar [regexp])))
310 (define-key-after
311 menu
312 [relsymlink-regexp]
313 '(menu-item
314 "Relative symlink..."
315 dired-do-relsymlink-regexp
316 :visible (fboundp 'make-symbolic-link)
317 :help "Make relative symbolic links for files matching regexp")
318 'symlink))
319 (let ((menu (lookup-key menu-bar [immediate])))
320 (define-key-after
321 menu
322 [omit-mode]
323 '(menu-item
324 "Omit mode" dired-omit-mode
325 :button (:toggle . dired-omit-mode)
326 :help "Enable or disable omitting \"uninteresting\" files")
327 'dashes)))
328
9572a9dd 329;;; GLOBAL BINDING.
cb3fe1f0
RS
330(if dired-bind-jump
331 (progn
332 (define-key global-map "\C-x\C-j" 'dired-jump)
333 (define-key global-map "\C-x4\C-j" 'dired-jump-other-window)))
334
335\f
b578f267 336;;; Install into appropriate hooks.
cb3fe1f0
RS
337
338(add-hook 'dired-mode-hook 'dired-extra-startup)
339(add-hook 'dired-after-readin-hook 'dired-omit-expunge)
340
341(defun dired-extra-startup ()
6fbad7af 342 "Automatically put on `dired-mode-hook' to get extra Dired features:
cb3fe1f0 343\\<dired-mode-map>
cb3fe1f0
RS
344 \\[dired-do-run-mail]\t-- run mail on folder (see `dired-bind-vm')
345 \\[dired-info]\t-- run info on file
346 \\[dired-man]\t-- run man on file
347 \\[dired-do-find-marked-files]\t-- visit all marked files simultaneously
ce64e046 348 \\[dired-omit-mode]\t-- toggle omitting of files
b847eb8c 349 \\[dired-mark-sexp]\t-- mark by Lisp expression
6fbad7af
JB
350 \\[dired-copy-filename-as-kill]\t-- copy the file or subdir names into the kill ring;
351 \t you can feed it to other commands using \\[yank]
cb3fe1f0
RS
352
353For more features, see variables
354
b847eb8c
DL
355 `dired-bind-vm'
356 `dired-bind-jump'
357 `dired-bind-info'
358 `dired-bind-man'
359 `dired-vm-read-only-folders'
ce64e046 360 `dired-omit-mode'
b847eb8c
DL
361 `dired-omit-files'
362 `dired-omit-extensions'
363 `dired-omit-size-limit'
364 `dired-find-subdir'
365 `dired-enable-local-variables'
366 `dired-local-variables-file'
367 `dired-guess-shell-gnutar'
368 `dired-guess-shell-gzip-quiet'
369 `dired-guess-shell-znew-switches'
370 `dired-guess-shell-alist-user'
371 `dired-clean-up-buffers-too'
cb3fe1f0
RS
372
373See also functions
374
b847eb8c
DL
375 `dired-flag-extension'
376 `dired-virtual'
377 `dired-jump'
378 `dired-man'
379 `dired-vm'
380 `dired-rmail'
381 `dired-info'
382 `dired-do-find-marked-files'"
cb3fe1f0
RS
383 (interactive)
384
385 ;; These must be done in each new dired buffer.
386 (dired-hack-local-variables)
387 (dired-omit-startup))
388
389\f
b578f267 390;;; BUFFER CLEANING.
cb3fe1f0 391
b578f267 392;; REDEFINE.
cb3fe1f0 393(defun dired-clean-up-after-deletion (fn)
b847eb8c
DL
394 "Clean up after a deleted file or directory FN.
395Remove expanded subdir of deleted dir, if any."
cb3fe1f0
RS
396 (save-excursion (and (cdr dired-subdir-alist)
397 (dired-goto-subdir fn)
398 (dired-kill-subdir)))
399
400 ;; Offer to kill buffer of deleted file FN.
401 (if dired-clean-up-buffers-too
402 (progn
403 (let ((buf (get-file-buffer fn)))
404 (and buf
405 (funcall (function y-or-n-p)
406 (format "Kill buffer of %s, too? "
407 (file-name-nondirectory fn)))
408 (save-excursion ; you never know where kill-buffer leaves you
409 (kill-buffer buf))))
12c38283 410 (let ((buf-list (dired-buffers-for-dir (expand-file-name fn)))
cb3fe1f0
RS
411 (buf nil))
412 (and buf-list
413 (y-or-n-p (format "Kill dired buffer%s of %s, too? "
414 (dired-plural-s (length buf-list))
415 (file-name-nondirectory fn)))
416 (while buf-list
417 (save-excursion (kill-buffer (car buf-list)))
418 (setq buf-list (cdr buf-list)))))))
9572a9dd 419 ;; Anything else?
cb3fe1f0
RS
420 )
421
422\f
b578f267 423;;; EXTENSION MARKING FUNCTIONS.
cb3fe1f0 424
9572a9dd 425;;; Mark files with some extension.
cb3fe1f0 426(defun dired-mark-extension (extension &optional marker-char)
b847eb8c 427 "Mark all files with a certain EXTENSION for use in later commands.
6fbad7af 428A `.' is *not* automatically prepended to the string entered."
cb3fe1f0
RS
429 ;; EXTENSION may also be a list of extensions instead of a single one.
430 ;; Optional MARKER-CHAR is marker to use.
431 (interactive "sMarking extension: \nP")
432 (or (listp extension)
433 (setq extension (list extension)))
434 (dired-mark-files-regexp
435 (concat ".";; don't match names with nothing but an extension
436 "\\("
437 (mapconcat 'regexp-quote extension "\\|")
438 "\\)$")
439 marker-char))
440
441(defun dired-flag-extension (extension)
b847eb8c 442 "In dired, flag all files with a certain EXTENSION for deletion.
cb3fe1f0
RS
443A `.' is *not* automatically prepended to the string entered."
444 (interactive "sFlagging extension: ")
445 (dired-mark-extension extension dired-del-marker))
446
447;;; Define some unpopular file extensions. Used for cleaning and omitting.
448
449(defvar dired-patch-unclean-extensions
450 '(".rej" ".orig")
451 "List of extensions of dispensable files created by the `patch' program.")
452
453(defvar dired-tex-unclean-extensions
454 '(".toc" ".log" ".aux");; these are already in completion-ignored-extensions
455 "List of extensions of dispensable files created by TeX.")
456
457(defvar dired-latex-unclean-extensions
458 '(".idx" ".lof" ".lot" ".glo")
459 "List of extensions of dispensable files created by LaTeX.")
460
461(defvar dired-bibtex-unclean-extensions
462 '(".blg" ".bbl")
463 "List of extensions of dispensable files created by BibTeX.")
464
465(defvar dired-texinfo-unclean-extensions
466 '(".cp" ".cps" ".fn" ".fns" ".ky" ".kys" ".pg" ".pgs"
467 ".tp" ".tps" ".vr" ".vrs")
468 "List of extensions of dispensable files created by texinfo.")
469
470(defun dired-clean-patch ()
471 "Flag dispensable files created by patch for deletion.
472See variable `dired-patch-unclean-extensions'."
473 (interactive)
474 (dired-flag-extension dired-patch-unclean-extensions))
475
476(defun dired-clean-tex ()
9572a9dd 477 "Flag dispensable files created by [La]TeX etc. for deletion.
ca388882 478See variables `dired-tex-unclean-extensions',
9572a9dd
KH
479`dired-latex-unclean-extensions', `dired-bibtex-unclean-extensions' and
480`dired-texinfo-unclean-extensions'."
cb3fe1f0
RS
481 (interactive)
482 (dired-flag-extension (append dired-texinfo-unclean-extensions
483 dired-latex-unclean-extensions
484 dired-bibtex-unclean-extensions
485 dired-tex-unclean-extensions)))
486
9572a9dd
KH
487(defun dired-very-clean-tex ()
488 "Flag dispensable files created by [La]TeX *and* \".dvi\" for deletion.
489See variables `dired-texinfo-unclean-extensions',
490`dired-latex-unclean-extensions', `dired-bibtex-unclean-extensions' and
491`dired-texinfo-unclean-extensions'."
cb3fe1f0 492 (interactive)
9572a9dd
KH
493 (dired-flag-extension (append dired-texinfo-unclean-extensions
494 dired-latex-unclean-extensions
495 dired-bibtex-unclean-extensions
496 dired-tex-unclean-extensions
497 (list ".dvi"))))
cb3fe1f0 498\f
b578f267 499;;; JUMP.
cb3fe1f0 500
40c8b203 501;;;###autoload
cb3fe1f0
RS
502(defun dired-jump (&optional other-window)
503 "Jump to dired buffer corresponding to current buffer.
504If in a file, dired the current directory and move to file's line.
6fbad7af 505If in Dired already, pop up a level and goto old directory's line.
cb3fe1f0
RS
506In case the proper dired file line cannot be found, refresh the dired
507buffer and try again."
508 (interactive "P")
509 (let* ((file buffer-file-name)
510 (dir (if file (file-name-directory file) default-directory)))
511 (if (eq major-mode 'dired-mode)
512 (progn
513 (setq dir (dired-current-directory))
514 (dired-up-directory other-window)
515 (or (dired-goto-file dir)
516 ;; refresh and try again
9572a9dd 517 (progn
cb3fe1f0
RS
518 (dired-insert-subdir (file-name-directory dir))
519 (dired-goto-file dir))))
520 (if other-window
521 (dired-other-window dir)
522 (dired dir))
523 (if file
524 (or (dired-goto-file file)
525 ;; refresh and try again
9572a9dd 526 (progn
cb3fe1f0 527 (dired-insert-subdir (file-name-directory file))
7e90bcf5
RS
528 (dired-goto-file file))
529 ;; Toggle omitting, if it is on, and try again.
ce64e046 530 (if dired-omit-mode
7e90bcf5 531 (progn
ce64e046 532 (dired-omit-mode)
7e90bcf5 533 (dired-goto-file file))))))))
cb3fe1f0
RS
534
535(defun dired-jump-other-window ()
6fbad7af 536 "Like \\[dired-jump] (`dired-jump') but in other window."
cb3fe1f0
RS
537 (interactive)
538 (dired-jump t))
cb3fe1f0 539\f
b578f267 540;;; OMITTING.
cb3fe1f0
RS
541
542;;; Enhanced omitting of lines from directory listings.
543;;; Marked files are never omitted.
544
545;; should probably get rid of this and always use 'no-dir.
546;; sk 28-Aug-1991 09:37
547(defvar dired-omit-localp 'no-dir
b847eb8c 548 "The LOCALP argument `dired-omit-expunge' passes to `dired-get-filename'.
6fbad7af 549If it is `no-dir', omitting is much faster, but you can only match
470fa6d1
KS
550against the non-directory part of the file name. Set it to nil if you
551need to match the entire file name.")
cb3fe1f0
RS
552
553;; \017=^O for Omit - other packages can chose other control characters.
554(defvar dired-omit-marker-char ?\017
4cdc09a9 555 "Temporary marker used by dired-omit.
cb3fe1f0
RS
556Should never be used as marker by the user or other packages.")
557
558(defun dired-omit-startup ()
ce64e046 559 (or (assq 'dired-omit-mode minor-mode-alist)
cb3fe1f0 560 (setq minor-mode-alist
ce64e046 561 (append '((dired-omit-mode
ab606888
GM
562 (:eval (if (eq major-mode 'dired-mode)
563 " Omit" ""))))
564 minor-mode-alist))))
cb3fe1f0 565
ce64e046
LH
566(defun dired-mark-omitted ()
567 "Mark files matching `dired-omit-files' and `dired-omit-extensions'."
568 (interactive)
569 (let ((dired-omit-mode nil)) (revert-buffer)) ;; Show omitted files
570 (dired-mark-unmarked-files (dired-omit-regexp) nil nil dired-omit-localp))
cb3fe1f0
RS
571
572(defvar dired-omit-extensions
573 (append completion-ignored-extensions
574 dired-latex-unclean-extensions
575 dired-bibtex-unclean-extensions
576 dired-texinfo-unclean-extensions)
b847eb8c 577 "If non-nil, a list of extensions \(strings\) to omit from Dired listings.
685ff9f8
RS
578Defaults to elements of `completion-ignored-extensions',
579`dired-latex-unclean-extensions', `dired-bibtex-unclean-extensions', and
b847eb8c 580`dired-texinfo-unclean-extensions'.
685ff9f8 581
ce64e046
LH
582See interactive function `dired-omit-mode' \(\\[dired-omit-mode]\) and
583variables `dired-omit-mode' and `dired-omit-files'.")
cb3fe1f0
RS
584
585(defun dired-omit-expunge (&optional regexp)
586 "Erases all unmarked files matching REGEXP.
ce64e046 587Does nothing if global variable `dired-omit-mode' is nil, or if called
ad8c4554 588 non-interactively and buffer is bigger than `dired-omit-size-limit'.
cb3fe1f0
RS
589If REGEXP is nil or not specified, uses `dired-omit-files', and also omits
590 filenames ending in `dired-omit-extensions'.
591If REGEXP is the empty string, this function is a no-op.
592
593This functions works by temporarily binding `dired-marker-char' to
594`dired-omit-marker-char' and calling `dired-do-kill-lines'."
595 (interactive "sOmit files (regexp): ")
ce64e046 596 (if (and dired-omit-mode
ad8c4554
RS
597 (or (interactive-p)
598 (not dired-omit-size-limit)
8e458944
RS
599 (< (buffer-size) dired-omit-size-limit)
600 (progn
601 (message "Not omitting: directory larger than %d characters."
602 dired-omit-size-limit)
ce64e046 603 (setq dired-omit-mode nil)
8e458944 604 nil)))
cb3fe1f0 605 (let ((omit-re (or regexp (dired-omit-regexp)))
9b5ef74b 606 (old-modified-p (buffer-modified-p))
cb3fe1f0
RS
607 count)
608 (or (string= omit-re "")
609 (let ((dired-marker-char dired-omit-marker-char))
610 (message "Omitting...")
611 (if (dired-mark-unmarked-files omit-re nil nil dired-omit-localp)
612 (progn
613 (setq count (dired-do-kill-lines nil "Omitted %d line%s."))
048ea441 614 (force-mode-line-update))
cb3fe1f0 615 (message "(Nothing to omit)"))))
9b5ef74b
RS
616 ;; Try to preserve modified state of buffer. So `%*' doesn't appear
617 ;; in mode-line of omitted buffers.
b847eb8c 618 (set-buffer-modified-p (and old-modified-p
9b5ef74b
RS
619 (save-excursion
620 (goto-char (point-min))
621 (re-search-forward dired-re-mark nil t))))
cb3fe1f0
RS
622 count)))
623
624(defun dired-omit-regexp ()
625 (concat (if dired-omit-files (concat "\\(" dired-omit-files "\\)") "")
626 (if (and dired-omit-files dired-omit-extensions) "\\|" "")
627 (if dired-omit-extensions
628 (concat ".";; a non-extension part should exist
629 "\\("
630 (mapconcat 'regexp-quote dired-omit-extensions "\\|")
631 "\\)$")
632 "")))
633
634;; Returns t if any work was done, nil otherwise.
635(defun dired-mark-unmarked-files (regexp msg &optional unflag-p localp)
b847eb8c 636 "Mark unmarked files matching REGEXP, displaying MSG.
470fa6d1 637REGEXP is matched against the entire file name.
cb3fe1f0
RS
638Does not re-mark files which already have a mark.
639With prefix argument, unflag all those files.
6fbad7af 640Optional fourth argument LOCALP is as in `dired-get-filename'."
cb3fe1f0 641 (interactive "P")
6fbad7af 642 (let ((dired-marker-char (if unflag-p ?\s dired-marker-char)))
cb3fe1f0
RS
643 (dired-mark-if
644 (and
645 ;; not already marked
646 (looking-at " ")
647 ;; uninteresting
648 (let ((fn (dired-get-filename localp t)))
649 (and fn (string-match regexp fn))))
650 msg)))
651
552939e4
GM
652;; Compiler does not get fset.
653(declare-function dired-omit-old-add-entry "dired-x")
654
655;;; REDEFINE.
656;;; Redefine dired-aux.el's version of `dired-add-entry'
657;;; Save old defun if not already done:
658(or (fboundp 'dired-omit-old-add-entry)
659 (fset 'dired-omit-old-add-entry (symbol-function 'dired-add-entry)))
e637bdf8 660
9572a9dd 661;;; REDEFINE.
c8225cbe 662(defun dired-omit-new-add-entry (filename &optional marker-char relative)
cb3fe1f0
RS
663 ;; This redefines dired-aux.el's dired-add-entry to avoid calling ls for
664 ;; files that are going to be omitted anyway.
ce64e046 665 (if dired-omit-mode
cb3fe1f0
RS
666 ;; perhaps return t without calling ls
667 (let ((omit-re (dired-omit-regexp)))
668 (if (or (string= omit-re "")
669 (not
670 (string-match omit-re
671 (cond
672 ((eq 'no-dir dired-omit-localp)
673 filename)
674 ((eq t dired-omit-localp)
675 (dired-make-relative filename))
676 (t
677 (dired-make-absolute
678 filename
679 (file-name-directory filename)))))))
680 ;; if it didn't match, go ahead and add the entry
c8225cbe 681 (dired-omit-old-add-entry filename marker-char relative)
cb3fe1f0
RS
682 ;; dired-add-entry returns t for success, perhaps we should
683 ;; return file-exists-p
684 t))
685 ;; omitting is not turned on at all
c8225cbe 686 (dired-omit-old-add-entry filename marker-char relative)))
cb3fe1f0 687
cb3fe1f0
RS
688;; Redefine it.
689(fset 'dired-add-entry 'dired-omit-new-add-entry)
690
691\f
b578f267 692;;; VIRTUAL DIRED MODE.
cb3fe1f0
RS
693
694;;; For browsing `ls -lR' listings in a dired-like fashion.
695
6fbad7af 696(defalias 'virtual-dired 'dired-virtual)
cb3fe1f0
RS
697(defun dired-virtual (dirname &optional switches)
698 "Put this buffer into Virtual Dired mode.
699
700In Virtual Dired mode, all commands that do not actually consult the
701filesystem will work.
702
703This is useful if you want to peruse and move around in an ls -lR
704output file, for example one you got from an ftp server. With
705ange-ftp, you can even dired a directory containing an ls-lR file,
706visit that file and turn on virtual dired mode. But don't try to save
707this file, as dired-virtual indents the listing and thus changes the
708buffer.
709
710If you have save a Dired buffer in a file you can use \\[dired-virtual] to
711resume it in a later session.
712
6fbad7af
JB
713Type \\<dired-mode-map>\\[revert-buffer] \
714in the Virtual Dired buffer and answer `y' to convert
715the virtual to a real dired buffer again. You don't have to do this, though:
716you can relist single subdirs using \\[dired-do-redisplay]."
cb3fe1f0
RS
717
718 ;; DIRNAME is the top level directory of the buffer. It will become
719 ;; its `default-directory'. If nil, the old value of
720 ;; default-directory is used.
721
722 ;; Optional SWITCHES are the ls switches to use.
723
724 ;; Shell wildcards will be used if there already is a `wildcard'
725 ;; line in the buffer (thus it is a saved Dired buffer), but there
726 ;; is no other way to get wildcards. Insert a `wildcard' line by
727 ;; hand if you want them.
728
729 (interactive
730 (list (read-string "Virtual Dired directory: " (dired-virtual-guess-dir))))
731 (goto-char (point-min))
732 (or (looking-at " ")
733 ;; if not already indented, do it now:
734 (indent-region (point-min) (point-max) 2))
735 (or dirname (setq dirname default-directory))
736 (setq dirname (expand-file-name (file-name-as-directory dirname)))
737 (setq default-directory dirname) ; contains no wildcards
738 (let ((wildcard (save-excursion
739 (goto-char (point-min))
740 (forward-line 1)
741 (and (looking-at "^ wildcard ")
742 (buffer-substring (match-end 0)
743 (progn (end-of-line) (point)))))))
744 (if wildcard
745 (setq dirname (expand-file-name wildcard default-directory))))
746 ;; If raw ls listing (not a saved old dired buffer), give it a
747 ;; decent subdir headerline:
748 (goto-char (point-min))
749 (or (looking-at dired-subdir-regexp)
e8425548 750 (insert " "
fc50a3be
MY
751 (directory-file-name (file-name-directory default-directory))
752 ":\n"))
cb3fe1f0
RS
753 (dired-mode dirname (or switches dired-listing-switches))
754 (setq mode-name "Virtual Dired"
755 revert-buffer-function 'dired-virtual-revert)
756 (set (make-local-variable 'dired-subdir-alist) nil)
757 (dired-build-subdir-alist)
758 (goto-char (point-min))
759 (dired-initial-position dirname))
760
761(defun dired-virtual-guess-dir ()
b847eb8c 762 "Guess and return appropriate working directory of this buffer.
4e6ef391 763The buffer is assumed to be in Dired or ls -lR format. The guess is
b847eb8c
DL
764based upon buffer contents. If nothing could be guessed, returns
765nil."
cb3fe1f0
RS
766
767 (let ((regexp "^\\( \\)?\\([^ \n\r]*\\)\\(:\\)[\n\r]")
768 (subexpr 2))
769 (goto-char (point-min))
770 (cond ((looking-at regexp)
771 ;; If a saved dired buffer, look to which dir and
772 ;; perhaps wildcard it belongs:
773 (let ((dir (buffer-substring (match-beginning subexpr)
774 (match-end subexpr))))
775 (file-name-as-directory dir)))
776 ;; Else no match for headerline found. It's a raw ls listing.
777 ;; In raw ls listings the directory does not have a headerline
778 ;; try parent of first subdir, if any
779 ((re-search-forward regexp nil t)
780 (file-name-directory
781 (directory-file-name
782 (file-name-as-directory
783 (buffer-substring (match-beginning subexpr)
784 (match-end subexpr))))))
785 (t ; if all else fails
786 nil))))
787
788
789(defun dired-virtual-revert (&optional arg noconfirm)
790 (if (not
791 (y-or-n-p "Cannot revert a Virtual Dired buffer - switch to Real Dired mode? "))
b847eb8c 792 (error "Cannot revert a Virtual Dired buffer")
cb3fe1f0
RS
793 (setq mode-name "Dired"
794 revert-buffer-function 'dired-revert)
795 (revert-buffer)))
796
797;; A zero-arg version of dired-virtual.
cb3fe1f0 798(defun dired-virtual-mode ()
6fbad7af 799 "Put current buffer into Virtual Dired mode (see `dired-virtual').
b94d76ae 800Useful on `magic-mode-alist' with the regexp
cb3fe1f0 801
b94d76ae 802 \"^ \\\\(/[^ /]+\\\\)+/?:$\"
cb3fe1f0 803
6fbad7af 804to put saved dired buffers automatically into Virtual Dired mode.
cb3fe1f0 805
b94d76ae 806Also useful for `auto-mode-alist' like this:
cb3fe1f0 807
b94d76ae
GM
808 (add-to-list 'auto-mode-alist
809 '(\"[^/]\\\\.dired\\\\'\" . dired-virtual-mode))"
cb3fe1f0
RS
810 (interactive)
811 (dired-virtual (dired-virtual-guess-dir)))
812
813\f
b578f267 814;;; SMART SHELL.
cb3fe1f0
RS
815
816;;; An Emacs buffer can have but one working directory, stored in the
817;;; buffer-local variable `default-directory'. A Dired buffer may have
818;;; several subdirectories inserted, but still has but one working directory:
819;;; that of the top level Dired directory in that buffer. For some commands
820;;; it is appropriate that they use the current Dired directory instead of
821;;; `default-directory', e.g., `find-file' and `compile'. This is a general
822;;; mechanism is provided for special handling of the working directory in
823;;; special major modes.
824
825;; It's easier to add to this alist than redefine function
826;; default-directory while keeping the old information.
827(defconst default-directory-alist
828 '((dired-mode . (if (fboundp 'dired-current-directory)
829 (dired-current-directory)
830 default-directory)))
b847eb8c
DL
831 "Alist of major modes and their opinion on `default-directory'.
832This is given as a Lisp expression to evaluate. A resulting value of
833nil is ignored in favor of `default-directory'.")
cb3fe1f0 834
b847eb8c
DL
835(defun dired-default-directory ()
836 "Usage like variable `default-directory'.
837Knows about the special cases in variable `default-directory-alist'."
cb3fe1f0
RS
838 (or (eval (cdr (assq major-mode default-directory-alist)))
839 default-directory))
840
841(defun dired-smart-shell-command (cmd &optional insert)
6fbad7af 842 "Like function `shell-command', but in the current Virtual Dired directory."
93714f3c
GM
843 (interactive (list (read-from-minibuffer "Shell command: "
844 nil nil nil 'shell-command-history)
845 current-prefix-arg))
b847eb8c 846 (let ((default-directory (dired-default-directory)))
cb3fe1f0
RS
847 (shell-command cmd insert)))
848
849\f
b578f267 850;;; LOCAL VARIABLES FOR DIRED BUFFERS.
cb3fe1f0 851
9572a9dd
KH
852;;; Brief Description:
853;;;
854;;; * `dired-extra-startup' is part of the `dired-mode-hook'.
855;;;
cb3fe1f0 856;;; * `dired-extra-startup' calls `dired-hack-local-variables'
9572a9dd 857;;;
cb3fe1f0 858;;; * `dired-hack-local-variables' checks the value of
9572a9dd
KH
859;;; `dired-local-variables-file'
860;;;
cb3fe1f0
RS
861;;; * Check if `dired-local-variables-file' is a non-nil string and is a
862;;; filename found in the directory of the Dired Buffer being created.
9572a9dd 863;;;
cb3fe1f0
RS
864;;; * If `dired-local-variables-file' satisfies the above, then temporarily
865;;; include it in the Dired Buffer at the bottom.
9572a9dd 866;;;
cb3fe1f0
RS
867;;; * Set `enable-local-variables' temporarily to the user variable
868;;; `dired-enable-local-variables' and run `hack-local-variables' on the
869;;; Dired Buffer.
870
db8f8812 871(defvar dired-local-variables-file (convert-standard-filename ".dired")
cb3fe1f0
RS
872 "Filename, as string, containing local dired buffer variables to be hacked.
873If this file found in current directory, then it will be inserted into dired
6fbad7af
JB
874buffer and `hack-local-variables' will be run. See Info node
875`(emacs)File Variables' for more information on local variables.
876See also `dired-enable-local-variables'.")
cb3fe1f0
RS
877
878(defun dired-hack-local-variables ()
879 "Evaluate local variables in `dired-local-variables-file' for dired buffer."
880 (if (and dired-local-variables-file
881 (stringp dired-local-variables-file)
882 (file-exists-p dired-local-variables-file))
883 (let ((opoint (point-max))
884 buffer-read-only
885 ;; In case user has `enable-local-variables' set to nil we
886 ;; override it locally with dired's variable.
887 (enable-local-variables dired-enable-local-variables))
888 ;; Insert 'em.
889 (save-excursion
890 (goto-char opoint)
891 (insert "\^L\n")
892 (insert-file-contents dired-local-variables-file))
893 ;; Hack 'em.
894 (let ((buffer-file-name dired-local-variables-file))
895 (hack-local-variables))
896 ;; Make sure that the modeline shows the proper information.
897 (dired-sort-set-modeline)
898 ;; Delete this stuff: `eobp' is used to find last subdir by dired.el.
9572a9dd 899 (delete-region opoint (point-max)))))
cb3fe1f0 900
9572a9dd 901(defun dired-omit-here-always ()
b847eb8c 902 "Create `dired-local-variables-file' for omitting and reverts directory.
6fbad7af 903Sets `dired-omit-mode' to t in a local variables file that is readable by
cb3fe1f0 904dired."
9572a9dd 905 (interactive)
cb3fe1f0
RS
906 (if (file-exists-p dired-local-variables-file)
907 (message "File `./%s' already exists." dired-local-variables-file)
908
909 ;; Create `dired-local-variables-file'.
910 (save-excursion
911 (set-buffer (get-buffer-create " *dot-dired*"))
912 (erase-buffer)
ce64e046 913 (insert "Local Variables:\ndired-omit-mode: t\nEnd:\n")
cb3fe1f0
RS
914 (write-file dired-local-variables-file)
915 (kill-buffer (current-buffer)))
916
917 ;; Run extra-hooks and revert directory.
918 (dired-extra-startup)
919 (dired-revert)))
920
921\f
b578f267 922;;; GUESS SHELL COMMAND.
cb3fe1f0 923
9572a9dd
KH
924;;; Brief Description:
925;;;
926;;; `dired-do-shell-command' is bound to `!' by dired.el.
927;;;
cb3fe1f0
RS
928;;; * Redefine `dired-do-shell-command' so it calls
929;;; `dired-guess-shell-command'.
9572a9dd 930;;;
cb3fe1f0
RS
931;;; * `dired-guess-shell-command' calls `dired-guess-default' with list of
932;;; marked files.
9572a9dd 933;;;
cb3fe1f0
RS
934;;; * Parse `dired-guess-shell-alist-user' and
935;;; `dired-guess-shell-alist-default' (in that order) for the first REGEXP
936;;; that matches the first file in the file list.
9572a9dd 937;;;
cb3fe1f0 938;;; * If the REGEXP matches all the entries of the file list then evaluate
c0d79871 939;;; COMMAND, which is either a string or a Lisp expression returning a
cb3fe1f0 940;;; string. COMMAND may be a list of commands.
9572a9dd 941;;;
cb3fe1f0 942;;; * Return this command to `dired-guess-shell-command' which prompts user
747e8ee2 943;;; with it. The list of commands is put into the list of default values.
cb3fe1f0
RS
944;;; If a command is used successfully then it is stored permanently in
945;;; `dired-shell-command-history'.
946
947;;; Guess what shell command to apply to a file.
948(defvar dired-shell-command-history nil
949 "History list for commands that read dired-shell commands.")
950
9572a9dd 951;;; Default list of shell commands.
cb3fe1f0
RS
952
953;;; NOTE: Use `gunzip -c' instead of `zcat' on `.gz' files. Some do not
954;;; install GNU zip's version of zcat.
955
956(defvar dired-guess-shell-alist-default
957 (list
ecd69427 958 (list "\\.tar$"
ca136496
RF
959 '(if dired-guess-shell-gnutar
960 (concat dired-guess-shell-gnutar " xvf")
961 "tar xvf")
962 ;; Extract files into a separate subdirectory
963 '(if dired-guess-shell-gnutar
964 (concat "mkdir " (file-name-sans-extension file)
965 "; " dired-guess-shell-gnutar " -C "
966 (file-name-sans-extension file) " -xvf")
967 (concat "mkdir " (file-name-sans-extension file)
968 "; tar -C " (file-name-sans-extension file) " -xvf"))
969 ;; List archive contents.
970 '(if dired-guess-shell-gnutar
971 (concat dired-guess-shell-gnutar " tvf")
972 "tar tvf"))
cb3fe1f0
RS
973
974 ;; REGEXPS for compressed archives must come before the .Z rule to
975 ;; be recognized:
976 (list "\\.tar\\.Z$"
ca136496
RF
977 ;; Untar it.
978 '(if dired-guess-shell-gnutar
979 (concat dired-guess-shell-gnutar " zxvf")
980 (concat "zcat * | tar xvf -"))
981 ;; Optional conversion to gzip format.
982 '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
983 " " dired-guess-shell-znew-switches))
cb3fe1f0
RS
984
985 ;; gzip'ed archives
2f017676 986 (list "\\.t\\(ar\\.\\)?gz$"
ca136496
RF
987 '(if dired-guess-shell-gnutar
988 (concat dired-guess-shell-gnutar " zxvf")
989 (concat "gunzip -qc * | tar xvf -"))
990 ;; Extract files into a separate subdirectory
991 '(if dired-guess-shell-gnutar
992 (concat "mkdir " (file-name-sans-extension file)
993 "; " dired-guess-shell-gnutar " -C "
994 (file-name-sans-extension file) " -zxvf")
995 (concat "mkdir " (file-name-sans-extension file)
996 "; gunzip -qc * | tar -C "
997 (file-name-sans-extension file) " -xvf -"))
998 ;; Optional decompression.
999 '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q" ""))
1000 ;; List archive contents.
1001 '(if dired-guess-shell-gnutar
1002 (concat dired-guess-shell-gnutar " ztvf")
1003 (concat "gunzip -qc * | tar tvf -")))
ecd69427 1004
7ba7b794 1005 ;; bzip2'ed archives
ecd69427 1006 (list "\\.t\\(ar\\.bz2\\|bz\\)$"
7ba7b794 1007 "bunzip2 -c * | tar xvf -"
ca136496
RF
1008 ;; Extract files into a separate subdirectory
1009 '(concat "mkdir " (file-name-sans-extension file)
1010 "; bunzip2 -c * | tar -C "
1011 (file-name-sans-extension file) " -xvf -")
7ba7b794 1012 ;; Optional decompression.
ca136496 1013 "bunzip2")
cb3fe1f0 1014
ecd69427
JL
1015 '("\\.shar\\.Z$" "zcat * | unshar")
1016 '("\\.shar\\.g?z$" "gunzip -qc * | unshar")
cb3fe1f0 1017
85400f54 1018 '("\\.e?ps$" "ghostview" "xloadimage" "lpr")
ecd69427 1019 (list "\\.e?ps\\.g?z$" "gunzip -qc * | ghostview -"
ca136496
RF
1020 ;; Optional decompression.
1021 '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
ecd69427 1022 (list "\\.e?ps\\.Z$" "zcat * | ghostview -"
ca136496
RF
1023 ;; Optional conversion to gzip format.
1024 '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
1025 " " dired-guess-shell-znew-switches))
ecd69427 1026
cb3fe1f0 1027 '("\\.patch$" "cat * | patch")
ecd69427 1028 (list "\\.patch\\.g?z$" "gunzip -qc * | patch"
ca136496
RF
1029 ;; Optional decompression.
1030 '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
ecd69427 1031 (list "\\.patch\\.Z$" "zcat * | patch"
ca136496
RF
1032 ;; Optional conversion to gzip format.
1033 '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
1034 " " dired-guess-shell-znew-switches))
cb3fe1f0 1035
ecd69427 1036 ;; The following four extensions are useful with dired-man ("N" key)
d2ea84be 1037 (list "\\.\\(?:[0-9]\\|man\\)$" '(progn (require 'man)
ca136496
RF
1038 (if (Man-support-local-filenames)
1039 "man -l"
1040 "cat * | tbl | nroff -man -h")))
d2ea84be 1041 (list "\\.\\(?:[0-9]\\|man\\)\\.g?z$" '(progn (require 'man)
ca136496
RF
1042 (if (Man-support-local-filenames)
1043 "man -l"
1044 "gunzip -qc * | tbl | nroff -man -h"))
1045 ;; Optional decompression.
1046 '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
ecd69427 1047 (list "\\.[0-9]\\.Z$" '(progn (require 'man)
ca136496
RF
1048 (if (Man-support-local-filenames)
1049 "man -l"
1050 "zcat * | tbl | nroff -man -h"))
1051 ;; Optional conversion to gzip format.
1052 '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
1053 " " dired-guess-shell-znew-switches))
ecd69427
JL
1054 '("\\.pod$" "perldoc" "pod2man * | nroff -man")
1055
ca136496
RF
1056 '("\\.dvi$" "xdvi" "dvips") ; preview and printing
1057 '("\\.au$" "play") ; play Sun audiofiles
1058 '("\\.mpe?g$\\|\\.avi$" "xine -p")
1059 '("\\.wav$" "play")
1060 '("\\.uu$" "uudecode") ; for uudecoded files
cb3fe1f0 1061 '("\\.hqx$" "mcvert")
ca136496
RF
1062 '("\\.sh$" "sh") ; execute shell scripts
1063 '("\\.xbm$" "bitmap") ; view X11 bitmaps
cb3fe1f0 1064 '("\\.gp$" "gnuplot")
85400f54 1065 '("\\.p[bgpn]m$" "xloadimage")
ca136496 1066 '("\\.gif$" "xloadimage") ; view gif pictures
85400f54 1067 '("\\.tif$" "xloadimage")
b847eb8c 1068 '("\\.png$" "display") ; xloadimage 4.1 doesn't grok PNG
ecd69427 1069 '("\\.jpe?g$" "xloadimage")
ca136496
RF
1070 '("\\.fig$" "xfig") ; edit fig pictures
1071 '("\\.out$" "xgraph") ; for plotting purposes.
cb3fe1f0
RS
1072 '("\\.tex$" "latex" "tex")
1073 '("\\.texi\\(nfo\\)?$" "makeinfo" "texi2dvi")
ca136496
RF
1074 '("\\.pdf$" "xpdf")
1075 '("\\.doc$" "antiword" "strings")
1076 '("\\.rpm$" "rpm -qilp" "rpm -ivh")
1077 '("\\.dia$" "dia")
1078 '("\\.mgp$" "mgp")
cb3fe1f0
RS
1079
1080 ;; Some other popular archivers.
ca136496
RF
1081 (list "\\.zip$" "unzip" "unzip -l"
1082 ;; Extract files into a separate subdirectory
1083 '(concat "unzip" (if dired-guess-shell-gzip-quiet " -q")
1084 " -d " (file-name-sans-extension file)))
cb3fe1f0 1085 '("\\.zoo$" "zoo x//")
cb3fe1f0
RS
1086 '("\\.lzh$" "lharc x")
1087 '("\\.arc$" "arc x")
1088 '("\\.shar$" "unshar")
1089
1090 ;; Compression.
1091 (list "\\.g?z$" '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
ecd69427 1092 (list "\\.dz$" "dictunzip")
7ba7b794 1093 (list "\\.bz2$" "bunzip2")
cb3fe1f0 1094 (list "\\.Z$" "uncompress"
ca136496
RF
1095 ;; Optional conversion to gzip format.
1096 '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
1097 " " dired-guess-shell-znew-switches))
1098
1099 '("\\.sign?$" "gpg --verify"))
9572a9dd 1100
cb3fe1f0 1101 "Default alist used for shell command guessing.
b847eb8c 1102See `dired-guess-shell-alist-user'.")
cb3fe1f0 1103
b847eb8c
DL
1104(defcustom dired-guess-shell-alist-user nil
1105 "User-defined alist of rules for suggested commands.
1106These rules take precedence over the predefined rules in the variable
cb3fe1f0
RS
1107`dired-guess-shell-alist-default' (to which they are prepended).
1108
1109Each element of this list looks like
1110
1111 \(REGEXP COMMAND...\)
1112
6fbad7af 1113where each COMMAND can either be a string or a Lisp expression that evaluates
cb3fe1f0
RS
1114to a string. If several COMMANDs are given, the first one will be the default
1115and the rest will be added temporarily to the history and can be retrieved
1116with \\[previous-history-element] (M-p) .
1117
1118You can set this variable in your ~/.emacs. For example, to add rules for
1119`.foo' and `.bar' files, write
1120
1121 \(setq dired-guess-shell-alist-user
b847eb8c 1122 (list (list \"\\\\.foo\\\\'\" \"FOO-COMMAND\");; fixed rule
cb3fe1f0 1123 ;; possibly more rules ...
b847eb8c 1124 (list \"\\\\.bar\\\'\";; rule with condition test
cb3fe1f0
RS
1125 '(if condition
1126 \"BAR-COMMAND-1\"
b847eb8c
DL
1127 \"BAR-COMMAND-2\")))\)"
1128 :group 'dired-x
1129 :type '(alist :key-type regexp :value-type (repeat sexp)))
cb3fe1f0 1130
d7af463c
RF
1131(defcustom dired-guess-shell-case-fold-search t
1132 "If non-nil, `dired-guess-shell-alist-default' and
1133`dired-guess-shell-alist-user' are matched case-insensitively."
1134 :group 'dired-x
1135 :type 'boolean)
1136
cb3fe1f0 1137(defun dired-guess-default (files)
b847eb8c
DL
1138 "Guess a shell commands for FILES. Return command or list of commands.
1139See `dired-guess-shell-alist-user'."
cb3fe1f0 1140
d7af463c 1141 (let* ((case-fold-search dired-guess-shell-case-fold-search)
cb3fe1f0
RS
1142 ;; Prepend the user's alist to the default alist.
1143 (alist (append dired-guess-shell-alist-user
1144 dired-guess-shell-alist-default))
1145 (file (car files))
1146 (flist (cdr files))
1147 elt regexp cmds)
1148
1149 ;; Find the first match in the alist for first file in FILES.
1150 (while alist
1151 (setq elt (car alist)
1152 regexp (car elt)
1153 alist (cdr alist))
1154 (if (string-match regexp file)
1155 (setq cmds (cdr elt)
1156 alist nil)))
1157
1158 ;; If more than one file, see if all of FILES match regular expression.
1159 (while (and flist
1160 (string-match regexp (car flist)))
1161 (setq flist (cdr flist)))
9572a9dd 1162
cb3fe1f0
RS
1163 ;; If flist is still non-nil, then do not guess since this means that not
1164 ;; all the files in FILES were matched by the regexp.
1165 (setq cmds (and (not flist) cmds))
1166
9572a9dd
KH
1167 ;; Return commands or nil if flist is still non-nil.
1168 ;; Evaluate the commands in order that any logical testing will be done.
cb3fe1f0
RS
1169 (cond ((not (cdr cmds))
1170 (eval (car cmds))) ; single command
1171 (t
1172 (mapcar (function eval) cmds)))))
1173
1174(defun dired-guess-shell-command (prompt files)
b847eb8c 1175 "Ask user with PROMPT for a shell command, guessing a default from FILES."
cb3fe1f0 1176 (let ((default (dired-guess-default files))
5420b514 1177 default-list val)
cb3fe1f0
RS
1178 (if (null default)
1179 ;; Nothing to guess
1180 (read-from-minibuffer prompt nil nil nil 'dired-shell-command-history)
cb3fe1f0 1181 (if (listp default)
cb3fe1f0
RS
1182 ;; More than one guess
1183 (setq default-list default
1184 default (car default)
1185 prompt (concat
1186 prompt
1187 (format "{%d guesses} " (length default-list))))
cb3fe1f0
RS
1188 ;; Just one guess
1189 (setq default-list (list default)))
5420b514
JL
1190 ;; Put the first guess in the prompt but not in the initial value.
1191 (setq prompt (concat prompt (format "[%s] " default)))
1192 ;; All guesses can be retrieved with M-n
1193 (setq val (read-from-minibuffer prompt nil nil nil
1194 'dired-shell-command-history
1195 default-list))
1196 ;; If we got a return, then return default.
1197 (if (equal val "") default val))))
cb3fe1f0 1198
9572a9dd 1199;;; REDEFINE.
cb3fe1f0
RS
1200;;; Redefine dired-aux.el's version:
1201(defun dired-read-shell-command (prompt arg files)
b847eb8c
DL
1202 "Read a dired shell command prompting with PROMPT (using read-string).
1203ARG is the prefix arg and may be used to indicate in the prompt which
1204 files are affected.
1205This is an extra function so that you can redefine it."
cb3fe1f0
RS
1206 (dired-mark-pop-up
1207 nil 'shell files
1208 'dired-guess-shell-command
1209 (format prompt (dired-mark-prompt arg files)) ; PROMPT
1210 files)) ; FILES
1211
1212\f
b578f267 1213;;; RELATIVE SYMBOLIC LINKS.
cb3fe1f0 1214
e8425548
JB
1215(declare-function make-symbolic-link "fileio.c")
1216
cb3fe1f0
RS
1217(defvar dired-keep-marker-relsymlink ?S
1218 "See variable `dired-keep-marker-move'.")
1219
1220(defun dired-make-relative-symlink (file1 file2 &optional ok-if-already-exists)
b847eb8c 1221 "Make a symbolic link (pointing to FILE1) in FILE2.
cb3fe1f0
RS
1222The link is relative (if possible), for example
1223
1224 \"/vol/tex/bin/foo\" \"/vol/local/bin/foo\"
1225
1226results in
1227
b847eb8c 1228 \"../../tex/bin/foo\" \"/vol/local/bin/foo\""
cb3fe1f0
RS
1229 (interactive "FRelSymLink: \nFRelSymLink %s: \np")
1230 (let (name1 name2 len1 len2 (index 0) sub)
1231 (setq file1 (expand-file-name file1)
1232 file2 (expand-file-name file2)
1233 len1 (length file1)
1234 len2 (length file2))
470fa6d1 1235 ;; Find common initial file name components:
cb3fe1f0
RS
1236 (let (next)
1237 (while (and (setq next (string-match "/" file1 index))
1238 (setq next (1+ next))
1239 (< next (min len1 len2))
1240 ;; For the comparison, both substrings must end in
1241 ;; `/', so NEXT is *one plus* the result of the
1242 ;; string-match.
1243 ;; E.g., consider the case of linking "/tmp/a/abc"
34ff2275 1244 ;; to "/tmp/abc" erroneously giving "/tmp/a" instead
cb3fe1f0
RS
1245 ;; of "/tmp/" as common initial component
1246 (string-equal (substring file1 0 next)
1247 (substring file2 0 next)))
1248 (setq index next))
1249 (setq name2 file2
1250 sub (substring file1 0 index)
1251 name1 (substring file1 index)))
1252 (if (string-equal sub "/")
470fa6d1 1253 ;; No common initial file name found
cb3fe1f0
RS
1254 (setq name1 file1)
1255 ;; Else they have a common parent directory
1256 (let ((tem (substring file2 index))
1257 (start 0)
1258 (count 0))
1259 ;; Count number of slashes we must compensate for ...
1260 (while (setq start (string-match "/" tem start))
1261 (setq count (1+ count)
1262 start (1+ start)))
1263 ;; ... and prepend a "../" for each slash found:
1264 (while (> count 0)
1265 (setq count (1- count)
1266 name1 (concat "../" name1)))))
1267 (make-symbolic-link
1268 (directory-file-name name1) ; must not link to foo/
1269 ; (trailing slash!)
1270 name2 ok-if-already-exists)))
1271
5e5eaeda 1272;;;###autoload
cb3fe1f0 1273(defun dired-do-relsymlink (&optional arg)
b847eb8c
DL
1274 "Relative symlink all marked (or next ARG) files into a directory.
1275Otherwise make a relative symbolic link to the current file.
cb3fe1f0
RS
1276This creates relative symbolic links like
1277
1278 foo -> ../bar/foo
1279
1280not absolute ones like
1281
42496dc8
EZ
1282 foo -> /ugly/file/name/that/may/change/any/day/bar/foo
1283
4d4238cc 1284For absolute symlinks, use \\[dired-do-symlink]."
cb3fe1f0
RS
1285 (interactive "P")
1286 (dired-do-create-files 'relsymlink (function dired-make-relative-symlink)
1287 "RelSymLink" arg dired-keep-marker-relsymlink))
1288
d8e396ce 1289(defun dired-do-relsymlink-regexp (regexp newname &optional arg whole-name)
cb3fe1f0
RS
1290 "RelSymlink all marked files containing REGEXP to NEWNAME.
1291See functions `dired-do-rename-regexp' and `dired-do-relsymlink'
1292for more info."
1293 (interactive (dired-mark-read-regexp "RelSymLink"))
1294 (dired-do-create-files-regexp
1295 (function dired-make-relative-symlink)
d8e396ce 1296 "RelSymLink" arg regexp newname whole-name dired-keep-marker-relsymlink))
cb3fe1f0
RS
1297
1298\f
b578f267 1299;;; VISIT ALL MARKED FILES SIMULTANEOUSLY.
cb3fe1f0 1300
9572a9dd
KH
1301;;; Brief Description:
1302;;;
1303;;; `dired-do-find-marked-files' is bound to `F' by dired-x.el.
1304;;;
cb3fe1f0 1305;;; * Use `dired-get-marked-files' to collect the marked files in the current
9572a9dd
KH
1306;;; Dired Buffer into a list of filenames `FILE-LIST'.
1307;;;
cb3fe1f0
RS
1308;;; * Pass FILE-LIST to `dired-simultaneous-find-file' all with
1309;;; `dired-do-find-marked-files''s prefix argument NOSELECT.
9572a9dd 1310;;;
cb3fe1f0
RS
1311;;; * `dired-simultaneous-find-file' runs through FILE-LIST decrementing the
1312;;; list each time.
9572a9dd 1313;;;
cb3fe1f0
RS
1314;;; * If NOSELECT is non-nil then just run `find-file-noselect' on each
1315;;; element of FILE-LIST.
9572a9dd 1316;;;
cb3fe1f0
RS
1317;;; * If NOSELECT is nil then calculate the `size' of the window for each file
1318;;; by dividing the `window-height' by length of FILE-LIST. Thus, `size' is
1319;;; cognizant of the window-configuration.
9572a9dd 1320;;;
cb3fe1f0
RS
1321;;; * If `size' is too small abort, otherwise run `find-file' on each element
1322;;; of FILE-LIST giving each a window of height `size'.
1323
1324(defun dired-do-find-marked-files (&optional noselect)
1325 "Find all marked files displaying all of them simultaneously.
1326With optional NOSELECT just find files but do not select them.
1327
1328The current window is split across all files marked, as evenly as possible.
1329Remaining lines go to bottom-most window. The number of files that can be
1330displayed this way is restricted by the height of the current window and
1331`window-min-height'.
1332
9572a9dd 1333To keep dired buffer displayed, type \\[split-window-vertically] first.
cb3fe1f0
RS
1334To display just marked files, type \\[delete-other-windows] first."
1335
1336 (interactive "P")
1337 (dired-simultaneous-find-file (dired-get-marked-files) noselect))
1338
1339(defun dired-simultaneous-find-file (file-list noselect)
1340
b847eb8c
DL
1341 "Visit all files in FILE-LIST and display them simultaneously.
1342The current window is split across all files in FILE-LIST, as evenly as
1343possible. Remaining lines go to the bottom-most window. The number of
1344files that can be displayed this way is restricted by the height of the
1345current window and the variable `window-min-height'. With non-nil
1346NOSELECT the files are merely found but not selected."
9572a9dd 1347
cb3fe1f0
RS
1348 ;; We don't make this function interactive because it is usually too clumsy
1349 ;; to specify FILE-LIST interactively unless via dired.
1350
1351 (let (size)
1352
1353 (if noselect
1354 ;; Do not select the buffer.
1355 (find-file-noselect (car file-list))
1356
1357 ;; We will have to select the buffer. Calculate and check window size.
1358 (setq size (/ (window-height) (length file-list)))
1359 (or (<= window-min-height size)
b847eb8c 1360 (error "Too many files to visit simultaneously. Try C-u prefix"))
cb3fe1f0
RS
1361 (find-file (car file-list)))
1362
1363 ;; Decrement.
1364 (setq file-list (cdr file-list))
1365
1366 (while file-list
1367
1368 (if noselect
1369 ;; Do not select the buffer.
1370 (find-file-noselect (car file-list))
1371
1372 ;; Vertically split off a window of desired size. Upper window will
1373 ;; have SIZE lines. Select lower (larger) window. We split it again.
1374 (select-window (split-window nil size))
1375 (find-file (car file-list)))
1376
1377 ;; Decrement.
1378 (setq file-list (cdr file-list)))))
1379
1380\f
b578f267 1381;;; MISCELLANEOUS COMMANDS.
cb3fe1f0 1382
9572a9dd
KH
1383;;; Run man on files.
1384
cb3fe1f0 1385(defun dired-man ()
9572a9dd 1386 "Run man on this file. Display old buffer if buffer name matches filename.
6fbad7af 1387Uses `man.el' of \\[manual-entry] fame."
cb3fe1f0 1388 (interactive)
685ff9f8 1389 (require 'man)
ecd69427
JL
1390 (let* ((file (dired-get-filename))
1391 (manual-program (replace-regexp-in-string "\\*" "%s"
1392 (dired-guess-shell-command
1393 "Man command: " (list file)))))
685ff9f8 1394 (Man-getpage-in-background file)))
cb3fe1f0
RS
1395
1396;;; Run Info on files.
1397
1398(defun dired-info ()
1399 "Run info on this file."
1400 (interactive)
1401 (info (dired-get-filename)))
1402
1403;;; Run mail on mail folders.
1404
670d3fce
RF
1405;; Avoid compiler warning.
1406(eval-when-compile
1407 (when (not (fboundp 'vm-visit-folder))
1408 (defun vm-visit-folder (file &optional arg)
1409 nil)))
9572a9dd 1410
cb3fe1f0
RS
1411(defun dired-vm (&optional read-only)
1412 "Run VM on this file.
1413With prefix arg, visit folder read-only (this requires at least VM 5).
1414See also variable `dired-vm-read-only-folders'."
1415 (interactive "P")
1416 (let ((dir (dired-current-directory))
1417 (fil (dired-get-filename)))
1418 ;; take care to supply 2nd arg only if requested - may still run VM 4!
1419 (cond (read-only (vm-visit-folder fil t))
1420 ((eq t dired-vm-read-only-folders) (vm-visit-folder fil t))
1421 ((null dired-vm-read-only-folders) (vm-visit-folder fil))
1422 (t (vm-visit-folder fil (not (file-writable-p fil)))))
1423 ;; so that pressing `v' inside VM does prompt within current directory:
1424 (set (make-local-variable 'vm-folder-directory) dir)))
1425
1426(defun dired-rmail ()
1427 "Run RMAIL on this file."
1428 (interactive)
1429 (rmail (dired-get-filename)))
1430
1431(defun dired-do-run-mail ()
1432 "If `dired-bind-vm' is t, then function `dired-vm', otherwise `dired-rmail'."
1433 (interactive)
1434 (if dired-bind-vm
1435 ;; Read mail folder using vm.
1436 (dired-vm)
1437 ;; Read mail folder using rmail.
1438 (dired-rmail)))
1439
1440\f
b578f267 1441;;; MISCELLANEOUS INTERNAL FUNCTIONS.
cb3fe1f0 1442
552939e4 1443(declare-function dired-old-find-buffer-nocreate "dired-x")
e637bdf8 1444
cb3fe1f0
RS
1445(or (fboundp 'dired-old-find-buffer-nocreate)
1446 (fset 'dired-old-find-buffer-nocreate
1447 (symbol-function 'dired-find-buffer-nocreate)))
1448
9572a9dd 1449;;; REDEFINE.
cb3fe1f0 1450;;; Redefines dired.el's version of `dired-find-buffer-nocreate'
ac1ce341 1451(defun dired-find-buffer-nocreate (dirname &optional mode)
10774fb5
KH
1452 (if (and dired-find-subdir
1453 ;; don't try to find a wildcard as a subdirectory
1454 (string-equal dirname (file-name-directory dirname)))
cb3fe1f0 1455 (let* ((cur-buf (current-buffer))
10774fb5 1456 (buffers (nreverse
12c38283 1457 (dired-buffers-for-dir (expand-file-name dirname))))
10774fb5
KH
1458 (cur-buf-matches (and (memq cur-buf buffers)
1459 ;; wildcards must match, too:
1460 (equal dired-directory dirname))))
1461 ;; We don't want to switch to the same buffer---
1462 (setq buffers (delq cur-buf buffers));;need setq with delq
1463 (or (car (sort buffers (function dired-buffer-more-recently-used-p)))
1464 ;; ---unless it's the only possibility:
1465 (and cur-buf-matches cur-buf)))
ac1ce341 1466 (dired-old-find-buffer-nocreate dirname mode)))
cb3fe1f0
RS
1467
1468;; This should be a builtin
1469(defun dired-buffer-more-recently-used-p (buffer1 buffer2)
1470 "Return t if BUFFER1 is more recently used than BUFFER2."
1471 (if (equal buffer1 buffer2)
1472 nil
1473 (let ((more-recent nil)
1474 (list (buffer-list)))
1475 (while (and list
1476 (not (setq more-recent (equal buffer1 (car list))))
1477 (not (equal buffer2 (car list))))
1478 (setq list (cdr list)))
1479 more-recent)))
1480
1481;;; Same thing as `dired-buffers-for-dir' of dired.el? - lrd 11/23/93
1482;;; (defun dired-buffers-for-dir-exact (dir)
1483;;; ;; Return a list of buffers that dired DIR (a directory or wildcard)
1484;;; ;; at top level, or as subdirectory.
1485;;; ;; Top level matches must match the wildcard part too, if any.
1486;;; ;; The list is in reverse order of buffer creation, most recent last.
1487;;; ;; As a side effect, killed dired buffers for DIR are removed from
1488;;; ;; dired-buffers.
1489;;; (let ((alist dired-buffers) result elt)
1490;;; (while alist
1491;;; (setq elt (car alist)
1492;;; alist (cdr alist))
1493;;; (let ((buf (cdr elt)))
1494;;; (if (buffer-name buf)
1495;;; ;; Top level must match exactly against dired-directory in
1496;;; ;; case one of them is a wildcard.
1497;;; (if (or (equal dir (save-excursion (set-buffer buf)
1498;;; dired-directory))
1499;;; (assoc dir (save-excursion (set-buffer buf)
1500;;; dired-subdir-alist)))
1501;;; (setq result (cons buf result)))
1502;;; ;; else buffer is killed - clean up:
1503;;; (setq dired-buffers (delq elt dired-buffers)))))
1504;;; result))
1505
9572a9dd 1506;;; REDEFINE.
cb3fe1f0
RS
1507;;; Redefines dired.el's version of `dired-initial-position'
1508(defun dired-initial-position (dirname)
b847eb8c
DL
1509 "Where point should go in a new listing of DIRNAME.
1510Point assumed at beginning of new subdir line.
6fbad7af 1511You may redefine this function as you wish, e.g. like in `dired-x.el'."
cb3fe1f0
RS
1512 (end-of-line)
1513 (if dired-find-subdir (dired-goto-subdir dirname)) ; new
1514 (if dired-trivial-filenames (dired-goto-next-nontrivial-file)))
1515
1516\f
1517;; Does anyone use this? - lrd 6/29/93.
44c816da 1518;; Apparently people do use it. - lrd 12/22/97.
cb3fe1f0
RS
1519(defun dired-mark-sexp (predicate &optional unflag-p)
1520 "Mark files for which PREDICATE returns non-nil.
1521With a prefix arg, unflag those files instead.
1522
1523PREDICATE is a lisp expression that can refer to the following symbols:
1524
1525 inode [integer] the inode of the file (only for ls -i output)
1526 s [integer] the size of the file for ls -s output
34ff2275 1527 (usually in blocks or, with -k, in KByte)
cb3fe1f0
RS
1528 mode [string] file permission bits, e.g. \"-rw-r--r--\"
1529 nlink [integer] number of links to file
1530 uid [string] owner
1531 gid [string] group (If the gid is not displayed by ls,
1532 this will still be set (to the same as uid))
1533 size [integer] file size in bytes
1534 time [string] the time that ls displays, e.g. \"Feb 12 14:17\"
1535 name [string] the name of the file
1536 sym [string] if file is a symbolic link, the linked-to name, else \"\"
1537
1538For example, use
1539
1540 (equal 0 size)
1541
1542to mark all zero length files."
1543 ;; Using sym="" instead of nil avoids the trap of
1544 ;; (string-match "foo" sym) into which a user would soon fall.
1545 ;; Give `equal' instead of `=' in the example, as this works on
1546 ;; integers and strings.
1547 (interactive "xMark if (lisp expr): \nP")
1548 (message "%s" predicate)
1549 (let ((dired-marker-char (if unflag-p ?\040 dired-marker-char))
1550 inode s mode nlink uid gid size time name sym)
1551 (dired-mark-if
1552 (save-excursion
1553 (and
1554 ;; Sets vars
1555 ;; inode s mode nlink uid gid size time name sym
1556
1557 ;; according to current file line. Returns t for success, nil if
1558 ;; there is no file line. Upon success, all variables are set, either
1559 ;; to nil or the appropriate value, so they need not be initialized.
1560 ;; Moves point within the current line.
1561 (if (dired-move-to-filename)
1562 (let (pos
1563 (mode-len 10) ; length of mode string
1564 ;; like in dired.el, but with subexpressions \1=inode, \2=s:
1565 (dired-re-inode-size "\\s *\\([0-9]*\\)\\s *\\([0-9]*\\) ?"))
1566 (beginning-of-line)
1567 (forward-char 2)
1568 (if (looking-at dired-re-inode-size)
1569 (progn
1570 (goto-char (match-end 0))
027a4b6b
JB
1571 (setq inode (string-to-number (buffer-substring (match-beginning 1)
1572 (match-end 1)))
1573 s (string-to-number (buffer-substring (match-beginning 2)
1574 (match-end 2)))))
cb3fe1f0
RS
1575 (setq inode nil
1576 s nil))
1577 (setq mode (buffer-substring (point) (+ mode-len (point))))
1578 (forward-char mode-len)
1579 (setq nlink (read (current-buffer)))
44c816da 1580 ;; Karsten Wenger <kw@cis.uni-muenchen.de> fixed uid.
b847eb8c
DL
1581 (setq uid (buffer-substring (+ (point) 1)
1582 (progn (forward-word 1) (point))))
9bc260cf 1583 (re-search-forward directory-listing-before-filename-regexp)
cb3fe1f0
RS
1584 (goto-char (match-beginning 1))
1585 (forward-char -1)
027a4b6b
JB
1586 (setq size (string-to-number (buffer-substring (save-excursion
1587 (backward-word 1)
1588 (setq pos (point)))
1589 (point))))
cb3fe1f0
RS
1590 (goto-char pos)
1591 (backward-word 1)
1592 ;; if no gid is displayed, gid will be set to uid
1593 ;; but user will then not reference it anyway in PREDICATE.
b847eb8c
DL
1594 (setq gid (buffer-substring (save-excursion
1595 (forward-word 1) (point))
cb3fe1f0
RS
1596 (point))
1597 time (buffer-substring (match-beginning 1)
1598 (1- (dired-move-to-filename)))
1599 name (buffer-substring (point)
b847eb8c
DL
1600 (or
1601 (dired-move-to-end-of-filename t)
1602 (point)))
cb3fe1f0
RS
1603 sym (progn
1604 (if (looking-at " -> ")
b847eb8c
DL
1605 (buffer-substring
1606 (progn (forward-char 4) (point))
1607 (progn (end-of-line) (point)))
cb3fe1f0
RS
1608 "")))
1609 t)
1610 nil)
1611 (eval predicate)))
1612 (format "'%s file" predicate))))
1613
1614\f
b578f267 1615;;; FIND FILE AT POINT.
cb3fe1f0 1616
ccb1d39a 1617(defvar dired-x-hands-off-my-keys t
b847eb8c 1618 "*Non-nil means don't bind `dired-x-find-file' over `find-file' on keyboard.
ccb1d39a 1619Similarly for `dired-x-find-file-other-window' over `find-file-other-window'.
6fbad7af 1620If you change this variable after `dired-x.el' is loaded then do
ccb1d39a
RS
1621\\[dired-x-bind-find-file].")
1622
1623;;; Bind `dired-x-find-file{-other-window}' over wherever
1624;;; `find-file{-other-window}' is bound?
1625(defun dired-x-bind-find-file ()
1626 "Bind `dired-x-find-file' in place of `find-file' \(or reverse\).
1627Similarly for `dired-x-find-file-other-window' and `find-file-other-window'.
1628Binding direction based on `dired-x-hands-off-my-keys'.
6fbad7af 1629This function is part of `after-init-hook'."
ccb1d39a
RS
1630 (interactive)
1631 (if (interactive-p)
1632 (setq dired-x-hands-off-my-keys
1633 (not (y-or-n-p "Bind dired-x-find-file over find-file? "))))
1634 (cond ((not dired-x-hands-off-my-keys)
1635 (substitute-key-definition 'find-file
1636 'dired-x-find-file
1637 (current-global-map))
1638 (substitute-key-definition 'find-file-other-window
1639 'dired-x-find-file-other-window
1640 (current-global-map)))
1641 (t
1642 (substitute-key-definition 'dired-x-find-file
1643 'find-file
1644 (current-global-map))
1645 (substitute-key-definition 'dired-x-find-file-other-window
1646 'find-file-other-window
1647 (current-global-map))))
1648 ;; Clear mini-buffer.
1649 (message nil))
1650
1651;;; Now call it so binding is correct and put on `after-init-hook' in case
1652;;; user changes binding.
1653(dired-x-bind-find-file)
1654(add-hook 'after-init-hook 'dired-x-bind-find-file)
1655
1656(defun dired-x-find-file (filename)
1657 "Edit file FILENAME.
1658May create a new window, or reuse an existing one.
1659See the function `display-buffer'.
1660
1661Identical to `find-file' except when called interactively, with a prefix arg
6fbad7af
JB
1662\(e.g., \\[universal-argument]\), in which case it guesses filename near point.
1663Useful for editing file mentioned in buffer you are viewing,
1664or to test if that file exists. Use minibuffer after snatching filename."
ccb1d39a
RS
1665 (interactive (list (read-filename-at-point "Find file: ")))
1666 (find-file (expand-file-name filename)))
1667
1668(defun dired-x-find-file-other-window (filename)
1669 "Edit file FILENAME, in another window.
1670May create a new window, or reuse an existing one.
1671See the function `display-buffer'.
1672
1673Identical to `find-file-other-window' except when called interactively, with a
6fbad7af
JB
1674prefix arg \(e.g., \\[universal-argument]\), in which case it guesses filename near point.
1675Useful for editing file mentioned in buffer you are viewing,
1676or to test if that file exists. Use minibuffer after snatching filename."
ccb1d39a
RS
1677 (interactive (list (read-filename-at-point "Find file: ")))
1678 (find-file-other-window (expand-file-name filename)))
1679
1680;;; Internal functions.
cb3fe1f0 1681
1e56daa5 1682;; Fixme: This should probably use `thing-at-point'. -- fx
f53a06c3 1683(defun dired-filename-at-point ()
b847eb8c
DL
1684 "Get the filename closest to point, but do not change position.
1685Has a preference for looking backward when not directly on a symbol. Not
1686perfect - point must be in middle of or end of filename."
cb3fe1f0 1687
f53a06c3 1688 (let ((filename-chars "-.[:alnum:]_/:$+@")
6b622862 1689 start end filename prefix)
cb3fe1f0
RS
1690
1691 (save-excursion
1692 ;; First see if just past a filename.
1693 (if (not (eobp))
1694 (if (looking-at "[] \t\n[{}()]") ; whitespace or some parens
1695 (progn
1696 (skip-chars-backward " \n\t\r({[]})")
1697 (if (not (bobp))
1698 (backward-char 1)))))
9572a9dd 1699
cb3fe1f0
RS
1700 (if (string-match (concat "[" filename-chars "]")
1701 (char-to-string (following-char)))
1702 (progn
1e56daa5
DL
1703 (if (re-search-backward (concat "[^" filename-chars "]") nil t)
1704 (forward-char)
1705 (goto-char (point-min)))
cb3fe1f0 1706 (setq start (point))
6b622862 1707 (setq prefix
1e56daa5
DL
1708 (and (string-match
1709 "^\\w+@"
1710 (buffer-substring start (line-beginning-position)))
6b622862
GM
1711 "/"))
1712 (goto-char start)
cb3fe1f0
RS
1713 (if (string-match "[/~]" (char-to-string (preceding-char)))
1714 (setq start (1- start)))
1e56daa5 1715 (re-search-forward (concat "\\=[" filename-chars "]*") nil t))
cb3fe1f0
RS
1716
1717 (error "No file found around point!"))
1718
9572a9dd 1719 ;; Return string.
6b622862 1720 (expand-file-name (concat prefix (buffer-substring start (point)))))))
cb3fe1f0 1721
ccb1d39a 1722(defun read-filename-at-point (prompt)
b847eb8c
DL
1723 "Return filename prompting with PROMPT with completion.
1724If `current-prefix-arg' is non-nil, uses name at point as guess."
ccb1d39a
RS
1725 (if current-prefix-arg
1726 (let ((guess (dired-filename-at-point)))
1727 (read-file-name prompt
1728 (file-name-directory guess)
1729 guess
1730 nil (file-name-nondirectory guess)))
1731 (read-file-name prompt default-directory)))
cb3fe1f0 1732\f
b578f267 1733;;; BUG REPORTS
cb3fe1f0 1734
b847eb8c
DL
1735;; Fixme: get rid of this later.
1736
cb3fe1f0
RS
1737;;; This section is provided for reports. It uses Barry A. Warsaw's
1738;;; reporter.el which is bundled with GNU Emacs v19.
1739
b847eb8c 1740(defconst dired-x-help-address "bug-gnu-emacs@gnu.org"
cb3fe1f0
RS
1741 "Address(es) accepting submission of reports on dired-x.el.")
1742
cb3fe1f0 1743(defconst dired-x-variable-list
9572a9dd 1744 (list
cb3fe1f0
RS
1745 'dired-bind-vm
1746 'dired-vm-read-only-folders
1747 'dired-bind-jump
1748 'dired-bind-info
1749 'dired-bind-man
1750 'dired-find-subdir
1751 'dired-enable-local-variables
1752 'dired-local-variables-file
1753 'dired-guess-shell-gnutar
1754 'dired-guess-shell-gzip-quiet
1755 'dired-guess-shell-znew-switches
1756 'dired-guess-shell-alist-user
1757 'dired-clean-up-buffers-too
ce64e046 1758 'dired-omit-mode
cb3fe1f0
RS
1759 'dired-omit-files
1760 'dired-omit-extensions
1761 )
b847eb8c 1762 "List of variables to be appended to reports sent by `dired-x-submit-report'.")
cb3fe1f0
RS
1763
1764(defun dired-x-submit-report ()
6fbad7af 1765 "Submit via `reporter.el' a bug report on program.
b847eb8c
DL
1766Send report on `dired-x-file' version `dired-x-version,' to
1767`dired-x-maintainer' at address `dired-x-help-address' listing
1768variables `dired-x-variable-list' in the message."
cb3fe1f0
RS
1769 (interactive)
1770
b847eb8c
DL
1771 (reporter-submit-bug-report
1772 dired-x-help-address ; address
1773 "dired-x" ; pkgname
1774 dired-x-variable-list ; varlist
1775 nil nil ; pre-/post-hooks
1776 ""))
cb3fe1f0
RS
1777
1778\f
1779;; As Barry Warsaw would say: "This might be useful..."
1780(provide 'dired-x)
1781
2d29381c 1782;; arch-tag: 71a43ba2-7a00-4793-a028-0613dd7765ae
cb3fe1f0 1783;;; dired-x.el ends here