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