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