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