declare smobs in alloc.c
[bpt/emacs.git] / lisp / dired-x.el
CommitLineData
e17d94a5 1;;; dired-x.el --- extra Dired functionality -*- lexical-binding:t -*-
cb3fe1f0 2
5dbc3244 3;; Copyright (C) 1993-1994, 1997, 2001-2014 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
e43273ef
GM
88 (define-key ctl-x-map "\C-j" 'dired-jump)
89 (define-key ctl-x-4-map "\C-j" 'dired-jump-other-window))
90 (if (eq 'dired-jump (lookup-key ctl-x-map "\C-j"))
91 (define-key ctl-x-map "\C-j" nil))
92 (if (eq 'dired-jump-other-window (lookup-key ctl-x-4-map "\C-j"))
93 (define-key ctl-x-4-map "\C-j" nil))))
286c247d
RS
94 :group 'dired-keys)
95
96(defcustom dired-bind-man t
cedf5c9d 97 "Non-nil means bind `dired-man' to \"N\" in Dired, otherwise do not.
da5e0ce4
GM
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
cedf5c9d 109 "Non-nil means bind `dired-info' to \"I\" in Dired, otherwise do not.
da5e0ce4
GM
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
e5bd0a28
SM
135;; For backward compatibility
136(define-obsolete-variable-alias 'dired-omit-files-p 'dired-omit-mode "22.1")
ce64e046 137(define-minor-mode dired-omit-mode
06e21633
CY
138 "Toggle omission of uninteresting files in Dired (Dired-Omit mode).
139With a prefix argument ARG, enable Dired-Omit mode if ARG is
140positive, and disable it otherwise. If called from Lisp, enable
141the mode if ARG is omitted or nil.
2223a1b3 142
06e21633
CY
143Dired-Omit mode is a buffer-local minor mode. When enabled in a
144Dired buffer, Dired does not list files whose filenames match
145regexp `dired-omit-files', nor files ending with extensions in
146`dired-omit-extensions'.
2223a1b3 147
06e21633
CY
148To enable omitting in every Dired buffer, you can put this in
149your init file:
150
151 (add-hook 'dired-mode-hook (lambda () (dired-omit-mode)))
2223a1b3
JL
152
153See Info node `(dired-x) Omitting Variables' for more information."
ce64e046
LH
154 :group 'dired-x
155 (if dired-omit-mode
156 ;; This will mention how many lines were omitted:
157 (let ((dired-omit-size-limit nil)) (dired-omit-expunge))
158 (revert-buffer)))
159
817b48a7
GM
160(put 'dired-omit-mode 'safe-local-variable 'booleanp)
161
99358b97 162(defcustom dired-omit-files "^\\.?#\\|^\\.$\\|^\\.\\.$"
9201cc28 163 "Filenames matching this regexp will not be displayed.
ce64e046 164This only has effect when `dired-omit-mode' is t. See interactive function
cedf5c9d 165`dired-omit-mode' (\\[dired-omit-mode]) and variable
99358b97
RS
166`dired-omit-extensions'. The default is to omit `.', `..', auto-save
167files and lock files."
286c247d
RS
168 :type 'regexp
169 :group 'dired-x)
cb3fe1f0 170
f754f898
TH
171(defcustom dired-omit-verbose t
172 "When non-nil, show messages when omitting files.
173When nil, don't show messages."
2bed3f04 174 :version "24.1"
f754f898
TH
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
cedf5c9d 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
3b922c70 243(define-key dired-mode-map "\C-x\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.
736b5829
GM
333A `.' is *not* automatically prepended to the string entered.
334EXTENSION may also be a list of extensions instead of a single one.
335Optional MARKER-CHAR is marker to use."
cb3fe1f0
RS
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)
cedf5c9d 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)
cedf5c9d
JB
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.
cedf5c9d 411In case the proper Dired file line cannot be found, refresh the dired
f5d6548a 412buffer and try again.
cedf5c9d 413When OTHER-WINDOW is non-nil, jump to Dired buffer in other window.
f5d6548a
JL
414Interactively with prefix argument, read FILE-NAME and
415move to its line in dired."
416 (interactive
417 (list nil (and current-prefix-arg
cedf5c9d 418 (read-file-name "Jump to Dired file: "))))
f5d6548a 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
cedf5c9d 448 (read-file-name "Jump to Dired file: "))))
f5d6548a 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)
cedf5c9d 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
cedf5c9d 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 557 (interactive
5dbc3244
GM
558 (list (read-regexp
559 "Mark unmarked files matching regexp (default all): "
560 nil 'dired-regexp-history)
ddb8b596 561 nil current-prefix-arg nil))
6fbad7af 562 (let ((dired-marker-char (if unflag-p ?\s dired-marker-char)))
cb3fe1f0
RS
563 (dired-mark-if
564 (and
565 ;; not already marked
70f1b5e8 566 (looking-at-p " ")
cb3fe1f0
RS
567 ;; uninteresting
568 (let ((fn (dired-get-filename localp t)))
70f1b5e8 569 (and fn (string-match-p regexp fn))))
cb3fe1f0
RS
570 msg)))
571
cb3fe1f0 572\f
b578f267 573;;; VIRTUAL DIRED MODE.
cb3fe1f0 574
efcb74f6 575;; For browsing `ls -lR' listings in a dired-like fashion.
cb3fe1f0 576
6fbad7af 577(defalias 'virtual-dired 'dired-virtual)
cb3fe1f0
RS
578(defun dired-virtual (dirname &optional switches)
579 "Put this buffer into Virtual Dired mode.
580
581In Virtual Dired mode, all commands that do not actually consult the
582filesystem will work.
583
584This is useful if you want to peruse and move around in an ls -lR
585output file, for example one you got from an ftp server. With
cedf5c9d
JB
586ange-ftp, you can even Dired a directory containing an ls-lR file,
587visit that file and turn on Virtual Dired mode. But don't try to save
cb3fe1f0
RS
588this file, as dired-virtual indents the listing and thus changes the
589buffer.
590
591If you have save a Dired buffer in a file you can use \\[dired-virtual] to
592resume it in a later session.
593
6fbad7af
JB
594Type \\<dired-mode-map>\\[revert-buffer] \
595in the Virtual Dired buffer and answer `y' to convert
cedf5c9d 596the virtual to a real Dired buffer again. You don't have to do this, though:
6fbad7af 597you can relist single subdirs using \\[dired-do-redisplay]."
cb3fe1f0
RS
598
599 ;; DIRNAME is the top level directory of the buffer. It will become
600 ;; its `default-directory'. If nil, the old value of
601 ;; default-directory is used.
602
603 ;; Optional SWITCHES are the ls switches to use.
604
605 ;; Shell wildcards will be used if there already is a `wildcard'
606 ;; line in the buffer (thus it is a saved Dired buffer), but there
607 ;; is no other way to get wildcards. Insert a `wildcard' line by
608 ;; hand if you want them.
609
610 (interactive
611 (list (read-string "Virtual Dired directory: " (dired-virtual-guess-dir))))
612 (goto-char (point-min))
70f1b5e8 613 (or (looking-at-p " ")
cb3fe1f0
RS
614 ;; if not already indented, do it now:
615 (indent-region (point-min) (point-max) 2))
616 (or dirname (setq dirname default-directory))
617 (setq dirname (expand-file-name (file-name-as-directory dirname)))
618 (setq default-directory dirname) ; contains no wildcards
619 (let ((wildcard (save-excursion
620 (goto-char (point-min))
621 (forward-line 1)
622 (and (looking-at "^ wildcard ")
623 (buffer-substring (match-end 0)
da5e0ce4 624 (line-end-position))))))
cb3fe1f0
RS
625 (if wildcard
626 (setq dirname (expand-file-name wildcard default-directory))))
627 ;; If raw ls listing (not a saved old dired buffer), give it a
628 ;; decent subdir headerline:
629 (goto-char (point-min))
70f1b5e8 630 (or (looking-at-p dired-subdir-regexp)
e8425548 631 (insert " "
fc50a3be
MY
632 (directory-file-name (file-name-directory default-directory))
633 ":\n"))
cb3fe1f0
RS
634 (dired-mode dirname (or switches dired-listing-switches))
635 (setq mode-name "Virtual Dired"
636 revert-buffer-function 'dired-virtual-revert)
637 (set (make-local-variable 'dired-subdir-alist) nil)
638 (dired-build-subdir-alist)
639 (goto-char (point-min))
640 (dired-initial-position dirname))
641
642(defun dired-virtual-guess-dir ()
b847eb8c 643 "Guess and return appropriate working directory of this buffer.
4e6ef391 644The buffer is assumed to be in Dired or ls -lR format. The guess is
b847eb8c
DL
645based upon buffer contents. If nothing could be guessed, returns
646nil."
cb3fe1f0
RS
647
648 (let ((regexp "^\\( \\)?\\([^ \n\r]*\\)\\(:\\)[\n\r]")
649 (subexpr 2))
650 (goto-char (point-min))
651 (cond ((looking-at regexp)
652 ;; If a saved dired buffer, look to which dir and
653 ;; perhaps wildcard it belongs:
654 (let ((dir (buffer-substring (match-beginning subexpr)
655 (match-end subexpr))))
656 (file-name-as-directory dir)))
657 ;; Else no match for headerline found. It's a raw ls listing.
658 ;; In raw ls listings the directory does not have a headerline
659 ;; try parent of first subdir, if any
660 ((re-search-forward regexp nil t)
661 (file-name-directory
662 (directory-file-name
663 (file-name-as-directory
664 (buffer-substring (match-beginning subexpr)
665 (match-end subexpr))))))
666 (t ; if all else fails
667 nil))))
668
669
06b60517 670(defun dired-virtual-revert (&optional _arg _noconfirm)
cb3fe1f0
RS
671 (if (not
672 (y-or-n-p "Cannot revert a Virtual Dired buffer - switch to Real Dired mode? "))
b847eb8c 673 (error "Cannot revert a Virtual Dired buffer")
cb3fe1f0
RS
674 (setq mode-name "Dired"
675 revert-buffer-function 'dired-revert)
676 (revert-buffer)))
677
678;; A zero-arg version of dired-virtual.
cb3fe1f0 679(defun dired-virtual-mode ()
6fbad7af 680 "Put current buffer into Virtual Dired mode (see `dired-virtual').
b94d76ae 681Useful on `magic-mode-alist' with the regexp
cb3fe1f0 682
b94d76ae 683 \"^ \\\\(/[^ /]+\\\\)+/?:$\"
cb3fe1f0 684
cedf5c9d 685to put saved Dired buffers automatically into Virtual Dired mode.
cb3fe1f0 686
b94d76ae 687Also useful for `auto-mode-alist' like this:
cb3fe1f0 688
b94d76ae
GM
689 (add-to-list 'auto-mode-alist
690 '(\"[^/]\\\\.dired\\\\'\" . dired-virtual-mode))"
cb3fe1f0
RS
691 (interactive)
692 (dired-virtual (dired-virtual-guess-dir)))
693
694\f
b578f267 695;;; SMART SHELL.
cb3fe1f0 696
efcb74f6
SM
697;; An Emacs buffer can have but one working directory, stored in the
698;; buffer-local variable `default-directory'. A Dired buffer may have
699;; several subdirectories inserted, but still has but one working directory:
700;; that of the top level Dired directory in that buffer. For some commands
701;; it is appropriate that they use the current Dired directory instead of
702;; `default-directory', e.g., `find-file' and `compile'. This is a general
703;; mechanism is provided for special handling of the working directory in
704;; special major modes.
cb3fe1f0 705
da5e0ce4
GM
706(define-obsolete-variable-alias 'default-directory-alist
707 'dired-default-directory-alist "24.1")
708
cb3fe1f0
RS
709;; It's easier to add to this alist than redefine function
710;; default-directory while keeping the old information.
da5e0ce4 711(defconst dired-default-directory-alist
cb3fe1f0
RS
712 '((dired-mode . (if (fboundp 'dired-current-directory)
713 (dired-current-directory)
714 default-directory)))
b847eb8c 715 "Alist of major modes and their opinion on `default-directory'.
5dedeef2
GM
716Each element has the form (MAJOR . EXPRESSION).
717The function `dired-default-directory' evaluates EXPRESSION to
718determine a default directory.")
719
720(put 'dired-default-directory-alist 'risky-local-variable t) ; gets eval'd
2777ccbf
GM
721(make-obsolete-variable 'dired-default-directory-alist
722 "this feature is due to be removed." "24.1")
cb3fe1f0 723
b847eb8c 724(defun dired-default-directory ()
5dedeef2
GM
725 "Return the `dired-default-directory-alist' entry for the current major-mode.
726If none, return `default-directory'."
59f7af81
CY
727 ;; It looks like this was intended to be something of a "general"
728 ;; feature, but it only ever seems to have been used in
729 ;; dired-smart-shell-command, and doesn't seem worth keeping around.
730 (declare (obsolete nil "24.1"))
da5e0ce4 731 (or (eval (cdr (assq major-mode dired-default-directory-alist)))
cb3fe1f0
RS
732 default-directory))
733
d3a89b9e 734(defun dired-smart-shell-command (command &optional output-buffer error-buffer)
6fbad7af 735 "Like function `shell-command', but in the current Virtual Dired directory."
d3a89b9e
JL
736 (interactive
737 (list
57199d9b
JL
738 (read-shell-command "Shell command: " nil nil
739 (cond
740 (buffer-file-name (file-relative-name buffer-file-name))
741 ((eq major-mode 'dired-mode) (dired-get-filename t t))))
d3a89b9e
JL
742 current-prefix-arg
743 shell-command-default-error-buffer))
dbb17c4e
GM
744 (let ((default-directory (or (and (eq major-mode 'dired-mode)
745 (dired-current-directory))
746 default-directory)))
d3a89b9e 747 (shell-command command output-buffer error-buffer)))
cb3fe1f0
RS
748
749\f
b578f267 750;;; LOCAL VARIABLES FOR DIRED BUFFERS.
cb3fe1f0 751
817b48a7
GM
752;; Brief Description (This feature is obsolete as of Emacs 24.1)
753;;
efcb74f6 754;; * `dired-extra-startup' is part of the `dired-mode-hook'.
817b48a7 755;;
efcb74f6 756;; * `dired-extra-startup' calls `dired-hack-local-variables'
817b48a7 757;;
efcb74f6 758;; * `dired-hack-local-variables' checks the value of
817b48a7
GM
759;; `dired-local-variables-file'
760;;
efcb74f6 761;; * Check if `dired-local-variables-file' is a non-nil string and is a
817b48a7
GM
762;; filename found in the directory of the Dired Buffer being created.
763;;
efcb74f6 764;; * If `dired-local-variables-file' satisfies the above, then temporarily
817b48a7
GM
765;; include it in the Dired Buffer at the bottom.
766;;
efcb74f6 767;; * Set `enable-local-variables' temporarily to the user variable
817b48a7
GM
768;; `dired-enable-local-variables' and run `hack-local-variables' on the
769;; Dired Buffer.
cb3fe1f0 770
461b69ae 771(defcustom dired-local-variables-file (convert-standard-filename ".dired")
cedf5c9d 772 "Filename, as string, containing local Dired buffer variables to be hacked.
cb3fe1f0 773If this file found in current directory, then it will be inserted into dired
6fbad7af
JB
774buffer and `hack-local-variables' will be run. See Info node
775`(emacs)File Variables' for more information on local variables.
461b69ae
GM
776See also `dired-enable-local-variables'."
777 :type 'file
778 :group 'dired)
cb3fe1f0 779
817b48a7
GM
780(make-obsolete-variable 'dired-local-variables-file 'dir-locals-file "24.1")
781
cb3fe1f0 782(defun dired-hack-local-variables ()
cedf5c9d 783 "Evaluate local variables in `dired-local-variables-file' for Dired buffer."
59f7af81 784 (declare (obsolete hack-dir-local-variables-non-file-buffer "24.1"))
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)))
37269466
CY
803 ;; Make sure that the mode line shows the proper information.
804 (dired-sort-set-mode-line))))
cb3fe1f0 805
8889f4e2 806;; Does not seem worth a dedicated command.
6640b281 807;; See the more general features in files-x.el.
9572a9dd 808(defun dired-omit-here-always ()
817b48a7
GM
809 "Create `dir-locals-file' setting `dired-omit-mode' to t in `dired-mode'.
810If in a Dired buffer, reverts it."
59f7af81 811 (declare (obsolete add-dir-local-variable "24.1"))
9572a9dd 812 (interactive)
cb3fe1f0 813 (if (file-exists-p dired-local-variables-file)
817b48a7
GM
814 (error "Old-style dired-local-variables-file `./%s' found;
815replace it with a dir-locals-file `./%s'"
816 dired-local-variables-file
817 dir-locals-file))
818 (if (file-exists-p dir-locals-file)
819 (message "File `./%s' already exists." dir-locals-file)
820 (with-temp-buffer
6640b281
GM
821 (insert "\
822\((dired-mode . ((subdirs . nil)
823 (dired-omit-mode . t))))\n")
817b48a7 824 (write-file dir-locals-file))
cb3fe1f0 825 ;; Run extra-hooks and revert directory.
817b48a7
GM
826 (when (derived-mode-p 'dired-mode)
827 (hack-dir-local-variables-non-file-buffer)
828 (dired-extra-startup)
829 (dired-revert))))
cb3fe1f0
RS
830
831\f
b578f267 832;;; GUESS SHELL COMMAND.
cb3fe1f0 833
efcb74f6 834;; Brief Description:
9572a9dd 835;;;
d6e96966 836;; * `dired-do-shell-command' is bound to `!' by dired.el.
9572a9dd 837;;;
d6e96966
GM
838;; * `dired-guess-shell-command' provides smarter defaults for
839;;; dired-aux.el's `dired-read-shell-command'.
9572a9dd 840;;;
efcb74f6 841;; * `dired-guess-shell-command' calls `dired-guess-default' with list of
cb3fe1f0 842;;; marked files.
9572a9dd 843;;;
efcb74f6 844;; * Parse `dired-guess-shell-alist-user' and
cb3fe1f0
RS
845;;; `dired-guess-shell-alist-default' (in that order) for the first REGEXP
846;;; that matches the first file in the file list.
9572a9dd 847;;;
efcb74f6 848;; * If the REGEXP matches all the entries of the file list then evaluate
c0d79871 849;;; COMMAND, which is either a string or a Lisp expression returning a
cb3fe1f0 850;;; string. COMMAND may be a list of commands.
9572a9dd 851;;;
efcb74f6 852;; * Return this command to `dired-guess-shell-command' which prompts user
747e8ee2 853;;; with it. The list of commands is put into the list of default values.
cb3fe1f0
RS
854;;; If a command is used successfully then it is stored permanently in
855;;; `dired-shell-command-history'.
856
efcb74f6 857;; Guess what shell command to apply to a file.
cb3fe1f0
RS
858(defvar dired-shell-command-history nil
859 "History list for commands that read dired-shell commands.")
860
efcb74f6 861;; Default list of shell commands.
cb3fe1f0 862
efcb74f6
SM
863;; NOTE: Use `gunzip -c' instead of `zcat' on `.gz' files. Some do not
864;; install GNU zip's version of zcat.
cb3fe1f0 865
3ab7ebb9 866(autoload 'Man-support-local-filenames "man")
461b69ae 867
cb3fe1f0
RS
868(defvar dired-guess-shell-alist-default
869 (list
0a906ec3 870 (list "\\.tar\\'"
ca136496
RF
871 '(if dired-guess-shell-gnutar
872 (concat dired-guess-shell-gnutar " xvf")
873 "tar xvf")
874 ;; Extract files into a separate subdirectory
875 '(if dired-guess-shell-gnutar
876 (concat "mkdir " (file-name-sans-extension file)
877 "; " dired-guess-shell-gnutar " -C "
878 (file-name-sans-extension file) " -xvf")
879 (concat "mkdir " (file-name-sans-extension file)
880 "; tar -C " (file-name-sans-extension file) " -xvf"))
881 ;; List archive contents.
882 '(if dired-guess-shell-gnutar
883 (concat dired-guess-shell-gnutar " tvf")
884 "tar tvf"))
cb3fe1f0
RS
885
886 ;; REGEXPS for compressed archives must come before the .Z rule to
887 ;; be recognized:
0a906ec3 888 (list "\\.tar\\.Z\\'"
ca136496
RF
889 ;; Untar it.
890 '(if dired-guess-shell-gnutar
891 (concat dired-guess-shell-gnutar " zxvf")
892 (concat "zcat * | tar xvf -"))
893 ;; Optional conversion to gzip format.
894 '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
895 " " dired-guess-shell-znew-switches))
cb3fe1f0
RS
896
897 ;; gzip'ed archives
0a906ec3 898 (list "\\.t\\(ar\\.\\)?gz\\'"
ca136496
RF
899 '(if dired-guess-shell-gnutar
900 (concat dired-guess-shell-gnutar " zxvf")
901 (concat "gunzip -qc * | tar xvf -"))
902 ;; Extract files into a separate subdirectory
903 '(if dired-guess-shell-gnutar
904 (concat "mkdir " (file-name-sans-extension file)
905 "; " dired-guess-shell-gnutar " -C "
906 (file-name-sans-extension file) " -zxvf")
907 (concat "mkdir " (file-name-sans-extension file)
908 "; gunzip -qc * | tar -C "
909 (file-name-sans-extension file) " -xvf -"))
910 ;; Optional decompression.
911 '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q" ""))
912 ;; List archive contents.
913 '(if dired-guess-shell-gnutar
914 (concat dired-guess-shell-gnutar " ztvf")
915 (concat "gunzip -qc * | tar tvf -")))
ecd69427 916
7ba7b794 917 ;; bzip2'ed archives
0a906ec3 918 (list "\\.t\\(ar\\.bz2\\|bz\\)\\'"
7ba7b794 919 "bunzip2 -c * | tar xvf -"
ca136496
RF
920 ;; Extract files into a separate subdirectory
921 '(concat "mkdir " (file-name-sans-extension file)
922 "; bunzip2 -c * | tar -C "
923 (file-name-sans-extension file) " -xvf -")
7ba7b794 924 ;; Optional decompression.
ca136496 925 "bunzip2")
cb3fe1f0 926
c10e0633 927 ;; xz'ed archives
0a906ec3 928 (list "\\.t\\(ar\\.\\)?xz\\'"
c10e0633
GM
929 "unxz -c * | tar xvf -"
930 ;; Extract files into a separate subdirectory
931 '(concat "mkdir " (file-name-sans-extension file)
932 "; unxz -c * | tar -C "
933 (file-name-sans-extension file) " -xvf -")
934 ;; Optional decompression.
935 "unxz")
936
0a906ec3
GM
937 '("\\.shar\\.Z\\'" "zcat * | unshar")
938 '("\\.shar\\.g?z\\'" "gunzip -qc * | unshar")
cb3fe1f0 939
0a906ec3
GM
940 '("\\.e?ps\\'" "ghostview" "xloadimage" "lpr")
941 (list "\\.e?ps\\.g?z\\'" "gunzip -qc * | ghostview -"
ca136496
RF
942 ;; Optional decompression.
943 '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
0a906ec3 944 (list "\\.e?ps\\.Z\\'" "zcat * | ghostview -"
ca136496
RF
945 ;; Optional conversion to gzip format.
946 '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
947 " " dired-guess-shell-znew-switches))
ecd69427 948
0a906ec3
GM
949 '("\\.patch\\'" "cat * | patch")
950 (list "\\.patch\\.g?z\\'" "gunzip -qc * | patch"
ca136496
RF
951 ;; Optional decompression.
952 '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
0a906ec3 953 (list "\\.patch\\.Z\\'" "zcat * | patch"
ca136496
RF
954 ;; Optional conversion to gzip format.
955 '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
956 " " dired-guess-shell-znew-switches))
cb3fe1f0 957
ecd69427 958 ;; The following four extensions are useful with dired-man ("N" key)
3ab7ebb9
GM
959 ;; FIXME "man ./" does not work with dired-do-shell-command,
960 ;; because there seems to be no way for us to modify the filename,
961 ;; only the command. Hmph. `dired-man' works though.
f25aef2e
GM
962 (list "\\.\\(?:[0-9]\\|man\\)\\'"
963 '(let ((loc (Man-support-local-filenames)))
964 (cond ((eq loc 'man-db) "man -l")
965 ((eq loc 'man) "man ./")
966 (t
967 "cat * | tbl | nroff -man -h | col -b"))))
3ab7ebb9
GM
968 (list "\\.\\(?:[0-9]\\|man\\)\\.g?z\\'"
969 '(let ((loc (Man-support-local-filenames)))
970 (cond ((eq loc 'man-db)
971 "man -l")
972 ((eq loc 'man)
973 "man ./")
f25aef2e 974 (t "gunzip -qc * | tbl | nroff -man -h | col -b")))
ca136496
RF
975 ;; Optional decompression.
976 '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
f25aef2e
GM
977 (list "\\.[0-9]\\.Z\\'"
978 '(let ((loc (Man-support-local-filenames)))
979 (cond ((eq loc 'man-db) "man -l")
980 ((eq loc 'man) "man ./")
981 (t "zcat * | tbl | nroff -man -h | col -b")))
ca136496
RF
982 ;; Optional conversion to gzip format.
983 '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
984 " " dired-guess-shell-znew-switches))
0a906ec3
GM
985 '("\\.pod\\'" "perldoc" "pod2man * | nroff -man")
986
cedf5c9d 987 '("\\.dvi\\'" "xdvi" "dvips") ; preview and printing
0a906ec3
GM
988 '("\\.au\\'" "play") ; play Sun audiofiles
989 '("\\.mpe?g\\'\\|\\.avi\\'" "xine -p")
990 '("\\.ogg\\'" "ogg123")
991 '("\\.mp3\\'" "mpg123")
992 '("\\.wav\\'" "play")
993 '("\\.uu\\'" "uudecode") ; for uudecoded files
994 '("\\.hqx\\'" "mcvert")
995 '("\\.sh\\'" "sh") ; execute shell scripts
996 '("\\.xbm\\'" "bitmap") ; view X11 bitmaps
997 '("\\.gp\\'" "gnuplot")
998 '("\\.p[bgpn]m\\'" "xloadimage")
999 '("\\.gif\\'" "xloadimage") ; view gif pictures
1000 '("\\.tif\\'" "xloadimage")
1001 '("\\.png\\'" "display") ; xloadimage 4.1 doesn't grok PNG
1002 '("\\.jpe?g\\'" "xloadimage")
cedf5c9d 1003 '("\\.fig\\'" "xfig") ; edit fig pictures
0a906ec3
GM
1004 '("\\.out\\'" "xgraph") ; for plotting purposes.
1005 '("\\.tex\\'" "latex" "tex")
1006 '("\\.texi\\(nfo\\)?\\'" "makeinfo" "texi2dvi")
1007 '("\\.pdf\\'" "xpdf")
1008 '("\\.doc\\'" "antiword" "strings")
1009 '("\\.rpm\\'" "rpm -qilp" "rpm -ivh")
1010 '("\\.dia\\'" "dia")
1011 '("\\.mgp\\'" "mgp")
cb3fe1f0
RS
1012
1013 ;; Some other popular archivers.
0a906ec3 1014 (list "\\.zip\\'" "unzip" "unzip -l"
ca136496
RF
1015 ;; Extract files into a separate subdirectory
1016 '(concat "unzip" (if dired-guess-shell-gzip-quiet " -q")
1017 " -d " (file-name-sans-extension file)))
0a906ec3
GM
1018 '("\\.zoo\\'" "zoo x//")
1019 '("\\.lzh\\'" "lharc x")
1020 '("\\.arc\\'" "arc x")
1021 '("\\.shar\\'" "unshar")
1022 '("\\.rar\\'" "unrar x")
1023 '("\\.7z\\'" "7z x")
cb3fe1f0
RS
1024
1025 ;; Compression.
0a906ec3
GM
1026 (list "\\.g?z\\'" '(concat "gunzip" (if dired-guess-shell-gzip-quiet " -q")))
1027 (list "\\.dz\\'" "dictunzip")
1028 (list "\\.bz2\\'" "bunzip2")
1029 (list "\\.xz\\'" "unxz")
1030 (list "\\.Z\\'" "uncompress"
ca136496
RF
1031 ;; Optional conversion to gzip format.
1032 '(concat "znew" (if dired-guess-shell-gzip-quiet " -q")
1033 " " dired-guess-shell-znew-switches))
1034
0a906ec3 1035 '("\\.sign?\\'" "gpg --verify"))
9572a9dd 1036
cb3fe1f0 1037 "Default alist used for shell command guessing.
b847eb8c 1038See `dired-guess-shell-alist-user'.")
cb3fe1f0 1039
b847eb8c
DL
1040(defcustom dired-guess-shell-alist-user nil
1041 "User-defined alist of rules for suggested commands.
1042These rules take precedence over the predefined rules in the variable
cb3fe1f0
RS
1043`dired-guess-shell-alist-default' (to which they are prepended).
1044
1045Each element of this list looks like
1046
cedf5c9d 1047 (REGEXP COMMAND...)
cb3fe1f0 1048
6fbad7af 1049where each COMMAND can either be a string or a Lisp expression that evaluates
d3fc6549
GM
1050to a string. This expression can access the file name as the variable `file'.
1051If several COMMANDs are given, the first one will be the default
cb3fe1f0
RS
1052and the rest will be added temporarily to the history and can be retrieved
1053with \\[previous-history-element] (M-p) .
1054
70ee5ed1
GM
1055The variable `dired-guess-shell-case-fold-search' controls whether
1056REGEXP is matched case-sensitively.
1057
cb3fe1f0
RS
1058You can set this variable in your ~/.emacs. For example, to add rules for
1059`.foo' and `.bar' files, write
1060
cedf5c9d 1061 (setq dired-guess-shell-alist-user
eea84fe5
LMI
1062 '((\"\\\\.foo\\\\'\" \"FOO-COMMAND\")
1063 (\"\\\\.bar\\\\'\"
1064 (if condition
1065 \"BAR-COMMAND-1\"
1066 \"BAR-COMMAND-2\"))))"
b847eb8c
DL
1067 :group 'dired-x
1068 :type '(alist :key-type regexp :value-type (repeat sexp)))
cb3fe1f0 1069
d7af463c
RF
1070(defcustom dired-guess-shell-case-fold-search t
1071 "If non-nil, `dired-guess-shell-alist-default' and
1072`dired-guess-shell-alist-user' are matched case-insensitively."
1073 :group 'dired-x
1074 :type 'boolean)
1075
cb3fe1f0 1076(defun dired-guess-default (files)
8a93078b 1077 "Return a shell command, or a list of commands, appropriate for FILES.
b847eb8c 1078See `dired-guess-shell-alist-user'."
cb3fe1f0 1079
d7af463c 1080 (let* ((case-fold-search dired-guess-shell-case-fold-search)
cb3fe1f0
RS
1081 ;; Prepend the user's alist to the default alist.
1082 (alist (append dired-guess-shell-alist-user
1083 dired-guess-shell-alist-default))
1084 (file (car files))
1085 (flist (cdr files))
1086 elt regexp cmds)
1087
1088 ;; Find the first match in the alist for first file in FILES.
1089 (while alist
1090 (setq elt (car alist)
1091 regexp (car elt)
1092 alist (cdr alist))
70f1b5e8 1093 (if (string-match-p regexp file)
cb3fe1f0
RS
1094 (setq cmds (cdr elt)
1095 alist nil)))
1096
1097 ;; If more than one file, see if all of FILES match regular expression.
1098 (while (and flist
70f1b5e8 1099 (string-match-p regexp (car flist)))
cb3fe1f0 1100 (setq flist (cdr flist)))
9572a9dd 1101
cb3fe1f0
RS
1102 ;; If flist is still non-nil, then do not guess since this means that not
1103 ;; all the files in FILES were matched by the regexp.
1104 (setq cmds (and (not flist) cmds))
1105
9572a9dd
KH
1106 ;; Return commands or nil if flist is still non-nil.
1107 ;; Evaluate the commands in order that any logical testing will be done.
adbb5a40 1108 (if (cdr cmds)
d3fc6549
GM
1109 (delete-dups (mapcar (lambda (cmd) (eval cmd `((file . ,file)))) cmds))
1110 (eval (car cmds) `((file . ,file)))))) ; single command
cb3fe1f0
RS
1111
1112(defun dired-guess-shell-command (prompt files)
b847eb8c 1113 "Ask user with PROMPT for a shell command, guessing a default from FILES."
cb3fe1f0 1114 (let ((default (dired-guess-default files))
5420b514 1115 default-list val)
cb3fe1f0
RS
1116 (if (null default)
1117 ;; Nothing to guess
c521381a 1118 (read-shell-command prompt nil 'dired-shell-command-history)
178fb95d 1119 (setq prompt (replace-regexp-in-string ": $" " " prompt))
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 1129 ;; Put the first guess in the prompt but not in the initial value.
178fb95d 1130 (setq prompt (concat prompt (format "[%s]: " default)))
5420b514 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:
e17d94a5 1189 (dotimes (_ 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
cedf5c9d 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 ()
044a9eac
CY
1348 "Visit the current file as a mailbox, using VM or RMAIL.
1349Prompt for confirmation first; if the user says yes, call
1350`dired-vm' if `dired-bind-vm' is non-nil, `dired-rmail'
1351otherwise."
cb3fe1f0 1352 (interactive)
044a9eac
CY
1353 (let ((file (dired-get-filename t)))
1354 (if dired-bind-vm
1355 (if (y-or-n-p (concat "Visit `" file
1356 "' as a mail folder with VM?"))
1357 (dired-vm))
1358 ;; Read mail folder using rmail.
1359 (if (y-or-n-p (concat "Visit `" file
1360 "' as a mailbox with RMAIL?"))
1361 (dired-rmail)))))
cb3fe1f0
RS
1362
1363\f
b578f267 1364;;; MISCELLANEOUS INTERNAL FUNCTIONS.
cb3fe1f0 1365
cb3fe1f0
RS
1366;; This should be a builtin
1367(defun dired-buffer-more-recently-used-p (buffer1 buffer2)
da5e0ce4
GM
1368 "Return t if BUFFER1 is more recently used than BUFFER2.
1369Considers buffers closer to the car of `buffer-list' to be more recent."
1370 (and (not (equal buffer1 buffer2))
1371 (memq buffer1 (buffer-list))
1372 (not (memq buffer1 (memq buffer2 (buffer-list))))))
cb3fe1f0 1373
efcb74f6
SM
1374;; Same thing as `dired-buffers-for-dir' of dired.el? - lrd 11/23/93
1375;; (defun dired-buffers-for-dir-exact (dir)
1376;; ;; Return a list of buffers that dired DIR (a directory or wildcard)
1377;; ;; at top level, or as subdirectory.
1378;; ;; Top level matches must match the wildcard part too, if any.
1379;; ;; The list is in reverse order of buffer creation, most recent last.
1380;; ;; As a side effect, killed dired buffers for DIR are removed from
1381;; ;; dired-buffers.
1382;; (let ((alist dired-buffers) result elt)
1383;; (while alist
1384;; (setq elt (car alist)
1385;; alist (cdr alist))
1386;; (let ((buf (cdr elt)))
1387;; (if (buffer-name buf)
1388;; ;; Top level must match exactly against dired-directory in
1389;; ;; case one of them is a wildcard.
1390;; (if (or (equal dir (with-current-buffer buf dired-directory))
1391;; (assoc dir (with-current-buffer buf dired-subdir-alist)))
1392;; (setq result (cons buf result)))
1393;; ;; else buffer is killed - clean up:
1394;; (setq dired-buffers (delq elt dired-buffers)))))
1395;; result))
1396
cb3fe1f0
RS
1397\f
1398;; Does anyone use this? - lrd 6/29/93.
44c816da 1399;; Apparently people do use it. - lrd 12/22/97.
06b60517 1400
cb3fe1f0
RS
1401(defun dired-mark-sexp (predicate &optional unflag-p)
1402 "Mark files for which PREDICATE returns non-nil.
a48868a7 1403With a prefix arg, unmark or unflag those files instead.
cb3fe1f0
RS
1404
1405PREDICATE is a lisp expression that can refer to the following symbols:
1406
1407 inode [integer] the inode of the file (only for ls -i output)
1408 s [integer] the size of the file for ls -s output
34ff2275 1409 (usually in blocks or, with -k, in KByte)
cb3fe1f0
RS
1410 mode [string] file permission bits, e.g. \"-rw-r--r--\"
1411 nlink [integer] number of links to file
1412 uid [string] owner
1413 gid [string] group (If the gid is not displayed by ls,
1414 this will still be set (to the same as uid))
1415 size [integer] file size in bytes
1416 time [string] the time that ls displays, e.g. \"Feb 12 14:17\"
1417 name [string] the name of the file
1418 sym [string] if file is a symbolic link, the linked-to name, else \"\"
1419
1420For example, use
1421
1422 (equal 0 size)
1423
1424to mark all zero length files."
1425 ;; Using sym="" instead of nil avoids the trap of
1426 ;; (string-match "foo" sym) into which a user would soon fall.
1427 ;; Give `equal' instead of `=' in the example, as this works on
1428 ;; integers and strings.
1429 (interactive "xMark if (lisp expr): \nP")
1430 (message "%s" predicate)
1431 (let ((dired-marker-char (if unflag-p ?\040 dired-marker-char))
1432 inode s mode nlink uid gid size time name sym)
1433 (dired-mark-if
1434 (save-excursion
1435 (and
1436 ;; Sets vars
1437 ;; inode s mode nlink uid gid size time name sym
1438
1439 ;; according to current file line. Returns t for success, nil if
1440 ;; there is no file line. Upon success, all variables are set, either
1441 ;; to nil or the appropriate value, so they need not be initialized.
1442 ;; Moves point within the current line.
d1be20a1
GM
1443 (dired-move-to-filename)
1444 (let (pos
1445 (mode-len 10) ; length of mode string
1446 ;; like in dired.el, but with subexpressions \1=inode, \2=s:
1447 (dired-re-inode-size "\\s *\\([0-9]*\\)\\s *\\([0-9]*\\) ?"))
1448 (beginning-of-line)
1449 (forward-char 2)
1450 (if (looking-at dired-re-inode-size)
1451 (progn
1452 (goto-char (match-end 0))
1453 (setq inode (string-to-number
1454 (buffer-substring (match-beginning 1)
1455 (match-end 1)))
1456 s (string-to-number
1457 (buffer-substring (match-beginning 2)
1458 (match-end 2)))))
1459 (setq inode nil
1460 s nil))
1461 (setq mode (buffer-substring (point) (+ mode-len (point))))
1462 (forward-char mode-len)
e5e916d8
GM
1463 ;; Skip any extended attributes marker ("." or "+").
1464 (or (looking-at " ")
1465 (forward-char 1))
d1be20a1
GM
1466 (setq nlink (read (current-buffer)))
1467 ;; Karsten Wenger <kw@cis.uni-muenchen.de> fixed uid.
1468 (setq uid (buffer-substring (1+ (point))
1469 (progn (forward-word 1) (point))))
1470 (re-search-forward directory-listing-before-filename-regexp)
1471 (goto-char (match-beginning 1))
1472 (forward-char -1)
1473 (setq size (string-to-number
1474 (buffer-substring (save-excursion
1475 (backward-word 1)
1476 (setq pos (point)))
1477 (point))))
1478 (goto-char pos)
1479 (backward-word 1)
1480 ;; if no gid is displayed, gid will be set to uid
1481 ;; but user will then not reference it anyway in PREDICATE.
1482 (setq gid (buffer-substring (save-excursion
1483 (forward-word 1) (point))
1484 (point))
1485 time (buffer-substring (match-beginning 1)
1486 (1- (dired-move-to-filename)))
1487 name (buffer-substring (point)
1488 (or
1489 (dired-move-to-end-of-filename t)
1490 (point)))
70f1b5e8 1491 sym (if (looking-at-p " -> ")
d1be20a1
GM
1492 (buffer-substring (progn (forward-char 4) (point))
1493 (line-end-position))
1494 ""))
1495 t)
e17d94a5
SM
1496 (eval predicate
1497 `((inode . ,inode)
1498 (s . ,s)
1499 (mode . ,mode)
1500 (nlink . ,nlink)
1501 (uid . ,uid)
1502 (gid . ,gid)
1503 (size . ,size)
1504 (time . ,time)
1505 (name . ,name)
1506 (sym . ,sym)))))
cb3fe1f0
RS
1507 (format "'%s file" predicate))))
1508
1509\f
b578f267 1510;;; FIND FILE AT POINT.
cb3fe1f0 1511
461b69ae 1512(defcustom dired-x-hands-off-my-keys t
d1be20a1
GM
1513 "Non-nil means don't remap `find-file' to `dired-x-find-file'.
1514Similarly for `find-file-other-window' and `dired-x-find-file-other-window'.
461b69ae
GM
1515If you change this variable without using \\[customize] after `dired-x.el'
1516is loaded then call \\[dired-x-bind-find-file]."
1517 :type 'boolean
1518 :initialize 'custom-initialize-default
06b60517
JB
1519 :set (lambda (symbol value)
1520 (set symbol value)
461b69ae
GM
1521 (dired-x-bind-find-file))
1522 :group 'dired-x)
ccb1d39a 1523
ccb1d39a 1524(defun dired-x-bind-find-file ()
d1be20a1 1525 "Bind `dired-x-find-file' in place of `find-file' (or vice-versa).
ccb1d39a 1526Similarly for `dired-x-find-file-other-window' and `find-file-other-window'.
d1be20a1 1527Binding direction based on `dired-x-hands-off-my-keys'."
ccb1d39a 1528 (interactive)
32226619 1529 (if (called-interactively-p 'interactive)
ccb1d39a
RS
1530 (setq dired-x-hands-off-my-keys
1531 (not (y-or-n-p "Bind dired-x-find-file over find-file? "))))
d1be20a1
GM
1532 (define-key (current-global-map) [remap find-file]
1533 (if (not dired-x-hands-off-my-keys) 'dired-x-find-file))
1534 (define-key (current-global-map) [remap find-file-other-window]
1535 (if (not dired-x-hands-off-my-keys) 'dired-x-find-file-other-window)))
1536
1537;; Now call it so binding is correct. This could go in the :initialize
1538;; slot, but then dired-x-bind-find-file has to be defined before the
1539;; defcustom, and we get free variable warnings.
ccb1d39a 1540(dired-x-bind-find-file)
ccb1d39a
RS
1541
1542(defun dired-x-find-file (filename)
1543 "Edit file FILENAME.
d1be20a1
GM
1544Like `find-file', except that when called interactively with a
1545prefix argument, it offers the filename near point as a default."
da5e0ce4 1546 (interactive (list (dired-x-read-filename-at-point "Find file: ")))
d1be20a1 1547 (find-file filename))
ccb1d39a
RS
1548
1549(defun dired-x-find-file-other-window (filename)
1550 "Edit file FILENAME, in another window.
d1be20a1
GM
1551Like `find-file-other-window', except that when called interactively with
1552a prefix argument, when it offers the filename near point as a default."
da5e0ce4 1553 (interactive (list (dired-x-read-filename-at-point "Find file: ")))
d1be20a1 1554 (find-file-other-window filename))
ccb1d39a
RS
1555
1556;;; Internal functions.
cb3fe1f0 1557
1e56daa5 1558;; Fixme: This should probably use `thing-at-point'. -- fx
f53a06c3 1559(defun dired-filename-at-point ()
fc14288b
GM
1560 "Return the filename closest to point, expanded.
1561Point should be in or after a filename."
d1be20a1
GM
1562 (save-excursion
1563 ;; First see if just past a filename.
1564 (or (eobp) ; why?
70f1b5e8 1565 (when (looking-at-p "[] \t\n[{}()]") ; whitespace or some parens
d1be20a1
GM
1566 (skip-chars-backward " \n\t\r({[]})")
1567 (or (bobp) (backward-char 1))))
1568 (let ((filename-chars "-.[:alnum:]_/:$+@")
1569 start prefix)
70f1b5e8 1570 (if (looking-at-p (format "[%s]" filename-chars))
cb3fe1f0 1571 (progn
fc14288b
GM
1572 (skip-chars-backward filename-chars)
1573 (setq start (point)
1574 prefix
1575 ;; This is something to do with ange-ftp filenames.
1576 ;; It convert foo@bar to /foo@bar.
1577 ;; But when does the former occur in dired buffers?
70f1b5e8 1578 (and (string-match-p
1e56daa5 1579 "^\\w+@"
8551cb32 1580 (buffer-substring start (line-end-position)))
6b622862 1581 "/"))
70f1b5e8 1582 (if (string-match-p "[/~]" (char-to-string (preceding-char)))
cb3fe1f0 1583 (setq start (1- start)))
fc14288b 1584 (skip-chars-forward filename-chars))
cb3fe1f0 1585 (error "No file found around point!"))
9572a9dd 1586 ;; Return string.
6b622862 1587 (expand-file-name (concat prefix (buffer-substring start (point)))))))
cb3fe1f0 1588
da5e0ce4 1589(defun dired-x-read-filename-at-point (prompt)
b847eb8c
DL
1590 "Return filename prompting with PROMPT with completion.
1591If `current-prefix-arg' is non-nil, uses name at point as guess."
ccb1d39a
RS
1592 (if current-prefix-arg
1593 (let ((guess (dired-filename-at-point)))
1594 (read-file-name prompt
1595 (file-name-directory guess)
1596 guess
1597 nil (file-name-nondirectory guess)))
1598 (read-file-name prompt default-directory)))
da5e0ce4
GM
1599
1600(define-obsolete-function-alias 'read-filename-at-point
1601 'dired-x-read-filename-at-point "24.1") ; is this even needed?
cb3fe1f0 1602\f
b578f267 1603;;; BUG REPORTS
cb3fe1f0 1604
461b69ae 1605(define-obsolete-function-alias 'dired-x-submit-report 'report-emacs-bug "24.1")
cb3fe1f0
RS
1606
1607\f
1608;; As Barry Warsaw would say: "This might be useful..."
1609(provide 'dired-x)
1610
276f1d00
GM
1611;; Local Variables:
1612;; byte-compile-dynamic: t
1613;; generated-autoload-file: "dired.el"
1614;; End:
1615
cb3fe1f0 1616;;; dired-x.el ends here