Commit | Line | Data |
---|---|---|
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. | |
122 | Is buffer local variable.") | |
123 | ||
124 | (defvar filesets-verbosity 1 | |
9f243b0d RS |
125 | "An integer defining the level of verbosity. |
126 | 0 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 | ||
134 | Well, if you use XEmacs (prior to 21.5?) custom.el is loaded after | |
135 | init.el. This means that settings saved in the cache file (see | |
136 | `filesets-menu-cache-file') will be overwritten by custom.el. In order | |
137 | to ensure the use of the cache file, set this variable to t -- which is | |
138 | the default for XEmacs prior to 21.5. If you want to change this value | |
139 | put \"(setq filesets-menu-ensure-use-cached VALUE)\" into your startup | |
140 | file -- before loading filesets.el. | |
141 | ||
142 | So, when should you think about setting this value to t? If filesets.el | |
143 | is loaded before user customizations. Thus, if (require 'filesets) | |
ea6c930a JB |
144 | precedes the `custom-set-variables' command or, for XEmacs, if init.el |
145 | is 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. | |
151 | COND-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 |
172 | Like `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 | 182 | It is supposed to work like cl's `member*'. At the moment only the :test |
f194e54a RS |
183 | key 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'. |
254 | If SYM is in the list `filesets-ignore-next-set-default', delete | |
255 | it from that list, and return nil. Otherwise, set the value of | |
256 | SYM 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 |
312 | See `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 |
321 | See `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 |
330 | See `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 | 356 | Set this to \"\", to disable caching of menus. |
c0e48b0b RS |
357 | Don'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 | |
370 | Possible uses: don't save configuration data in the main startup files | |
371 | but in filesets's own cache. In this case add `filesets-data' to this | |
372 | list. | |
373 | ||
91cc505c | 374 | There is a second reason for putting `filesets-data' on this list. If |
c0e48b0b RS |
375 | you frequently add and remove buffers on the fly to :files filesets, you |
376 | don't need to save your customizations if `filesets-data' is being | |
91cc505c | 377 | mirrored in the cache file. In this case the version in the cache file |
c0e48b0b RS |
378 | is the current one, and the version in your startup file will be |
379 | silently updated later on. | |
380 | ||
381 | If you want caching to work properly, at least `filesets-submenus', | |
382 | `filesets-menu-cache', and `filesets-ingroup-cache' should be in this | |
383 | list. | |
384 | ||
385 | Don'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 | |
409 | The hook is called with the cache file as current buffer and the cursor | |
410 | at the last position. I.e. each hook has to make sure that the cursor is | |
411 | at the last position. | |
412 | ||
413 | Possible uses: If you don't want to save `filesets-data' in your normal | |
414 | configuration 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 | ||
421 | to this hook. | |
422 | ||
423 | Don'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 |
430 | If the current name differs from the cached one, |
431 | rebuild 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 | 438 | If this variable is set to nil and if Emacs crashes, the cache and |
91cc505c | 439 | filesets-data could get out of sync. Set this to t if this happens from |
c0e48b0b RS |
440 | time 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 |
447 | Set this value to 0 to turn menu splitting off. BTW, parts of submenus |
448 | will 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 |
461 | When using an external command, \"%s\" will be replaced with the |
462 | directory's name. | |
463 | ||
464 | Note: 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 | |
481 | visiting files. This function checks if an external viewer is defined | |
482 | for 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 |
487 | readable, will not be opened. |
488 | ||
489 | Caveat: 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 |
502 | Caveat: 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 |
516 | This is for calls via `filesets-find-or-display-file' |
517 | or `filesets-find-file'. | |
518 | ||
44e97401 | 519 | Set 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 |
526 | This is useful if you want to use the same startup files in different |
527 | computer 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 | 546 | A :tree fileset is defined by a base directory the contents of which |
cd56bfef | 547 | will be recursively added to the menu. `filesets-tree-max-level' tells up |
c0e48b0b RS |
548 | to which level the directory structure should be scanned/listed, |
549 | i.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 | ||
560 | and it should become clear what this option is about. In any case, | |
561 | including 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 |
586 | An association list of names, functions, and an argument list (or a |
587 | function that returns one) to be run on a filesets' files. | |
588 | ||
589 | The argument <file-name> or <<file-name>> (quoted) will be replaced with | |
590 | the 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 | ||
653 | Has the form ((FILE-PATTERN VIEWER PROPERTIES) ...), VIEWER being either a | |
654 | function or a command name as string. | |
655 | ||
4f955a15 JB |
656 | Properties is an association list determining filesets' behavior in |
657 | several conditions. Choose one from this list: | |
c0e48b0b RS |
658 | |
659 | :ignore-on-open-all ... Don't open files of this type automatically -- | |
660 | i.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 | |
669 | in 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 | ||
674 | Avoid modifying this variable and achieve minor speed-ups by setting the | |
675 | variables my-ps-viewer, my-pdf-viewer, my-dvi-viewer, my-pic-viewer. | |
676 | ||
677 | In 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 |