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