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