0
|
1 ;;; recent-files.el --- Maintain menu of recently opened files.
|
134
|
2 ;;; $Header: /afs/informatik.uni-tuebingen.de/local/web/xemacs/xemacs-cvs/XEmacs/xemacs/lisp/packages/Attic/recent-files.el,v 1.2 1997/04/19 23:21:11 steve Exp $
|
0
|
3 ;;;
|
|
4 ;;; Copyright (C) 1994, 1995 Juergen Nickelsen <nickel@cs.tu-berlin.de>
|
|
5 ;;;
|
|
6 ;; Keywords: menu, file
|
|
7
|
|
8 ;; This file is part of XEmacs.
|
|
9
|
|
10 ;; XEmacs is free software; you can redistribute it and/or modify it
|
|
11 ;; under the terms of the GNU General Public License as published by
|
|
12 ;; the Free Software Foundation; either version 2, or (at your option)
|
|
13 ;; any later version.
|
|
14
|
|
15 ;; XEmacs is distributed in the hope that it will be useful, but
|
|
16 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
18 ;; General Public License for more details.
|
|
19
|
|
20 ;; You should have received a copy of the GNU General Public License
|
70
|
21 ;; along with XEmacs; see the file COPYING. If not, write to the
|
|
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
23 ;; Boston, MA 02111-1307, USA.
|
0
|
24
|
|
25 ;;; Synched up with: Not in FSF.
|
|
26 ;;;
|
|
27 ;;; recent-files.el is free software; you can redistribute it and/or
|
|
28 ;;; modify it under the terms of the GNU General Public License as
|
|
29 ;;; published by the Free Software Foundation; either version 2, or
|
|
30 ;;; (at your option) any later version.
|
|
31 ;;;
|
|
32 ;;; It is distributed in the hope that it will be useful, but WITHOUT
|
|
33 ;;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
34 ;;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
35 ;;; License for more details.
|
|
36 ;;;
|
|
37 ;;; You should have received a copy of the GNU General Public License
|
|
38 ;;; along with XEmacs; see the file COPYING. If not, write to the
|
|
39 ;;; Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
40 ;;; ------------------------------------------------------------------
|
|
41 ;;;
|
|
42 ;;; Enough of this boring stuff. To install recent-files, put the
|
|
43 ;;; following statements into your .emacs file
|
|
44 ;;; (load "recent-files")
|
|
45 ;;; (recent-files-initialize)
|
|
46 ;;; and place the file recent-files.el in a directory in your XEmacs's
|
|
47 ;;; load-path. In order to use recent-files with dired, dired has to
|
|
48 ;;; be loaded first. recent-files is known to work with Lucid Emacs /
|
|
49 ;;; XEmacs 19.8 and higher; it does not work correctly with 19.6 or
|
|
50 ;;; earlier versions due to a bug in add-menu.
|
|
51 ;;;
|
|
52 ;;; recent-files adds the menu "Recent Files" (or whatever name you
|
|
53 ;;; choose, see "Customization:" below) to Emacs's menubar. Its
|
|
54 ;;; entries are the files (and directories) that have recently been
|
|
55 ;;; opened by Emacs. You can open one of these files again by
|
|
56 ;;; selecting its entry in the "Recent Files" menu. The list of file
|
|
57 ;;; entries in this menu is preserved from one Emacs session to
|
|
58 ;;; another. You can prevent Emacs from saving this list by selecting
|
|
59 ;;; "Don't save recent-files list on exit" from the menu. If you have
|
|
60 ;;; disabled saving, you can re-enable it by selecting "Save
|
|
61 ;;; recent-files list on exit".
|
|
62 ;;;
|
|
63 ;;; The menu has permanent and non-permanent entries. Permanent
|
|
64 ;;; entries are marked with an asterisk in front of the filename. The
|
|
65 ;;; non-permanent entries are hidden in a submenu.
|
|
66 ;;;
|
|
67 ;;; Each time you open a file in Emacs, it is added as a non-permanent
|
|
68 ;;; entry to the menu. The value of `recent-files-number-of-entries'
|
|
69 ;;; determines how many non-permanent entries are held in the
|
|
70 ;;; menu. When the number of non-permanent entries reaches this value,
|
|
71 ;;; the least recently added non-permanent entry is removed from the
|
|
72 ;;; menu when another non-permanent entry is added. It is not removed
|
|
73 ;;; from the list, though; it may reappear when entries are deleted
|
|
74 ;;; from the list. The number of entries saved to disk is the value of
|
|
75 ;;; the variable `recent-files-number-of-saved-entries'.
|
|
76 ;;;
|
|
77 ;;; Permanent entries are not removed from the menu. You can make a
|
|
78 ;;; file entry permanent by selecting "Make <buffer> permanent" (where
|
|
79 ;;; <buffer> is the name of the current buffer) when the current
|
|
80 ;;; buffer holds this file. "Make <buffer> non-permanent" makes the
|
|
81 ;;; file entry of the current buffer non-permanent.
|
|
82 ;;;
|
|
83 ;;; The command "Kill buffer <buffer> and delete entry" is handy when
|
|
84 ;;; you have accidently opened a file but want to keep neither the
|
|
85 ;;; buffer nor the entry.
|
|
86 ;;;
|
|
87 ;;; You can erase the list of non-permanent entries by selecting
|
|
88 ;;; "Erase non-permanent entries" from the menu.
|
|
89 ;;;
|
|
90 ;;; Customization:
|
|
91 ;;;
|
|
92 ;;; There are lots of variables to control the behaviour of
|
|
93 ;;; recent-files. You do not have to change any of them if you like it
|
|
94 ;;; as it comes out of the box. However, you may want to look at these
|
|
95 ;;; options to make it behave different.
|
|
96 ;;;
|
|
97 ;;; `recent-files-number-of-entries'
|
|
98 ;;; Controls how many non-permanent entries are shown in the
|
|
99 ;;; recent-files list. The default is 15.
|
|
100 ;;;
|
|
101 ;;; `recent-files-number-of-saved-entries'
|
|
102 ;;; Controls how many non-permanent entries are saved to disk when
|
|
103 ;;; Emacs exits or recent-files-save-the-list is called. The
|
|
104 ;;; default is 50.
|
|
105 ;;;
|
|
106 ;;; `recent-files-save-file'
|
|
107 ;;; The name of the file where the recent-files list is saved
|
|
108 ;;; between Emacs session. You probably don't need to change this.
|
|
109 ;;; The default is ".recent-files.el" in your home directory.
|
|
110 ;;;
|
|
111 ;;; `recent-files-dont-include'
|
|
112 ;;; A list of regular expressions for files that should not be
|
|
113 ;;; included into the recent-files list. This list is empty by
|
|
114 ;;; default. For instance, a list to exclude all .newsrc
|
|
115 ;;; files, all auto-save-files, and all files in the /tmp
|
|
116 ;;; directory (but not the /tmp directory itself) would look
|
|
117 ;;; like this:
|
|
118 ;;; (setq recent-files-dont-include
|
|
119 ;;; '("/\\.newsrc" "~$" "^/tmp/."))
|
|
120 ;;; The default is empty.
|
|
121 ;;;
|
|
122 ;;; `recent-files-use-full-names'
|
|
123 ;;; If the value of this variable is non-nil, the full pathnames of
|
|
124 ;;; the files are shown in the recent-files menu. Otherwise only
|
|
125 ;;; the filename part (or the last name component if it is a
|
|
126 ;;; directory) is shown in the menu. The default it t, i.e. show
|
|
127 ;;; full names.
|
|
128 ;;;
|
|
129 ;;; `recent-files-filename-replacements'
|
|
130 ;;; This is a list of pairs of regular expressions and replacement
|
|
131 ;;; strings. If a filename matches one of the regular expressions,
|
|
132 ;;; the matching part is replaced by the replacement string for
|
|
133 ;;; display in the recent-files menu.
|
|
134 ;;; Example: My home directory is "/users/mmc/nickel/". I want to
|
|
135 ;;; replace it with "~/". I also want to replace the directory
|
|
136 ;;; "/imports/teleservices/mmc/avc2/", where I work a lot, with
|
|
137 ;;; ".../avc2/". The list then looks like
|
|
138 ;;; (setq recent-files-filename-replacements
|
|
139 ;;; '(("/users/mmc/nickel/" . "~/")
|
|
140 ;;; ("/imports/teleservices/mmc/avc2/" . ".../avc2/")))
|
|
141 ;;; Only the first match is replaced. So, if you have several
|
|
142 ;;; entries in this list that may match a filename simultaneously,
|
|
143 ;;; put the one you want to match (usually the most special) in
|
|
144 ;;; front of the others. The default is to replace the home
|
|
145 ;;; directory with "~".
|
|
146 ;;;
|
|
147 ;;; `recent-files-sort-function'
|
|
148 ;;; Contains a function symbol to sort the display of filenames in
|
|
149 ;;; the recent-files menu. Supplied are two functions,
|
|
150 ;;; 'recent-files-dont-sort and 'recent-files-sort-alphabetically.
|
|
151 ;;; The first, which is the default, preserves the order of "most
|
|
152 ;;; recent on top".
|
|
153 ;;;
|
|
154 ;;; `recent-files-permanent-submenu'
|
|
155 ;;; If this variable is non-nil, the permanent entries are put into
|
|
156 ;;; a separate submenu of the recent-files menu. The default is
|
|
157 ;;; nil.
|
|
158 ;;;
|
|
159 ;;; `recent-files-non-permanent-submenu'
|
|
160 ;;; If this variable is non-nil, the non-permanent entries are put
|
|
161 ;;; into a separate submenu of the recent-files menu. The default
|
|
162 ;;; is nil. (You can set both `recent-files-permanent-submenu' and
|
|
163 ;;; `recent-files-non-permanent-submenu' to t to have both lists in
|
|
164 ;;; separate submenus.)
|
|
165 ;;;
|
|
166 ;;; `recent-files-commands-submenu'
|
|
167 ;;; If this variable is non-nil, the commands if recent-files are
|
|
168 ;;; placed in a submenu of the recent-files menu. The default is
|
|
169 ;;; nil.
|
|
170 ;;;
|
|
171 ;;; `recent-files-commands-submenu-title'
|
|
172 ;;; If the commands are placed in a submenu, this string is used as
|
|
173 ;;; the title of the submenu. The default is "Commands...".
|
|
174 ;;;
|
|
175 ;;; `recent-files-actions-on-top'
|
|
176 ;;; If this variable is non-nil, the "action" menu entries ("Make
|
|
177 ;;; <buffer> permanent" etc.) are put on top of the menu. Otherwise
|
|
178 ;;; they appear below the file entries or submenus. The default is
|
|
179 ;;; nil.
|
|
180 ;;;
|
|
181 ;;; `recent-files-permanent-first'
|
|
182 ;;; If this variable is t, the permanent entries are put first in
|
|
183 ;;; the recent-files menu, i.e. above the non-permanent entries. If
|
|
184 ;;; the value is nil, non-permanent entries appear first. If the
|
|
185 ;;; value is neither t nor nil, the entries are sorted according to
|
|
186 ;;; recent-files-sort-function. The default is 'sort.
|
|
187 ;;;
|
|
188 ;;; `recent-files-find-file-command'
|
|
189 ;;; This variable contains to commandto execute when a file entry
|
|
190 ;;; is selected from the menu. Usually this will be `find-file',
|
|
191 ;;; which is the default.
|
|
192 ;;;
|
|
193 ;;; KNOWN BUG:
|
|
194 ;;; - recent-files overwrites the recent-files-save-file
|
|
195 ;;; unconditionally when Emacs exits. If you have two Emacs
|
|
196 ;;; processes running, the one exiting later will overwrite the
|
|
197 ;;; file without merging in the new entries from the other Emacs
|
|
198 ;;; process. This can be avoided by disabling the save on exit from
|
|
199 ;;; the menu.
|
|
200
|
|
201 (if (not (string-match "XEmacs" (emacs-version)))
|
|
202 (error "recent-files works with Lucid Emacs / XEmacs only."))
|
|
203
|
|
204 (provide 'recent-files)
|
|
205
|
|
206
|
|
207 ;;; User options
|
|
208
|
134
|
209 (defgroup recent-files nil
|
|
210 "Maintain a menu of recently opened files."
|
|
211 :group 'data)
|
0
|
212
|
134
|
213 (defgroup recent-files-menu nil
|
|
214 "Menu options of recent-files."
|
|
215 :prefix "recent-files-"
|
|
216 :group 'recent-files)
|
|
217
|
|
218
|
|
219 (defcustom recent-files-number-of-entries 15
|
|
220 "*Maximum of non-permanent entries in the recent-files menu."
|
|
221 :type 'integer
|
|
222 :group 'recent-files)
|
0
|
223
|
134
|
224 (defcustom recent-files-number-of-saved-entries 50
|
|
225 "*Maximum of non-permanent entries saved to `recent-files-save-file'."
|
|
226 :type 'integer
|
|
227 :group 'recent-files)
|
0
|
228
|
134
|
229 (defcustom recent-files-save-file (expand-file-name "~/.recent-files.el")
|
|
230 "*File to save the recent-files list in."
|
|
231 :type 'file
|
|
232 :group 'recent-files)
|
0
|
233
|
134
|
234 (defcustom recent-files-dont-include nil
|
|
235 "*List of regexps for filenames *not* to keep in recent-files."
|
|
236 :type '(repeat regexp)
|
|
237 :group 'recent-files)
|
|
238
|
|
239 (defcustom recent-files-use-full-names t
|
0
|
240 "*If non-nil, use the full pathname of a file in the recent-files menu.
|
|
241 Otherwise use only the filename part. The `recent-files-filename-replacements'
|
134
|
242 are not applied in the latter case."
|
|
243 :type 'boolean
|
|
244 :group 'recent-files)
|
0
|
245
|
134
|
246 (defcustom recent-files-filename-replacements
|
0
|
247 (list (cons (expand-file-name "~") "~"))
|
|
248 "*List of regexp/replacement pairs for filename filenamees.
|
|
249 If a filename of a filename matches one of the regexps, it is replaced
|
134
|
250 by the corresponding replacement."
|
|
251 :type '(repeat (cons regexp (string :tag "Replacement")))
|
|
252 :group 'recent-files)
|
0
|
253
|
134
|
254 (defcustom recent-files-sort-function (function recent-files-dont-sort)
|
0
|
255 "*Function to sort the recent-files list with.
|
|
256 The value `recent-files-dont-sort' means to keep the \"most recent on top\"
|
134
|
257 order."
|
|
258 :type 'function
|
|
259 :group 'recent-files)
|
0
|
260
|
134
|
261 (defcustom recent-files-permanent-submenu nil
|
|
262 "*If non-nil, put the permanent entries of recent-files into a submenu."
|
|
263 :type 'boolean
|
|
264 :group 'recent-files-menu)
|
0
|
265
|
134
|
266 (defcustom recent-files-non-permanent-submenu t
|
|
267 "*If non-nil, put the non-permanent entries of recent-files into a submenu."
|
|
268 :type 'boolean
|
|
269 :group 'recent-files-menu)
|
0
|
270
|
134
|
271 (defcustom recent-files-commands-submenu nil
|
|
272 "*If non-nil, put the commands of recent-files into a submenu."
|
|
273 :type 'boolean
|
|
274 :group 'recent-files-menu)
|
0
|
275
|
134
|
276 (defcustom recent-files-commands-submenu-title "Commands..."
|
|
277 "*Title of the commands submenu of recent-files."
|
|
278 :type 'string
|
|
279 :group 'recent-files-menu)
|
0
|
280
|
134
|
281 (defcustom recent-files-menu-title "Recent Files"
|
|
282 "*Name to be displayed as title of the recent-files menu."
|
|
283 :type 'string
|
|
284 :group 'recent-files-menu)
|
0
|
285
|
134
|
286 (defcustom recent-files-menu-path nil
|
0
|
287 "*Path where to add the recent-files menu.
|
|
288 A value of nil means add it as top-level menu.
|
134
|
289 For more information look up the documentation of `add-menu'."
|
|
290 :type '(choice (const :tag "Top Level" nil)
|
|
291 (sexp :tag "Menu Path"))
|
|
292 :group 'recent-files-menu)
|
0
|
293
|
134
|
294 (defcustom recent-files-add-menu-before nil
|
0
|
295 "*Name of the menu before which the recent-files menu shall be added.
|
|
296 A value of nil means add it as the last menu in recent-files-menu-path.
|
134
|
297 For more information look up the documentation of `add-menu'."
|
|
298 :type '(choice (string :tag "Name")
|
|
299 (const :tag "Last" nil))
|
|
300 :group 'recent-files-menu)
|
0
|
301
|
134
|
302 (defcustom recent-files-actions-on-top nil
|
|
303 "*If non-nil, put the actions on top of the recent-files menu."
|
|
304 :type 'boolean
|
|
305 :group 'recent-files-menu)
|
0
|
306
|
134
|
307 (defcustom recent-files-permanent-first 'sort
|
0
|
308 "*Control the placement of entries in the recent-files menu.
|
|
309 If the value is t, permanent entries are put first.
|
|
310 If the value is nil, non-permanent entries are put first.
|
|
311 If the value is neither, the entries are mixed following
|
134
|
312 recent-files-sort-function if neither appear in a submenu."
|
|
313 :type '(choice (const :tag "Permanent First" t)
|
|
314 (const :tag "Non-Permanent First" nil)
|
|
315 (sexp :tag "Mixed"))
|
|
316 :group 'recent-files-menu)
|
0
|
317
|
134
|
318 (defcustom recent-files-find-file-command (function find-file)
|
|
319 "*Command to invoke with an entry of the recent-files list."
|
|
320 :type 'function
|
|
321 :group 'recent-files)
|
0
|
322
|
134
|
323 (defcustom recent-files-include-save-now nil
|
|
324 "*If non-nil, have a menu entry to save the recent-files list immediately."
|
|
325 :type 'boolean
|
|
326 :group 'recent-files-menu)
|
0
|
327
|
|
328 ;;; Internal variables
|
|
329
|
|
330 (defconst recent-files-save-list-on-exit t
|
|
331 "If non-nil, save the recent-files list on exit.
|
|
332 This value is toggled by a menu entry.")
|
|
333
|
|
334 (defvar recent-files-list nil
|
|
335 "List of recently opened files.
|
|
336 Entries are pairs like (<filename> . <permant-p>).
|
|
337 If <permanent-p> is non-nil, the file stays permanently in the list.")
|
|
338
|
|
339 (defvar recent-files-commands-menu
|
|
340 '(list (vector (concat "Make " lastpart " permanent")
|
|
341 (function recent-files-make-permanent)
|
|
342 (and lastpart
|
|
343 (not (recent-files-permanent-p filename))
|
|
344 ;; (not (not ...)) is needed to enforce t for non-nil
|
|
345 (not (not (recent-files-retrieve-entry filename)))))
|
|
346 (vector (concat "Make " lastpart " non-permanent")
|
|
347 (function recent-files-make-non-permanent)
|
|
348 (and lastpart
|
|
349 (recent-files-permanent-p filename)
|
|
350 (not (not (recent-files-retrieve-entry filename)))))
|
|
351 (vector "Erase non-permanent entries"
|
|
352 (function recent-files-erase-non-permanent)
|
|
353 t)
|
|
354 (vector (if recent-files-save-list-on-exit
|
|
355 "Don't save recent-files list on exit"
|
|
356 "Save recent-files list on exit")
|
|
357 ;; for some weird reason a (function (lambda ...))
|
|
358 ;; doesn't work here
|
|
359 (function recent-files-toggle-save-list-on-exit)
|
|
360 t)
|
|
361 (vector "Save recent-files list now"
|
|
362 (function recent-files-save-the-list)
|
|
363 t)
|
|
364 (vector (concat "Kill buffer " lastpart
|
|
365 " and delete entry")
|
|
366 (function recent-files-kill-buffer-delete-entry)
|
|
367 lastpart))
|
|
368 "Command menu definition for recent-files.
|
|
369 This definition is evaluated in a context where `filename' holds the file
|
|
370 name of the current buffer and `lastpart' holds the last component of
|
|
371 `filename'.")
|
|
372
|
|
373
|
|
374 (defconst recent-files-save-file-header
|
|
375 ";; This file is generated by recent-files.
|
|
376 ;; The car of each entry of recent-files-save-list is to appear in the
|
|
377 ;; `recent-files' menu. If the cdr of an entry is t, the file is to stay
|
|
378 ;; in the menu permanently.
|
|
379 ;; Saved at %s.
|
|
380
|
|
381 " "Header to be written into the `recent-files-save-file'.")
|
|
382
|
|
383
|
|
384 (defconst recent-files-buffer-name " *recent files save list*"
|
|
385 "Name of the buffer to build the save file in.")
|
|
386
|
|
387 (defvar recent-files-list-changed-p t
|
|
388 "Non-nil if the recent-files-list has changed after last menubar update.")
|
|
389
|
|
390 (defvar recent-files-last-buffer nil
|
|
391 "Buffer at the time of last recent-files menu rebuild.
|
|
392 If the buffer has changed, the menu must be rebuilt.")
|
|
393
|
|
394 ;;; Module initialization
|
|
395
|
|
396 (defun recent-files-initialize ()
|
|
397 "Initialize the recent-files menu."
|
|
398 (interactive)
|
|
399 (add-hook 'find-file-hooks (function recent-files-find-and-write-file-hook))
|
|
400 (add-hook 'dired-after-readin-hook
|
|
401 (function recent-files-find-and-write-file-hook))
|
|
402 (add-hook 'kill-emacs-hook (function recent-files-save-the-list))
|
|
403 (add-hook 'activate-menubar-hook (function recent-files-update-menu))
|
|
404 (add-hook 'write-file-hooks (function recent-files-find-and-write-file-hook))
|
|
405 ;; Initialize recent-files-list only if it is non-nil.
|
|
406 (cond (recent-files-list
|
|
407 (message "recent-files is already initialized."))
|
|
408 ((file-readable-p recent-files-save-file)
|
|
409 (setq recent-files-list-changed-p t)
|
|
410 (load-file recent-files-save-file)))
|
|
411 (recent-files-update-menu))
|
|
412
|
|
413
|
|
414 (defun recent-files-version ()
|
|
415 "Return a string identifying the current verion of recent-files.
|
|
416 If called interactively, show it in the echo area."
|
|
417 (interactive)
|
134
|
418 (let ((version "$Header: /afs/informatik.uni-tuebingen.de/local/web/xemacs/xemacs-cvs/XEmacs/xemacs/lisp/packages/Attic/recent-files.el,v 1.2 1997/04/19 23:21:11 steve Exp $"))
|
0
|
419 (if (interactive-p)
|
|
420 (message version)
|
|
421 version)))
|
|
422
|
|
423
|
|
424 ;;; Hook functions
|
|
425
|
|
426 (defun recent-files-find-and-write-file-hook ()
|
|
427 "Find-file-hook, write-file-hook, and dired-mode-hook for recent-files.
|
|
428 Inserts the name of the file just opened or written into the
|
|
429 `recent-files-list' and updates the recent-files menu."
|
|
430 (recent-files-add-file (recent-files-get-file-name))
|
|
431 nil)
|
|
432
|
|
433
|
|
434 (defun recent-files-get-file-name ()
|
|
435 "Return the filename of the current buffer or nil, if there is none.
|
|
436 This functions is supposed to do \"the right thing\" also for some modes
|
|
437 with no buffer-file-name. Currently supported: 'dired-mode."
|
|
438 (cond (buffer-file-name
|
|
439 buffer-file-name)
|
|
440 ((eq major-mode 'dired-mode)
|
|
441 (dired-current-directory))))
|
|
442
|
|
443
|
|
444 (defun recent-files-save-the-list ()
|
|
445 "Save the current `recent-files-list' to the file `recent-files-save-file'.
|
|
446 This is done by writing a `setq' statement to `recent-files-list' into
|
|
447 the file."
|
|
448 (interactive)
|
|
449 (if recent-files-save-list-on-exit
|
|
450 (let ((l (recent-files-enforce-max-length
|
|
451 recent-files-number-of-saved-entries
|
|
452 recent-files-list)))
|
|
453 (save-excursion
|
|
454 (set-buffer (get-buffer-create recent-files-buffer-name))
|
|
455 (erase-buffer)
|
|
456 (insert (format recent-files-save-file-header (current-time-string)))
|
|
457 (insert "(setq recent-files-list \n '(")
|
|
458 (if l
|
|
459 (progn
|
|
460 (while l
|
|
461 (if (bolp)
|
|
462 (insert " "))
|
|
463 (prin1 (car l) (current-buffer))
|
|
464 (insert "\n")
|
|
465 (setq l (cdr l)))
|
|
466 (forward-line -1)))
|
|
467 (end-of-line)
|
|
468 (insert "))")
|
|
469 (if (file-writable-p recent-files-save-file)
|
|
470 (write-region (point-min) (point-max) recent-files-save-file))
|
|
471 (kill-buffer (current-buffer))))))
|
|
472
|
|
473
|
|
474 ;;; Construct the menu
|
|
475
|
|
476 (defun recent-files-update-menu ()
|
|
477 "Update the recent-files menu from the recent-files-list."
|
|
478 (if (or recent-files-list-changed-p
|
|
479 (not recent-files-last-buffer)
|
|
480 (not (eq recent-files-last-buffer
|
|
481 (current-buffer))))
|
|
482 ;; This is an ugly mess...
|
|
483 (let ((action-menu-entries
|
|
484 (let ((entries
|
|
485 (let* ((filename (recent-files-get-file-name))
|
|
486 (lastpart (recent-files-last-part-of-name
|
|
487 filename)))
|
|
488 (eval recent-files-commands-menu))))
|
|
489 (if recent-files-commands-submenu
|
|
490 (list (cons recent-files-commands-submenu-title
|
|
491 entries))
|
|
492 entries)))
|
|
493 permanent non-permanent all)
|
|
494 ;; ... getting weirder by the minute ...
|
|
495 (if (or recent-files-permanent-submenu
|
|
496 recent-files-non-permanent-submenu
|
|
497 (null recent-files-permanent-first)
|
|
498 (eq t recent-files-permanent-first))
|
|
499 (progn
|
|
500 (setq permanent (recent-files-make-file-menu-entries
|
|
501 recent-files-list
|
|
502 (function recent-files-filter-permanent)))
|
|
503 (setq non-permanent (recent-files-make-file-menu-entries
|
|
504 recent-files-list
|
|
505 (function
|
|
506 recent-files-filter-non-permanent))))
|
|
507 (setq all (recent-files-make-file-menu-entries
|
|
508 recent-files-list
|
|
509 (function (lambda (l) l)))))
|
|
510 (if recent-files-permanent-submenu
|
|
511 (setq permanent (list (cons "Permanent entries..." permanent))))
|
|
512 (if recent-files-non-permanent-submenu
|
|
513 (setq non-permanent (list (cons "Non-permanent entries..."
|
|
514 non-permanent))))
|
|
515 ;;; ... and now even uglier.
|
|
516 (add-menu recent-files-menu-path recent-files-menu-title
|
|
517 (nconc
|
|
518 (if recent-files-actions-on-top
|
|
519 (append action-menu-entries (list "-----")))
|
|
520 (if (or recent-files-permanent-submenu
|
|
521 recent-files-non-permanent-submenu)
|
|
522 (if recent-files-permanent-first
|
|
523 (nconc permanent non-permanent)
|
|
524 (nconc non-permanent permanent))
|
|
525 (cond ((eq t recent-files-permanent-first)
|
|
526 (nconc permanent non-permanent))
|
|
527 ((null recent-files-permanent-first)
|
|
528 (nconc non-permanent permanent))
|
|
529 (t all)))
|
|
530 (if (not recent-files-actions-on-top)
|
|
531 (cons "-----"
|
|
532 action-menu-entries)))
|
|
533 recent-files-add-menu-before)
|
|
534 (setq recent-files-list-changed-p nil)
|
|
535 (setq recent-files-last-buffer (current-buffer))))
|
|
536 nil)
|
|
537
|
|
538
|
|
539 (defun recent-files-retrieve-entry (filename)
|
|
540 "Retrieve an entry from the recent-files list."
|
|
541 (assoc filename recent-files-list))
|
|
542
|
|
543
|
|
544 (defun recent-files-make-file-menu-entries (recent-list filter)
|
|
545 "Make file menu entries for recent-files from RECENT-LIST using FILTER."
|
|
546 (mapcar (function recent-files-entry-to-menu-entry)
|
|
547 (funcall filter
|
|
548 (funcall recent-files-sort-function
|
|
549 (recent-files-enforce-max-length
|
|
550 recent-files-number-of-entries
|
|
551 recent-list)))))
|
|
552
|
|
553
|
|
554 (defun recent-files-last-part-of-name (filename)
|
|
555 "Return last part of FILENAME."
|
|
556 (if filename
|
|
557 (if (and (file-directory-p filename)
|
|
558 (equal (substring filename -1) "/"))
|
|
559 (concat (file-name-nondirectory
|
|
560 (substring filename 0 -1))
|
|
561 "/")
|
|
562 (file-name-nondirectory filename))))
|
|
563
|
|
564
|
|
565 (defun recent-files-filter-permanent (recent-list)
|
|
566 "Return list of permanent entries in RECENT-LIST."
|
|
567 (cond ((null recent-list) nil)
|
|
568 ((recent-files-permanent-p (car (car recent-list)))
|
|
569 (cons (car recent-list)
|
|
570 (recent-files-filter-permanent (cdr recent-list))))
|
|
571 (t (recent-files-filter-permanent (cdr recent-list)))))
|
|
572
|
|
573
|
|
574 (defun recent-files-filter-non-permanent (recent-list)
|
|
575 "Return list of non-permanent entries in RECENT-LIST."
|
|
576 (cond ((null recent-list) nil)
|
|
577 ((recent-files-permanent-p (car (car recent-list)))
|
|
578 (recent-files-filter-non-permanent (cdr recent-list)))
|
|
579 (t (cons (car recent-list)
|
|
580 (recent-files-filter-non-permanent (cdr recent-list))))))
|
|
581
|
|
582
|
|
583 (defun recent-files-permanent-p (filename)
|
|
584 "Return non-nil if FILENAME is a permanent entry in the recent-files menu."
|
|
585 (cdr (recent-files-retrieve-entry filename)))
|
|
586
|
|
587
|
|
588 (defun recent-files-entry-to-menu-entry (entry)
|
|
589 "Build a menu entry from an entry in `recent-files-list'."
|
|
590 (vector (concat (if (cdr entry)
|
|
591 "* "
|
|
592 " ")
|
|
593 (if recent-files-use-full-names
|
|
594 (recent-files-replace-filenames (car entry))
|
|
595 (recent-files-last-part-of-name (car entry))))
|
|
596 (list recent-files-find-file-command (car entry))
|
|
597 t))
|
|
598
|
|
599
|
|
600 (defun recent-files-replace-filenames (filename)
|
|
601 "Replace the part of FILENAME that matches a regular expression
|
|
602 in recent-files-filename-replacements with the corrensponding replacement.
|
|
603 If FILENAME does not match any regular expression, return it unchanged.
|
|
604 Only the first matching regexp/replacement pair is applied."
|
|
605 (let ((replist recent-files-filename-replacements)
|
|
606 (retval filename)
|
|
607 (matched nil))
|
|
608 (while (and replist
|
|
609 (not matched))
|
|
610 (if (string-match (car (car replist)) filename)
|
|
611 (progn
|
|
612 (setq matched t)
|
|
613 (setq retval (concat (substring filename 0 (match-beginning 0))
|
|
614 (cdr (car replist))
|
|
615 (substring filename (match-end 0))))))
|
|
616 (setq replist (cdr replist)))
|
|
617 retval))
|
|
618
|
|
619
|
|
620 ;;; add a new entry
|
|
621
|
|
622 (defun recent-files-add-file (filename)
|
|
623 "Add file FILENAME to `recent-files-list'.
|
|
624 FILENAME is not really added if it matches one of the regexps in
|
|
625 `recent-files-dont-include'."
|
|
626 (if (recent-files-no-match filename recent-files-dont-include)
|
|
627 (progn
|
|
628 (setq recent-files-list-changed-p t)
|
|
629 (setq recent-files-list
|
|
630 (cons (or (recent-files-retrieve-entry filename)
|
|
631 (cons filename nil))
|
|
632 (recent-files-remove-entry filename
|
|
633 recent-files-list))))))
|
|
634
|
|
635
|
|
636 (defun recent-files-dont-sort (recent-list)
|
|
637 "Return RECENT-LIST.
|
|
638 This is a dummy sorting function for the recent-files-list."
|
|
639 recent-list)
|
|
640
|
|
641 (defun recent-files-sort-alphabetically (recent-list)
|
|
642 "Return RECENT-LIST sorted alphabetically by the cars of the elements."
|
|
643 (sort recent-list (function
|
|
644 (lambda (e1 e2)
|
|
645 (string-lessp (car e1) (car e2))))))
|
|
646
|
|
647
|
|
648 (defun recent-files-enforce-max-length (n l)
|
|
649 "Return a list of all permanent and the first N non-permanent entries of L.
|
|
650 Preserve the order of the entries."
|
|
651 (let ((count 0)
|
|
652 (newlist nil))
|
|
653 (while l
|
|
654 (if (cdr (car l))
|
|
655 (setq newlist (cons (car l) newlist))
|
|
656 (if (< count n)
|
|
657 (setq newlist (cons (car l) newlist)))
|
|
658 (setq count (1+ count)))
|
|
659 (setq l (cdr l)))
|
|
660 (nreverse newlist)))
|
|
661
|
|
662
|
|
663 (defun recent-files-remove-entry (fname recent-list)
|
|
664 "Delete all elements that have FNAME as a car from RECENT-LIST.
|
|
665 The constructed list returned, RECENT-LIST is not changed.
|
|
666 Comparison is done with equal."
|
|
667 (let ((newlist nil))
|
|
668 (while recent-list
|
|
669 (if (not (equal (car (car recent-list)) fname))
|
|
670 (setq newlist (cons (car recent-list) newlist)))
|
|
671 (setq recent-list (cdr recent-list)))
|
|
672 (nreverse newlist)))
|
|
673
|
|
674 (defun recent-files-no-match (string re-list)
|
|
675 "Return t if STRING matches none of the regexps in RE-LIST."
|
|
676 (while (and re-list
|
|
677 (not (string-match (car re-list) string)))
|
|
678 (setq re-list (cdr re-list)))
|
|
679 (null re-list))
|
|
680
|
|
681
|
|
682 ;;; Menu commands
|
|
683
|
|
684 (defun recent-files-make-permanent ()
|
|
685 "Make the file in current buffer a permanent entry in recent-files."
|
|
686 (interactive)
|
|
687 (rplacd (recent-files-retrieve-entry (recent-files-get-file-name)) t)
|
|
688 (setq recent-files-list-changed-p t))
|
|
689
|
|
690
|
|
691 (defun recent-files-make-non-permanent ()
|
|
692 "Make the file in current buffer a non-permanent entry in recent-files."
|
|
693 (interactive)
|
|
694 (rplacd (recent-files-retrieve-entry (recent-files-get-file-name)) nil)
|
|
695 (setq recent-files-list-changed-p t))
|
|
696
|
|
697
|
|
698 (defun recent-files-kill-buffer-delete-entry ()
|
|
699 "Kill the current buffer and delete its entry in the recent-files menu."
|
|
700 (interactive)
|
|
701 (setq recent-files-list
|
|
702 (recent-files-remove-entry (recent-files-get-file-name)
|
|
703 recent-files-list))
|
|
704 (setq recent-files-list-changed-p t)
|
|
705 (kill-buffer (current-buffer)))
|
|
706
|
|
707 (defun recent-files-erase-non-permanent ()
|
|
708 "Erase all non-permanent entries from the recent-files menu."
|
|
709 (interactive)
|
|
710 (setq recent-files-list
|
|
711 (recent-files-filter-permanent recent-files-list))
|
|
712 (setq recent-files-list-changed-p t))
|
|
713
|
|
714 (defun recent-files-toggle-save-list-on-exit ()
|
|
715 "Toggle the value of `recent-files-save-list-on-exit'."
|
|
716 (interactive)
|
|
717 (setq recent-files-save-list-on-exit (not recent-files-save-list-on-exit))
|
|
718 (setq recent-files-list-changed-p t))
|
|
719
|
|
720 ;;; EOF
|