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