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