(Buffer-menu-mode): Document new commands in docstring.
[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
757a6abf 6;; Author: Thomas Link <t.link@gmx.at>
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
RS
309 :set (function filesets-set-default)
310 :type 'sexp
311 :group 'filesets)
312
204451b6 313(defcustom filesets-menu-path nil
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)
317 :type 'sexp
318 :group 'filesets)
319
320(defcustom filesets-menu-before "File"
91cc505c 321 "The name of a menu before which this menu should be added.
204451b6
GM
322See `add-submenu' for documentation."
323 :set (function filesets-set-default)
324 :type 'sexp
325 :group 'filesets)
326
327(defcustom filesets-menu-in-menu nil
91cc505c 328 "Use that instead of `current-menubar' as the menu to change.
204451b6
GM
329See `add-submenu' for documentation."
330 :set (function filesets-set-default)
331 :type 'sexp
332 :group 'filesets)
c0e48b0b
RS
333
334(defcustom filesets-menu-shortcuts-flag t
91cc505c 335 "Non-nil means to prepend menus with hopefully unique shortcuts."
c0e48b0b
RS
336 :set (function filesets-set-default!)
337 :type 'boolean
338 :group 'filesets)
339
340(defcustom filesets-menu-shortcuts-marker "%_"
91cc505c 341 "String for marking menu shortcuts."
c0e48b0b
RS
342 :set (function filesets-set-default!)
343 :type 'string
344 :group 'filesets)
345
91cc505c
SM
346;;(defcustom filesets-menu-cnvfp-flag nil
347;; "*Non-nil means show \"Convert :pattern to :files\" entry for :pattern menus."
348;; :set (function filesets-set-default!)
349;; :type 'boolean
350;; :group 'filesets)
c0e48b0b
RS
351
352(defcustom filesets-menu-cache-file
91cc505c 353 (if (featurep 'xemacs)
c0e48b0b 354 "~/.xemacs/filesets-cache.el"
5f96d7d6 355 (concat user-emacs-directory "filesets-cache.el"))
91cc505c 356 "File to be used for saving the filesets menu between sessions.
cd56bfef 357Set this to \"\", to disable caching of menus.
c0e48b0b
RS
358Don't forget to check out `filesets-menu-ensure-use-cached'."
359 :set (function filesets-set-default)
360 :type 'file
361 :group 'filesets)
cd56bfef 362(put 'filesets-menu-cache-file 'risky-local-variable t)
c0e48b0b
RS
363
364(defcustom filesets-menu-cache-contents
365 '(filesets-be-docile-flag
366 filesets-submenus
e9bbdfc3 367 filesets-menu-cache
c0e48b0b 368 filesets-ingroup-cache)
91cc505c 369 "Stuff we want to save in `filesets-menu-cache-file'.
c0e48b0b
RS
370
371Possible uses: don't save configuration data in the main startup files
372but in filesets's own cache. In this case add `filesets-data' to this
373list.
374
91cc505c 375There is a second reason for putting `filesets-data' on this list. If
c0e48b0b
RS
376you frequently add and remove buffers on the fly to :files filesets, you
377don't need to save your customizations if `filesets-data' is being
91cc505c 378mirrored in the cache file. In this case the version in the cache file
c0e48b0b
RS
379is the current one, and the version in your startup file will be
380silently updated later on.
381
382If you want caching to work properly, at least `filesets-submenus',
383`filesets-menu-cache', and `filesets-ingroup-cache' should be in this
384list.
385
386Don't forget to check out `filesets-menu-ensure-use-cached'."
387 :set (function filesets-set-default)
388 :type '(repeat
389 (choice :tag "Variable"
390 (const :tag "filesets-submenus"
391 :value filesets-submenus)
392 (const :tag "filesets-menu-cache"
393 :value filesets-menu-cache)
394 (const :tag "filesets-ingroup-cache"
395 :value filesets-ingroup-cache)
396 (const :tag "filesets-data"
397 :value filesets-data)
398 (const :tag "filesets-external-viewers"
399 :value filesets-external-viewers)
400 (const :tag "filesets-ingroup-patterns"
401 :value filesets-ingroup-patterns)
402 (const :tag "filesets-be-docile-flag"
403 :value filesets-be-docile-flag)
404 (sexp :tag "Other" :value nil)))
405 :group 'filesets)
406
407(defcustom filesets-cache-fill-content-hooks nil
91cc505c 408 "Hooks to run when writing the contents of filesets' cache file.
c0e48b0b
RS
409
410The hook is called with the cache file as current buffer and the cursor
411at the last position. I.e. each hook has to make sure that the cursor is
412at the last position.
413
414Possible uses: If you don't want to save `filesets-data' in your normal
415configuration file, you can add a something like this
416
417 \(lambda ()
418 \(insert (format \"(setq-default filesets-data '%S)\"
419 filesets-data))
420 \(newline 2))
421
422to this hook.
423
424Don't forget to check out `filesets-menu-ensure-use-cached'."
425 :set (function filesets-set-default)
426 :type 'hook
427 :group 'filesets)
428
429(defcustom filesets-cache-hostname-flag nil
91cc505c 430 "Non-nil means cache the hostname.
cd56bfef
RS
431If the current name differs from the cached one,
432rebuild the menu and create a new cache file."
c0e48b0b
RS
433 :set (function filesets-set-default)
434 :type 'boolean
435 :group 'filesets)
436
437(defcustom filesets-cache-save-often-flag nil
91cc505c 438 "Non-nil means save buffer on every change of the filesets menu.
c0e48b0b 439If this variable is set to nil and if Emacs crashes, the cache and
91cc505c 440filesets-data could get out of sync. Set this to t if this happens from
c0e48b0b
RS
441time to time or if the fileset cache causes troubles."
442 :set (function filesets-set-default)
443 :type 'boolean
444 :group 'filesets)
445
446(defcustom filesets-max-submenu-length 25
91cc505c 447 "Maximum length of submenus.
c0e48b0b
RS
448Set this value to 0 to turn menu splitting off. BTW, parts of submenus
449will not be rewrapped if their length exceeds this value."
450 :set (function filesets-set-default)
451 :type 'integer
452 :group 'filesets)
453
454(defcustom filesets-max-entry-length 50
91cc505c 455 "Truncate names of splitted submenus to this length."
c0e48b0b
RS
456 :set (function filesets-set-default)
457 :type 'integer
458 :group 'filesets)
459
cd56bfef 460(defcustom filesets-browse-dir-function 'dired
91cc505c 461 "A function or command used for browsing directories.
c0e48b0b
RS
462When using an external command, \"%s\" will be replaced with the
463directory's name.
464
465Note: You have to manually rebuild the menu if you change this value."
466 :set (function filesets-set-default)
467 :type '(choice :tag "Function:"
468 (const :tag "dired"
469 :value dired)
470 (list :tag "Command"
471 :value ("" "%s")
472 (string :tag "Name")
473 (string :tag "Arguments"))
474 (function :tag "Function"
475 :value nil))
476 :group 'filesets)
477
cd56bfef 478(defcustom filesets-open-file-function 'filesets-find-or-display-file
91cc505c 479 "The function used for opening files.
c0e48b0b
RS
480
481`filesets-find-or-display-file' ... Filesets' default function for
482visiting files. This function checks if an external viewer is defined
483for a specific file type. Either this viewer, if defined, or
484`find-file' will be used to visit a file.
485
486`filesets-find-file' ... An alternative function that always uses
91cc505c 487`find-file'. If `filesets-be-docile-flag' is true, a file, which isn't
c0e48b0b
RS
488readable, will not be opened.
489
490Caveat: Changes will take effect only after rebuilding the menu."
491 :set (function filesets-set-default)
492 :type '(choice :tag "Function:"
493 (const :tag "filesets-find-or-display-file"
494 :value filesets-find-or-display-file)
495 (const :tag "filesets-find-file"
496 :value filesets-find-file)
497 (function :tag "Function"
498 :value nil))
499 :group 'filesets)
500
cd56bfef 501(defcustom filesets-save-buffer-function 'save-buffer
91cc505c 502 "The function used to save a buffer.
c0e48b0b
RS
503Caveat: Changes will take effect after rebuilding the menu."
504 :set (function filesets-set-default)
505 :type '(choice :tag "Function:"
506 (const :tag "save-buffer"
507 :value save-buffer)
508 (function :tag "Function"
509 :value nil))
510 :group 'filesets)
511
512(defcustom filesets-find-file-delay
91cc505c 513 (if (and (featurep 'xemacs) gutter-buffers-tab-visible-p)
c0e48b0b
RS
514 0.5
515 0)
91cc505c 516 "Delay before calling `find-file'.
c0e48b0b
RS
517This is for calls via `filesets-find-or-display-file'
518or `filesets-find-file'.
519
520Set this to 0, if you don't use XEmacs' buffer tabs."
521 :set (function filesets-set-default)
522 :type 'number
523 :group 'filesets)
524
525(defcustom filesets-be-docile-flag nil
91cc505c 526 "Non-nil means don't complain if a file or a directory doesn't exist.
c0e48b0b
RS
527This is useful if you want to use the same startup files in different
528computer environments."
529 :set (function filesets-set-default)
530 :type 'boolean
531 :group 'filesets)
532
533(defcustom filesets-sort-menu-flag t
91cc505c 534 "Non-nil means sort the filesets menu alphabetically."
c0e48b0b
RS
535 :set (function filesets-set-default)
536 :type 'boolean
537 :group 'filesets)
538
539(defcustom filesets-sort-case-sensitive-flag t
095aa9cd 540 "Non-nil means sorting of the filesets menu is case sensitive."
c0e48b0b
RS
541 :set (function filesets-set-default)
542 :type 'boolean
543 :group 'filesets)
544
545(defcustom filesets-tree-max-level 3
91cc505c 546 "Maximum scan depth for directory trees.
c0e48b0b 547A :tree fileset is defined by a base directory the contents of which
cd56bfef 548will be recursively added to the menu. `filesets-tree-max-level' tells up
c0e48b0b
RS
549to which level the directory structure should be scanned/listed,
550i.e. how deep the menu should be. Try something like
551
552 \(\"HOME -- only one level\"
553 \(:tree \"~\" \"^[^.].*[^~]$\")
554 \(:tree-max-level 1)
555 \(:filter-dirs-flag t))
556 \(\"HOME -- up to 3 levels\"
557 \(:tree \"~\" \"^[^.].*[^~]$\")
558 \(:tree-max-level 3)
559 \(:filter-dirs-flag t))
560
561and it should become clear what this option is about. In any case,
562including directory trees to the menu can take a lot of memory."
563 :set (function filesets-set-default)
564 :type 'integer
565 :group 'filesets)
566
567(defcustom filesets-commands
568 `(("Query Replace"
569 query-replace
570 (filesets-cmd-query-replace-getargs))
571 ("Query Replace (regexp)"
572 query-replace-regexp
573 (filesets-cmd-query-replace-getargs))
574 ("Grep <<selection>>"
575 "grep"
576 ("-n " filesets-get-quoted-selection " " "<<file-name>>"))
577 ("Run Shell Command"
578 filesets-cmd-shell-command
579 (filesets-cmd-shell-command-getargs)))
91cc505c 580 "Commands to run on filesets.
c0e48b0b
RS
581An association list of names, functions, and an argument list (or a
582function that returns one) to be run on a filesets' files.
583
584The argument <file-name> or <<file-name>> (quoted) will be replaced with
585the filename."
586 :set (function filesets-set-default+)
587 :type '(repeat :tag "Commands"
588 (list :tag "Definition" :value ("")
589 (string "Name")
590 (choice :tag "Command"
591 (string :tag "String")
592 (function :tag "Function"))
593 (repeat :tag "Argument List"
594 (choice :tag "Arguments"
595 (sexp :tag "Sexp"
596 :value nil)
597 (string :tag "File Name"
598 :value "<file-name>")
599 (string :tag "Quoted File Name"
600 :value "<<file-name>>")
601 (function :tag "Function"
602 :value nil)))))
603 :group 'filesets)
cd56bfef 604(put 'filesets-commands 'risky-local-variable t)
c0e48b0b
RS
605
606(defcustom filesets-external-viewers
607 (let
91cc505c
SM
608 ;; ((ps-cmd (or (and (boundp 'my-ps-viewer) my-ps-viewer)
609 ;; (filesets-select-command "ggv gv")))
610 ;; (pdf-cmd (or (and (boundp 'my-ps-viewer) my-pdf-viewer)
611 ;; (filesets-select-command "xpdf acroread")))
612 ;; (dvi-cmd (or (and (boundp 'my-ps-viewer) my-dvi-viewer)
613 ;; (filesets-select-command "xdvi tkdvi")))
614 ;; (doc-cmd (or (and (boundp 'my-ps-viewer) my-doc-viewer)
615 ;; (filesets-select-command "antiword")))
616 ;; (pic-cmd (or (and (boundp 'my-ps-viewer) my-pic-viewer)
617 ;; (filesets-select-command "gqview ee display"))))
c0e48b0b
RS
618 ((ps-cmd "ggv")
619 (pdf-cmd "xpdf")
620 (dvi-cmd "xdvi")
621 (doc-cmd "antiword")
622 (pic-cmd "gqview"))
623 `(("^.+\\..?html?$" browse-url
624 ((:ignore-on-open-all t)))
625 ("^.+\\.pdf$" ,pdf-cmd
626 ((:ignore-on-open-all t)
627 (:ignore-on-read-text t)
628 (:constraint-flag ,pdf-cmd)))
629 ("^.+\\.e?ps\\(.gz\\)?$" ,ps-cmd
630 ((:ignore-on-open-all t)
631 (:ignore-on-read-text t)
632 (:constraint-flag ,ps-cmd)))
633 ("^.+\\.dvi$" ,dvi-cmd
634 ((:ignore-on-open-all t)
635 (:ignore-on-read-text t)
636 (:constraint-flag ,dvi-cmd)))
637 ("^.+\\.doc$" ,doc-cmd
638 ((:capture-output t)
639 (:ignore-on-read-text t)
640 (:constraint-flag ,doc-cmd)))
641 ("^.+\\.\\(tiff\\|xpm\\|gif\\|pgn\\)$" ,pic-cmd
642 ((:ignore-on-open-all t)
643 (:ignore-on-read-text t)
644 (:constraint-flag ,pic-cmd)))))
91cc505c 645 "Association list of file patterns and external viewers for use with
c0e48b0b
RS
646`filesets-find-or-display-file'.
647
648Has the form ((FILE-PATTERN VIEWER PROPERTIES) ...), VIEWER being either a
649function or a command name as string.
650
4f955a15
JB
651Properties is an association list determining filesets' behavior in
652several conditions. Choose one from this list:
c0e48b0b
RS
653
654:ignore-on-open-all ... Don't open files of this type automatically --
655i.e. on open-all-files-events or when running commands
656
657:capture-output ... capture an external viewer output
658
659:constraintp FUNCTION ... use this viewer only if FUNCTION returns non-nil
660
f194e54a 661:constraint-flag SEXP ... use this viewer only if SEXP evaluates to non-nil
c0e48b0b
RS
662
663:open-hook HOOK ... run hooks after spawning the viewer -- mainly useful
664in conjunction with :capture-output
665
666:args (FORMAT-STRING or SYMBOL or FUNCTION) ... a list of arguments
667\(defaults to (list \"%S\")) when using shell commands
668
669Avoid modifying this variable and achieve minor speed-ups by setting the
670variables my-ps-viewer, my-pdf-viewer, my-dvi-viewer, my-pic-viewer.
671
672In order to view pdf or rtf files in an Emacs buffer, you could use these:
673
674
91cc505c 675 \(\"^.+\\\\.pdf\\\\'\" \"pdftotext\"
c0e48b0b
RS
676 \((:capture-output t)
677 \(:args (\"%S - | fmt -w \" window-width))
678 \(:ignore-on-read-text t)
679 \(:constraintp (lambda ()
680 \(and \(filesets-which-command-p \"pdftotext\")
681 \(filesets-which-command-p \"fmt\"))))))
91cc505c 682 \(\"^.+\\\\.rtf\\\\'\" \"rtf2htm\"
c0e48b0b
RS
683 \((:capture-output t)
684 \(:args (\"%S 2> /dev/null | w3m -dump -T text/html\"))
685 \(:ignore-on-read-text t)
686 \(:constraintp (lambda ()
687 \(and (filesets-which-command-p \"rtf2htm\")
91cc505c 688 \(filesets-which-command-p \"w3m\"))))))"
c0e48b0b
RS
689 :set (function filesets-set-default)
690 :type '(repeat :tag "Viewer"
691 (list :tag "Definition"
692 :value ("^.+\\.suffix$" "")
693 (regexp :tag "Pattern")
694 (choice :tag "Viewer"
695 (symbol :tag "Function" :value nil)
696 (string :tag "Program" :value ""))
697 (repeat :tag "Properties"
698 (choice
699 (list :tag ":constraintp"
700 :value (:constraintp)
701 (const :format ""
702 :value :constraintp)
703 (function :tag "Function"))
704 (list :tag ":constraint-flag"
705 :value (:constraint-flag)
706 (const :format ""
707 :value :constraint-flag)
f194e54a 708 (sexp :tag "Symbol"))
c0e48b0b
RS
709 (list :tag ":ignore-on-open-all"
710 :value (:ignore-on-open-all t)
711 (const :format ""
712 :value :ignore-on-open-all)
713 (boolean :tag "Boolean"))
714 (list :tag ":ignore-on-read-text"
715 :value (:ignore-on-read-text t)
716 (const :format ""
717 :value :ignore-on-read-text)
718 (boolean :tag "Boolean"))
719 (list :tag ":args"
720 :value (:args)
721 (const :format ""
722 :value :args)
723 (repeat :tag "List"
724 (choice :tag "Arguments"
725 (string :tag "String"
726 :value "")
727 (symbol :tag "Symbol"
728 :value nil)
729 (function :tag "Function"
730 :value nil))))
731 (list :tag ":open-hook"
732 :value (:open-hook)
733 (const :format ""
734 :value :open-hook)
735 (hook :tag "Hook"))
736; (list :tag ":close-hook"
737; :value (:close-hook)
738; (const :format ""
739; :value :close-hook)
740; (hook :tag "Hook"))
741 (list :tag ":capture-output"
742 :value (:capture-output t)
743 (const :format ""
744 :value :capture-output)
745 (boolean :tag "Boolean"))))))
746 :group 'filesets)
cd56bfef 747(put 'filesets-external-viewers 'risky-local-variable t)
c0e48b0b
RS
748
749(defcustom filesets-ingroup-patterns
750 '(("^.+\\.tex$" t
751 (((:name "Package")
752 (:pattern "\\\\usepackage\\W*\\(\\[[^\]]*\\]\\W*\\)?{\\W*\\(.+\\)\\W*}")
753 (:match-number 2)
754 (:stub-flag t)
755 (:get-file-name (lambda (master file)
756 (filesets-which-file master
757 (concat file ".sty")
e9bbdfc3 758 (filesets-convert-path-list
c0e48b0b
RS
759 (or (getenv "MY_TEXINPUTS")
760 (getenv "TEXINPUTS")))))))
761 ((:name "Include")
762 (:pattern "\\\\include\\W*{\\W*\\(.+\\)\\W*}")
763 (:get-file-name (lambda (master file)
764 (filesets-which-file master
765 (concat file ".tex")
e9bbdfc3 766 (filesets-convert-path-list
c0e48b0b
RS
767 (or (getenv "MY_TEXINPUTS")
768 (getenv "TEXINPUTS"))))))
769 (:scan-depth 5))
770 ((:name "Input")
771 (:pattern "\\\\input\\W*{\\W*\\(.+\\)\\W*}")
772 (:stubp (lambda (a b) (not (filesets-files-in-same-directory-p a b))))
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 "Bibliography")
781 (:pattern "\\\\bibliography\\W*{\\W*\\(.+\\)\\W*}")
782 (:get-file-name (lambda (master file)
783 (filesets-which-file master
784 (concat file ".bib")
e9bbdfc3 785 (filesets-convert-path-list
c0e48b0b
RS
786 (or (getenv "MY_BIBINPUTS")
787 (getenv "BIBINPUTS")))))))))
788 ("^.+\\.el$" t
789 (((:name "Require")
790 (:pattern "(require\\W+'\\(.+\\))")
791 (:stubp (lambda (a b) (not (filesets-files-in-same-directory-p a b))))
792 (:get-file-name (lambda (master file)
793 (filesets-which-file master
794 (concat file ".el")
795 load-path))))
796 ((:name "Load")
797 (:pattern "(load\\(-library\\)?\\W+\"\\(.+\\)\")")
798 (:match-number 2)
799 (:get-file-name (lambda (master file)
800 (filesets-which-file master file load-path))))))
801