* filesets.el (filesets-data): Doc fix.
[bpt/emacs.git] / lisp / filesets.el
CommitLineData
c0e48b0b
RS
1;;; filesets.el --- handle group of files
2
eb3fa2cf
GM
3;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
4;; Free Software Foundation, Inc.
c0e48b0b 5
9dd4f5b2 6;; Author: Thomas Link <sanobast-emacs@yahoo.de>
9f243b0d 7;; Maintainer: FSF
c0e48b0b
RS
8;; Keywords: filesets convenience
9
757a6abf
PJ
10;; This file is part of GNU Emacs.
11
eb3fa2cf 12;; GNU Emacs is free software: you can redistribute it and/or modify
c0e48b0b 13;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
c0e48b0b 16
eb3fa2cf 17;; GNU Emacs is distributed in the hope that it will be useful,
c0e48b0b
RS
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
eb3fa2cf
GM
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24
25;;; Code:
c0e48b0b 26
f194e54a 27(defvar filesets-version "1.8.4")
c0e48b0b
RS
28(defvar filesets-homepage
29 "http://members.a1.net/t.link/CompEmacsFilesets.html")
30
31;;; Commentary:
32
b3ea44f8 33;; Define filesets, which can be opened or saved with the power of one or
757a6abf
PJ
34;; two mouse clicks only. A fileset is either a list of files, a file
35;; pattern, a base directory and a search pattern (for files), or an
36;; inclusion group (i.e. a base file including other files).
c0e48b0b 37
cfce85d8
RS
38;; Usage:
39;; 1. Put (require 'filesets) and (filesets-init) in your .emacs file.
40;; 2. Type ;; M-x filesets-edit or choose "Edit Filesets" from the menu.
41;; 3. Save your customizations.
c0e48b0b 42
757a6abf 43;; Caveat: Fileset names have to be unique.
c0e48b0b 44
757a6abf
PJ
45;; Filesets.el adds a nifty filesets menu to your menubar. If you change
46;; your filesets on the fly, don't forget to select "Save Filesets" from
47;; the menu.
c0e48b0b 48
757a6abf
PJ
49;; Pressing on the first item in the submenu will open all files at once.
50;; Define your own function, e.g. browse-url, for opening a fileset's
51;; files. Or define external viewers for opening files with other
52;; programs. See `filesets-external-viewers'.
c0e48b0b 53
757a6abf 54;; BTW, if you close a fileset, files, which have been changed, will
fffa137c 55;; be silently saved. Change this behavior by setting
757a6abf 56;; `filesets-save-buffer-fn'.
c0e48b0b
RS
57
58;;; Supported modes for inclusion groups (`filesets-ingroup-patterns'):
59;; - Elisp
60;; - Emacs-Wiki (simple names only)
61;; - LaTeX
62
63
64
65;;; Known bugs:
66
67
68;;; To do:
69
70;;- better handling of different customization scenarios
71
9f243b0d
RS
72;; Data gathering should be better separated from building the menu
73;; so that one could (1) use filesets without installing the menu
74;; and (2) create new "frontends" to speedbar and others.
75
76;; The functionality to call external viewers should be isolated in
77;; an extra package and possibly integrated with the MIME
78;; handling.
c0e48b0b
RS
79
80;;; Credits:
81
82;; Helpful suggestions (but no significant code) were contributed by
83
84;;- Christoph Conrad (at gmx de)
85;;- Christian Ohler (at Informatik Uni-Oldenburg DE)
86;;- Richard Stallman aka RMS (at gnu org)
87;;- Per Abrahamsen aka abraham (at dina kvl dk)
88
89
90;;; Code:
91
92(eval-when-compile
93 (require 'cl))
94
95
96;;; Some variables
c0e48b0b
RS
97
98(defvar filesets-menu-cache nil
99 "The whole filesets menu.")
100(defvar filesets-cache-version nil
101 "Filesets' cached version number.")
102(defvar filesets-cache-hostname nil
103 "Filesets' cached system name.")
104
105(defvar filesets-ingroup-cache nil
106 "A plist containing files and their ingroup data.")
78b3d0f7
RS
107(defvar filesets-ingroup-files nil
108 "List of files already processed when searching for included files.")
c0e48b0b
RS
109
110(defvar filesets-has-changed-flag t
111 "Non-nil means some fileset definition has changed.")
112(defvar filesets-submenus nil
113 "An association list with filesets menu data.")
114(defvar filesets-updated-buffers nil
115 "A list of buffers with updated menu bars.")
116(defvar filesets-menu-use-cached-flag nil
91cc505c 117 "Use cached data. See `filesets-menu-ensure-use-cached' for details.")
c0e48b0b
RS
118(defvar filesets-update-cache-file-flag nil
119 "Non-nil means the cache needs updating.")
120(defvar filesets-ignore-next-set-default nil
91cc505c 121 "List of custom variables for which the next `set-default' will be ignored.")
c0e48b0b
RS
122
123(defvar filesets-output-buffer-flag nil
124 "Non-nil means the current buffer is an output buffer created by filesets.
125Is buffer local variable.")
126
127(defvar filesets-verbosity 1
9f243b0d
RS
128 "An integer defining the level of verbosity.
1290 means no messages at all.")
c0e48b0b
RS
130
131(defvar filesets-menu-ensure-use-cached
91cc505c 132 (and (featurep 'xemacs)
b8caac06
RS
133 (if (fboundp 'emacs-version>=)
134 (not (emacs-version>= 21 5))))
c0e48b0b
RS
135 "Make sure (X)Emacs uses filesets' cache.
136
137Well, if you use XEmacs (prior to 21.5?) custom.el is loaded after
138init.el. This means that settings saved in the cache file (see
139`filesets-menu-cache-file') will be overwritten by custom.el. In order
140to ensure the use of the cache file, set this variable to t -- which is
141the default for XEmacs prior to 21.5. If you want to change this value
142put \"(setq filesets-menu-ensure-use-cached VALUE)\" into your startup
143file -- before loading filesets.el.
144
145So, when should you think about setting this value to t? If filesets.el
146is loaded before user customizations. Thus, if (require 'filesets)
147precedes the custom-set-variables command or, for XEmacs, if init.el is
148loaded before custom.el, set this variable to t.")
149
150
151;;; utils
152(defun filesets-filter-list (lst cond-fn)
153 "Remove all elements not conforming to COND-FN from list LST.
154COND-FN takes one argument: the current element."
155; (remove* 'dummy lst :test (lambda (dummy elt)
156; (not (funcall cond-fn elt)))))
157 (let ((rv nil))
158 (dolist (elt lst rv)
159 (when (funcall cond-fn elt)
160 (setq rv (append rv (list elt)))))))
161
f194e54a 162(defun filesets-ormap (fsom-pred lst)
095aa9cd 163 "Return the tail of LST for the head of which FSOM-PRED is non-nil."
f194e54a
RS
164 (let ((fsom-lst lst)
165 (fsom-rv nil))
166 (while (and (not (null fsom-lst))
167 (null fsom-rv))
168 (if (funcall fsom-pred (car fsom-lst))
169 (setq fsom-rv fsom-lst)
170 (setq fsom-lst (cdr fsom-lst))))
171 fsom-rv))
172
173(defun filesets-some (fss-pred fss-lst)
e9bbdfc3 174 "Return non-nil if FSS-PRED is non-nil for any element of FSS-LST.
f194e54a
RS
175Like `some', return the first value of FSS-PRED that is non-nil."
176 (catch 'exit
177 (dolist (fss-this fss-lst nil)
178 (let ((fss-rv (funcall fss-pred fss-this)))
179 (when fss-rv
180 (throw 'exit fss-rv))))))
181;(fset 'filesets-some 'some) ;; or use the cl function
182
183(defun filesets-member (fsm-item fsm-lst &rest fsm-keys)
184 "Find the first occurrence of FSM-ITEM in FSM-LST.
91cc505c 185It is supposed to work like cl's `member*'. At the moment only the :test
f194e54a
RS
186key is supported."
187 (let ((fsm-test (or (plist-get fsm-keys ':test)
188 (function equal))))
189 (filesets-ormap (lambda (fsm-this)
e9bbdfc3 190 (funcall fsm-test fsm-item fsm-this))
f194e54a
RS
191 fsm-lst)))
192;(fset 'filesets-member 'member*) ;; or use the cl function
193
c0e48b0b
RS
194(defun filesets-sublist (lst beg &optional end)
195 "Get the sublist of LST from BEG to END - 1."
196 (let ((rv nil)
197 (i beg)
198 (top (or end
199 (length lst))))
200 (while (< i top)
201 (setq rv (append rv (list (nth i lst))))
202 (setq i (+ i 1)))
203 rv))
204
205(defun filesets-select-command (cmd-list)
206 "Select one command from CMD-LIST -- a string with space separated names."
207 (let ((this (shell-command-to-string
208 (format "which --skip-alias %s 2> /dev/null | head -n 1"
209 cmd-list))))
e9bbdfc3 210 (if (equal this "")
c0e48b0b
RS
211 nil
212 (file-name-nondirectory (substring this 0 (- (length this) 1))))))
213
214(defun filesets-which-command (cmd)
91cc505c 215 "Call \"which CMD\"."
c0e48b0b
RS
216 (shell-command-to-string (format "which %s" cmd)))
217
218(defun filesets-which-command-p (cmd)
91cc505c 219 "Call \"which CMD\" and return non-nil if the command was found."
c0e48b0b
RS
220 (when (string-match (format "\\(/[^/]+\\)?/%s" cmd)
221 (filesets-which-command cmd))
222 cmd))
223
224(defun filesets-message (level &rest args)
225 "Show a message only if LEVEL is greater or equal then `filesets-verbosity'."
226 (when (<= level (abs filesets-verbosity))
227 (apply 'message args)))
228
229
230;;; config file
231(defun filesets-save-config ()
232 "Save filesets' customizations."
233 (interactive)
234 (customize-save-customized))
235
236(defun filesets-reset-fileset (&optional fileset no-cache)
237 "Reset the cached values for one or all filesets."
238 (if fileset
239 (setq filesets-submenus (lax-plist-put filesets-submenus fileset nil))
240 (setq filesets-submenus nil))
241 (setq filesets-has-changed-flag t)
242 (setq filesets-update-cache-file-flag (or filesets-update-cache-file-flag
243 (not no-cache))))
244
245(defun filesets-set-config (fileset var val)
246 "Set-default wrapper function."
247 (filesets-reset-fileset fileset)
248 (set-default var val))
249; (customize-set-variable var val))
250; (filesets-build-menu))
251
ed8c6a24 252;; It seems this is a workaround for the XEmacs issue described in the
91cc505c 253;; doc-string of filesets-menu-ensure-use-cached. Under Emacs this is
ed8c6a24 254;; essentially just `set-default'.
c0e48b0b 255(defun filesets-set-default (sym val &optional init-flag)
ed8c6a24
GM
256 "Set-default wrapper function used in conjunction with `defcustom'.
257If SYM is in the list `filesets-ignore-next-set-default', delete
258it from that list, and return nil. Otherwise, set the value of
259SYM to VAL and return t. If INIT-FLAG is non-nil, set with
260`custom-initialize-set', otherwise with `set-default'."
c0e48b0b
RS
261 (let ((ignore-flag (member sym filesets-ignore-next-set-default)))
262 (if ignore-flag
263 (setq filesets-ignore-next-set-default
264 (delete sym filesets-ignore-next-set-default))
265 (if init-flag
266 (custom-initialize-set sym val)
267 (set-default sym val)))
268 (not ignore-flag)))
269
270(defun filesets-set-default! (sym val)
271 "Call `filestes-set-default' and reset cached data (i.e. rebuild menu)."
272 (when (filesets-set-default sym val)
273 (filesets-reset-fileset)))
274
275(defun filesets-set-default+ (sym val)
276 "Call `filestes-set-default' and reset filesets' standard menu."
277 (when (filesets-set-default sym val)
278 (setq filesets-has-changed-flag t)))
279; (filesets-reset-fileset nil t)))
280
9f243b0d
RS
281(defvar filesets-data)
282
c0e48b0b
RS
283(defun filesets-data-set-default (sym val)
284 "Set the default for `filesets-data'."
285 (if filesets-menu-use-cached-flag
286 (setq filesets-menu-use-cached-flag nil)
287 (when (default-boundp 'filesets-data)
288 (let ((modified-filesets
289 (filesets-filter-list val
290 (lambda (x)
291 (let ((name (car x))
292 (data (cdr x)))
293 (let ((elt (assoc name filesets-data)))
294 (or (not elt)
295 (not (equal data (cdr elt))))))))))
296 (dolist (x modified-filesets)
297 (filesets-reset-fileset (car x))))))
298 (filesets-set-default sym val))
9f243b0d 299\f
c0e48b0b
RS
300;;; configuration
301(defgroup filesets nil
302 "The fileset swapper."
303 :prefix "filesets-"
485ecb5c 304 :group 'convenience
bf247b6e 305 :version "22.1")
c0e48b0b
RS
306
307(defcustom filesets-menu-name "Filesets"
91cc505c 308 "Filesets' menu name."
c0e48b0b 309 :set (function filesets-set-default)
6efb94fc 310 :type 'string
c0e48b0b
RS
311 :group 'filesets)
312
6efb94fc 313(defcustom filesets-menu-path '("File") ; cf recentf-menu-path
91cc505c 314 "The menu under which the filesets menu should be inserted.
204451b6
GM
315See `add-submenu' for documentation."
316 :set (function filesets-set-default)
6efb94fc
GM
317 :type '(choice (const :tag "Top Level" nil)
318 (sexp :tag "Menu Path"))
319 :version "23.1" ; was nil
204451b6
GM
320 :group 'filesets)
321
6efb94fc 322(defcustom filesets-menu-before "Open File..." ; cf recentf-menu-before
91cc505c 323 "The name of a menu before which this menu should be added.
204451b6
GM
324See `add-submenu' for documentation."
325 :set (function filesets-set-default)
6efb94fc
GM
326 :type '(choice (string :tag "Name")
327 (const :tag "Last" nil))
328 :version "23.1" ; was "File"
204451b6
GM
329 :group 'filesets)
330
331(defcustom filesets-menu-in-menu nil
91cc505c 332 "Use that instead of `current-menubar' as the menu to change.
204451b6
GM
333See `add-submenu' for documentation."
334 :set (function filesets-set-default)
335 :type 'sexp
336 :group 'filesets)
c0e48b0b
RS
337
338(defcustom filesets-menu-shortcuts-flag t
91cc505c 339 "Non-nil means to prepend menus with hopefully unique shortcuts."
c0e48b0b
RS
340 :set (function filesets-set-default!)
341 :type 'boolean
342 :group 'filesets)
343
344(defcustom filesets-menu-shortcuts-marker "%_"
91cc505c 345 "String for marking menu shortcuts."
c0e48b0b
RS
346 :set (function filesets-set-default!)
347 :type 'string
348 :group 'filesets)
349
91cc505c
SM
350;;(defcustom filesets-menu-cnvfp-flag nil
351;; "*Non-nil means show \"Convert :pattern to :files\" entry for :pattern menus."
352;; :set (function filesets-set-default!)
353;; :type 'boolean
354;; :group 'filesets)
c0e48b0b
RS
355
356(defcustom filesets-menu-cache-file
91cc505c 357 (if (featurep 'xemacs)
c0e48b0b 358 "~/.xemacs/filesets-cache.el"
5f96d7d6 359 (concat user-emacs-directory "filesets-cache.el"))
91cc505c 360 "File to be used for saving the filesets menu between sessions.
cd56bfef 361Set this to \"\", to disable caching of menus.
c0e48b0b
RS
362Don't forget to check out `filesets-menu-ensure-use-cached'."
363 :set (function filesets-set-default)
364 :type 'file
365 :group 'filesets)
cd56bfef 366(put 'filesets-menu-cache-file 'risky-local-variable t)
c0e48b0b
RS
367
368(defcustom filesets-menu-cache-contents
369 '(filesets-be-docile-flag
370 filesets-submenus
e9bbdfc3 371 filesets-menu-cache
c0e48b0b 372 filesets-ingroup-cache)
91cc505c 373 "Stuff we want to save in `filesets-menu-cache-file'.
c0e48b0b
RS
374
375Possible uses: don't save configuration data in the main startup files
376but in filesets's own cache. In this case add `filesets-data' to this
377list.
378
91cc505c 379There is a second reason for putting `filesets-data' on this list. If
c0e48b0b
RS
380you frequently add and remove buffers on the fly to :files filesets, you
381don't need to save your customizations if `filesets-data' is being
91cc505c 382mirrored in the cache file. In this case the version in the cache file
c0e48b0b
RS
383is the current one, and the version in your startup file will be
384silently updated later on.
385
386If you want caching to work properly, at least `filesets-submenus',
387`filesets-menu-cache', and `filesets-ingroup-cache' should be in this
388list.
389
390Don't forget to check out `filesets-menu-ensure-use-cached'."
391 :set (function filesets-set-default)
392 :type '(repeat
393 (choice :tag "Variable"
394 (const :tag "filesets-submenus"
395 :value filesets-submenus)
396 (const :tag "filesets-menu-cache"
397 :value filesets-menu-cache)
398 (const :tag "filesets-ingroup-cache"
399 :value filesets-ingroup-cache)
400 (const :tag "filesets-data"
401 :value filesets-data)
402 (const :tag "filesets-external-viewers"
403 :value filesets-external-viewers)
404 (const :tag "filesets-ingroup-patterns"
405 :value filesets-ingroup-patterns)
406 (const :tag "filesets-be-docile-flag"
407 :value filesets-be-docile-flag)
408 (sexp :tag "Other" :value nil)))
409 :group 'filesets)
410
411(defcustom filesets-cache-fill-content-hooks nil
91cc505c 412 "Hooks to run when writing the contents of filesets' cache file.
c0e48b0b
RS
413
414The hook is called with the cache file as current buffer and the cursor
415at the last position. I.e. each hook has to make sure that the cursor is
416at the last position.
417
418Possible uses: If you don't want to save `filesets-data' in your normal
419configuration file, you can add a something like this
420
421 \(lambda ()
422 \(insert (format \"(setq-default filesets-data '%S)\"
423 filesets-data))
424 \(newline 2))
425
426to this hook.
427
428Don't forget to check out `filesets-menu-ensure-use-cached'."
429 :set (function filesets-set-default)
430 :type 'hook
431 :group 'filesets)
432
433(defcustom filesets-cache-hostname-flag nil
91cc505c 434 "Non-nil means cache the hostname.
cd56bfef
RS
435If the current name differs from the cached one,
436rebuild the menu and create a new cache file."
c0e48b0b
RS
437 :set (function filesets-set-default)
438 :type 'boolean
439 :group 'filesets)
440
441(defcustom filesets-cache-save-often-flag nil
91cc505c 442 "Non-nil means save buffer on every change of the filesets menu.
c0e48b0b 443If this variable is set to nil and if Emacs crashes, the cache and
91cc505c 444filesets-data could get out of sync. Set this to t if this happens from
c0e48b0b
RS
445time to time or if the fileset cache causes troubles."
446 :set (function filesets-set-default)
447 :type 'boolean
448 :group 'filesets)
449
450(defcustom filesets-max-submenu-length 25
91cc505c 451 "Maximum length of submenus.
c0e48b0b
RS
452Set this value to 0 to turn menu splitting off. BTW, parts of submenus
453will not be rewrapped if their length exceeds this value."
454 :set (function filesets-set-default)
455 :type 'integer
456 :group 'filesets)
457
458(defcustom filesets-max-entry-length 50
91cc505c 459 "Truncate names of splitted submenus to this length."
c0e48b0b
RS
460 :set (function filesets-set-default)
461 :type 'integer
462 :group 'filesets)
463
cd56bfef 464(defcustom filesets-browse-dir-function 'dired
91cc505c 465 "A function or command used for browsing directories.
c0e48b0b
RS
466When using an external command, \"%s\" will be replaced with the
467directory's name.
468
469Note: You have to manually rebuild the menu if you change this value."
470 :set (function filesets-set-default)
471 :type '(choice :tag "Function:"
472 (const :tag "dired"
473 :value dired)
474 (list :tag "Command"
475 :value ("" "%s")
476 (string :tag "Name")
477 (string :tag "Arguments"))
478 (function :tag "Function"
479 :value nil))
480 :group 'filesets)
481
cd56bfef 482(defcustom filesets-open-file-function 'filesets-find-or-display-file
91cc505c 483 "The function used for opening files.
c0e48b0b
RS
484
485`filesets-find-or-display-file' ... Filesets' default function for
486visiting files. This function checks if an external viewer is defined
487for a specific file type. Either this viewer, if defined, or
488`find-file' will be used to visit a file.
489
490`filesets-find-file' ... An alternative function that always uses
91cc505c 491`find-file'. If `filesets-be-docile-flag' is true, a file, which isn't
c0e48b0b
RS
492readable, will not be opened.
493
494Caveat: Changes will take effect only after rebuilding the menu."
495 :set (function filesets-set-default)
496 :type '(choice :tag "Function:"
497 (const :tag "filesets-find-or-display-file"
498 :value filesets-find-or-display-file)
499 (const :tag "filesets-find-file"
500 :value filesets-find-file)
501 (function :tag "Function"
502 :value nil))
503 :group 'filesets)
504
cd56bfef 505(defcustom filesets-save-buffer-function 'save-buffer
91cc505c 506 "The function used to save a buffer.
c0e48b0b
RS
507Caveat: Changes will take effect after rebuilding the menu."
508 :set (function filesets-set-default)
509 :type '(choice :tag "Function:"
510 (const :tag "save-buffer"
511 :value save-buffer)
512 (function :tag "Function"
513 :value nil))
514 :group 'filesets)
515
516(defcustom filesets-find-file-delay
91cc505c 517 (if (and (featurep 'xemacs) gutter-buffers-tab-visible-p)
c0e48b0b
RS
518 0.5
519 0)
91cc505c 520 "Delay before calling `find-file'.
c0e48b0b
RS
521This is for calls via `filesets-find-or-display-file'
522or `filesets-find-file'.
523
524Set this to 0, if you don't use XEmacs' buffer tabs."
525 :set (function filesets-set-default)
526 :type 'number
527 :group 'filesets)
528
529(defcustom filesets-be-docile-flag nil
91cc505c 530 "Non-nil means don't complain if a file or a directory doesn't exist.
c0e48b0b
RS
531This is useful if you want to use the same startup files in different
532computer environments."
533 :set (function filesets-set-default)
534 :type 'boolean
535 :group 'filesets)
536
537(defcustom filesets-sort-menu-flag t
91cc505c 538 "Non-nil means sort the filesets menu alphabetically."
c0e48b0b
RS
539 :set (function filesets-set-default)
540 :type 'boolean
541 :group 'filesets)
542
543(defcustom filesets-sort-case-sensitive-flag t
095aa9cd 544 "Non-nil means sorting of the filesets menu is case sensitive."
c0e48b0b
RS
545 :set (function filesets-set-default)
546 :type 'boolean
547 :group 'filesets)
548
549(defcustom filesets-tree-max-level 3
91cc505c 550 "Maximum scan depth for directory trees.
c0e48b0b 551A :tree fileset is defined by a base directory the contents of which
cd56bfef 552will be recursively added to the menu. `filesets-tree-max-level' tells up
c0e48b0b
RS
553to which level the directory structure should be scanned/listed,
554i.e. how deep the menu should be. Try something like
555
556 \(\"HOME -- only one level\"
557 \(:tree \"~\" \"^[^.].*[^~]$\")
558 \(:tree-max-level 1)
559 \(:filter-dirs-flag t))
560 \(\"HOME -- up to 3 levels\"
561 \(:tree \"~\" \"^[^.].*[^~]$\")
562 \(:tree-max-level 3)
563 \(:filter-dirs-flag t))
564
565and it should become clear what this option is about. In any case,
566including directory trees to the menu can take a lot of memory."
567 :set (function filesets-set-default)
568 :type 'integer
569 :group 'filesets)
570
571(defcustom filesets-commands
67c18958
JL
572 `(("Isearch"
573 multi-isearch-files
574 (filesets-cmd-isearch-getargs))
575 ("Isearch (regexp)"
576 multi-isearch-files-regexp
577 (filesets-cmd-isearch-getargs))
578 ("Query Replace"
579 perform-replace
c0e48b0b
RS
580 (filesets-cmd-query-replace-getargs))
581 ("Query Replace (regexp)"
67c18958
JL
582 perform-replace
583 (filesets-cmd-query-replace-regexp-getargs))
c0e48b0b
RS
584 ("Grep <<selection>>"
585 "grep"
586 ("-n " filesets-get-quoted-selection " " "<<file-name>>"))
587 ("Run Shell Command"
588 filesets-cmd-shell-command
589 (filesets-cmd-shell-command-getargs)))
91cc505c 590 "Commands to run on filesets.
c0e48b0b
RS
591An association list of names, functions, and an argument list (or a
592function that returns one) to be run on a filesets' files.
593
594The argument <file-name> or <<file-name>> (quoted) will be replaced with
595the filename."
596 :set (function filesets-set-default+)
597 :type '(repeat :tag "Commands"
598 (list :tag "Definition" :value ("")
599 (string "Name")
600 (choice :tag "Command"
601 (string :tag "String")
602 (function :tag "Function"))
603 (repeat :tag "Argument List"
604 (choice :tag "Arguments"
605 (sexp :tag "Sexp"
606 :value nil)
607 (string :tag "File Name"
608 :value "<file-name>")
609 (string :tag "Quoted File Name"
610 :value "<<file-name>>")
611 (function :tag "Function"
612 :value nil)))))
613 :group 'filesets)
cd56bfef 614(put 'filesets-commands 'risky-local-variable t)
c0e48b0b
RS
615
616(defcustom filesets-external-viewers
617 (let
91cc505c
SM
618 ;; ((ps-cmd (or (and (boundp 'my-ps-viewer) my-ps-viewer)
619 ;; (filesets-select-command "ggv gv")))
620 ;; (pdf-cmd (or (and (boundp 'my-ps-viewer) my-pdf-viewer)
621 ;; (filesets-select-command "xpdf acroread")))
622 ;; (dvi-cmd (or (and (boundp 'my-ps-viewer) my-dvi-viewer)
623 ;; (filesets-select-command "xdvi tkdvi")))
624 ;; (doc-cmd (or (and (boundp 'my-ps-viewer) my-doc-viewer)
625 ;; (filesets-select-command "antiword")))
626 ;; (pic-cmd (or (and (boundp 'my-ps-viewer) my-pic-viewer)
627 ;; (filesets-select-command "gqview ee display"))))
c0e48b0b
RS
628 ((ps-cmd "ggv")
629 (pdf-cmd "xpdf")
630 (dvi-cmd "xdvi")
631 (doc-cmd "antiword")
632 (pic-cmd "gqview"))
633 `(("^.+\\..?html?$" browse-url
634 ((:ignore-on-open-all t)))
635 ("^.+\\.pdf$" ,pdf-cmd
636 ((:ignore-on-open-all t)
637 (:ignore-on-read-text t)
638 (:constraint-flag ,pdf-cmd)))
639 ("^.+\\.e?ps\\(.gz\\)?$" ,ps-cmd
640 ((:ignore-on-open-all t)
641 (:ignore-on-read-text t)
642 (:constraint-flag ,ps-cmd)))
643 ("^.+\\.dvi$" ,dvi-cmd
644 ((:ignore-on-open-all t)
645 (:ignore-on-read-text t)
646 (:constraint-flag ,dvi-cmd)))
647 ("^.+\\.doc$" ,doc-cmd
648 ((:capture-output t)
649 (:ignore-on-read-text t)
650 (:constraint-flag ,doc-cmd)))
651 ("^.+\\.\\(tiff\\|xpm\\|gif\\|pgn\\)$" ,pic-cmd
652 ((:ignore-on-open-all t)
653 (:ignore-on-read-text t)
654 (:constraint-flag ,pic-cmd)))))
91cc505c 655 "Association list of file patterns and external viewers for use with
c0e48b0b
RS
656`filesets-find-or-display-file'.
657
658Has the form ((FILE-PATTERN VIEWER PROPERTIES) ...), VIEWER being either a
659function or a command name as string.
660
4f955a15
JB
661Properties is an association list determining filesets' behavior in
662several conditions. Choose one from this list:
c0e48b0b
RS
663
664:ignore-on-open-all ... Don't open files of this type automatically --
665i.e. on open-all-files-events or when running commands
666
667:capture-output ... capture an external viewer output
668
669:constraintp FUNCTION ... use this viewer only if FUNCTION returns non-nil
670
f194e54a 671:constraint-flag SEXP ... use this viewer only if SEXP evaluates to non-nil
c0e48b0b
RS
672
673:open-hook HOOK ... run hooks after spawning the viewer -- mainly useful
674in conjunction with :capture-output
675
676:args (FORMAT-STRING or SYMBOL or FUNCTION) ... a list of arguments
677\(defaults to (list \"%S\")) when using shell commands
678
679Avoid modifying this variable and achieve minor speed-ups by setting the
680variables my-ps-viewer, my-pdf-viewer, my-dvi-viewer, my-pic-viewer.
681
682In order to view pdf or rtf files in an Emacs buffer, you could use these:
683
684
91cc505c 685 \(\"^.+\\\\.pdf\\\\'\" \"pdftotext\"
c0e48b0b
RS
686 \((:capture-output t)
687 \(:args (\"%S - | fmt -w \" window-width))
688 \(:ignore-on-read-text t)
689 \(:constraintp (lambda ()
690 \(and \(filesets-which-command-p \"pdftotext\")
691 \(filesets-which-command-p \"fmt\"))))))
91cc505c 692 \(\"^.+\\\\.rtf\\\\'\" \"rtf2htm\"
c0e48b0b
RS
693 \((:capture-output t)
694 \(:args (\"%S 2> /dev/null | w3m -dump -T text/html\"))
695 \(:ignore-on-read-text t)
696 \(:constraintp (lambda ()
697 \(and (filesets-which-command-p \"rtf2htm\")
91cc505c 698 \(filesets-which-command-p \"w3m\"))))))"
c0e48b0b
RS
699 :set (function filesets-set-default)
700 :type '(repeat :tag "Viewer"
701 (list :tag "Definition"
702 :value ("^.+\\.suffix$" "")
703 (regexp :tag "Pattern")
704 (choice :tag "Viewer"
705 (symbol :tag "Function" :value nil)
706 (string :tag "Program" :value ""))
707 (repeat :tag "Properties"
708 (choice
709 (list :tag ":constraintp"
710 :value (:constraintp)
711 (const :format ""
712 :value :constraintp)
713 (function :tag "Function"))
714 (list :tag ":constraint-flag"
715 :value (:constraint-flag)
716 (const :format ""
717 :value :constraint-flag)
f194e54a 718 (sexp :tag "Symbol"))
c0e48b0b
RS
719 (list :tag ":ignore-on-open-all"
720 :value (:ignore-on-open-all t)
721 (const :format ""
722 :value :ignore-on-open-all)
723 (boolean :tag "Boolean"))
724 (list :tag ":ignore-on-read-text"
725 :value (:ignore-on-read-text t)
726 (const :format ""
727 :value :ignore-on-read-text)
728 (boolean :tag "Boolean"))
729 (list :tag ":args"
730 :value (:args)
731 (const :format ""
732 :value :args)
733 (repeat :tag "List"
734 (choice :tag "Arguments"
735 (string :tag "String"
736 :value "")
737 (symbol :tag "Symbol"
738 :value nil)
739 (function :tag "Function"
740 :value nil))))
741 (list :tag ":open-hook"
742 :value (:open-hook)
743 (const :format ""
744 :value :open-hook)
745 (hook :tag "Hook"))
746; (list :tag ":close-hook"
747; :value (:close-hook)
748; (const :format ""
749; :value :close-hook)
750; (hook :tag "Hook"))
751 (list :tag ":capture-output"
752 :value (:capture-output t)
753 (const :format ""
754 :value :capture-output)
755 (boolean :tag "Boolean"))))))
756 :group 'filesets)
cd56bfef 757(put 'filesets-external-viewers 'risky-local-variable t)
c0e48b0b
RS
758
759(defcustom filesets-ingroup-patterns
760 '(("^.+\\.tex$" t
761 (((:name "Package")
762 (:pattern "\\\\usepackage\\W*\\(\\[[^\]]*\\]\\W*\\)?{\\W*\\(.+\\)\\W*}")
763 (:match-number 2)
764 (:stub-flag t)
765 (:get-file-name (lambda (master file)
766 (filesets-which-file master
767 (concat file ".sty")
e9bbdfc3 768 (filesets-convert-path-list
c0e48b0b
RS
769 (or (getenv "MY_TEXINPUTS")
770 (getenv "TEXINPUTS")))))))
771 ((:name "Include")
772 (:pattern "\\\\include\\W*{\\W*\\(.+\\)\\W*}")
773 (:get-file-name (lambda (master file)
774 (filesets-which-file master
775 (concat file ".tex")
e9bbdfc3 776 (filesets-convert-path-list
c0e48b0b
RS
777 (or (getenv "MY_TEXINPUTS")
778 (getenv "TEXINPUTS"))))))
779 (:scan-depth 5))
780 ((:name "Input")
781 (:pattern "\\\\input\\W*{\\W*\\(.+\\)\\W*}")
782 (:stubp (lambda (a b) (not (filesets-files-in-same-directory-p a b))))
783 (:get-file-name (lambda (master file)
784 (filesets-which-file master
785 (concat file ".tex")
e9bbdfc3 786 (filesets-convert-path-list
c0e48b0b
RS
787 (or (getenv "MY_TEXINPUTS")
788 (getenv "TEXINPUTS"))))))
789 (:scan-depth 5))
790 ((:name "Bibliography")
791 (:pattern "\\\\bibliography\\W*{\\W*\\(.+\\)\\W*}")
792 (:get-file-name (lambda (master file)
793 (filesets-which-file master
794 (concat file ".bib")
e9bbdfc3 795 (filesets-convert-path-list
c0e48b0b
RS
796 (or (getenv "MY_BIBINPUTS")
797 (getenv "BIBINPUTS")))))))))
798 ("^.+\\.el$" t
799 (((:name "Require")
800 (:pattern "(require\\W+'\\(.+\\))")
801 (:stubp (lambda (a b) (not (filesets-files-in-same-directory-p a b))))
802 (:get-file-name (lambda (master file)
803 (filesets-which-file master
804 (concat file ".el")
805 load-path))))
806 ((:name "Load")
807 (:pattern "(load\\(-library\\)?\\W+\"\\(.+\\)\")")
808 (:match-number 2)
809 (:get-file-name (lambda (master file)
810 (filesets-which-file master file load-path))))))
811