/[emacs]/emacs/lisp/recentf.el
ViewVC logotype

Diff of /emacs/lisp/recentf.el

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.22 by lektu, Fri Jan 31 15:17:55 2003 UTC revision 1.23 by lektu, Sat Apr 26 23:41:59 2003 UTC
# Line 1  Line 1 
1  ;;; recentf.el --- setup a menu of recently opened files  ;;; recentf.el --- setup a menu of recently opened files
2    
3  ;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.  ;; Copyright (C) 1999, 2000, 2001, 2002, 2003
4    ;;   Free Software Foundation, Inc.
5    
6  ;; Author: David Ponce <david@dponce.com>  ;; Author: David Ponce <david@dponce.com>
7  ;; Created: July 19 1999  ;; Created: July 19 1999
8  ;; Keywords: customization  ;; Maintainer: FSF
9    ;; Keywords: files
10    
11    (defconst recentf-version "$Revision$")
12    
13  ;; This file is part of GNU Emacs.  ;; This file is part of GNU Emacs.
14    
15  ;; GNU Emacs is free software; you can redistribute it and/or modify  ;; GNU Emacs is free software; you can redistribute it and/or modify
16  ;; it under the terms of the GNU General Public License as published by  ;; it under the terms of the GNU General Public License as published
17  ;; the Free Software Foundation; either version 2, or (at your option)  ;; by the Free Software Foundation; either version 2, or (at your
18  ;; any later version.  ;; option) any later version.
19    
20  ;; GNU Emacs is distributed in the hope that it will be useful,  ;; GNU Emacs is distributed in the hope that it will be useful,
21  ;; but WITHOUT ANY WARRANTY; without even the implied warranty of  ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
# Line 26  Line 30 
30  ;;; Commentary:  ;;; Commentary:
31    
32  ;; This package maintains a menu for visiting files that were operated  ;; This package maintains a menu for visiting files that were operated
33  ;; on recently. When enabled a new "Open Recent" submenu is displayed  ;; on recently.  When enabled a new "Open Recent" submenu is displayed
34  ;; in the "Files" menu. The recent files list is automatically saved  ;; in the "Files" menu.  The recent files list is automatically saved
35  ;; across Emacs sessions.  You can customize the number of recent  ;; across Emacs sessions.  You can customize the number of recent
36  ;; files displayed, the location of the menu and others options (see  ;; files displayed, the location of the menu and others options (see
37  ;; the source code for details).  To install and use, put the file on  ;; the source code for details).
38  ;; your Emacs-Lisp load path and add the following into your ~/.emacs  
39  ;; startup file:  ;;; History:
40  ;;  ;;
 ;;  (require 'recentf)  
 ;;  (recentf-mode 1)  
41    
42  ;;; Code:  ;;; Code:
   
43  (require 'easymenu)  (require 'easymenu)
44  (require 'wid-edit)  (require 'wid-edit)
45    (require 'timer)
46    
47  (defconst recentf-save-file-header  ;;; Internal data
48    ";;; Automatically generated by `recentf' on %s.\n"  ;;
   "Header to be written into the `recentf-save-file'.")  
   
49  (defvar recentf-list nil  (defvar recentf-list nil
50    "List of recently opened files.")    "List of recently opened files.")
51    
52  (defvar recentf-update-menu-p t  (defvar recentf-data-cache nil
53    "Non-nil if the recentf menu must be updated.")    "Cache of data used to build the recentf menu.
54    The menu is rebuilt when this data has changed.")
55  (defvar recentf-initialized-p nil  
56    "Non-nil if recentf already initialized.")  ;;; Customization
57    ;;
 ;; IMPORTANT: This function must be defined before the following defcustoms  
 ;; because it is used in their :set clause. To avoid byte-compiler warnings  
 ;; the `symbol-value' function is used to access the `recentf-menu-path'  
 ;; and `recentf-menu-title' values.  
 (defun recentf-menu-customization-changed (sym val)  
   "Function called when menu customization has changed.  
 It removes the recentf menu and forces its complete redrawing."  
   (when recentf-initialized-p  
     (easy-menu-remove-item nil  
                            (symbol-value 'recentf-menu-path)  
                            (symbol-value 'recentf-menu-title))  
     (setq recentf-update-menu-p t))  
   (custom-set-default sym val))  
   
58  (defgroup recentf nil  (defgroup recentf nil
59    "Maintain a menu of recently opened files."    "Maintain a menu of recently opened files."
60    :version "21.1"    :version "21.1"
# Line 80  You should define the options of your ow Line 66  You should define the options of your ow
66    :group 'recentf)    :group 'recentf)
67    
68  (defcustom recentf-max-saved-items 20  (defcustom recentf-max-saved-items 20
69    "*Maximum number of items saved to `recentf-save-file'."    "*Maximum number of items of the recent list that will be saved.
70    nil means to save the whole list.
71    See the command `recentf-save-list'."
72    :group 'recentf    :group 'recentf
73    :type 'integer)    :type 'integer)
74    
75  (defcustom recentf-save-file (expand-file-name "~/.recentf")  (defcustom recentf-save-file "~/.recentf"
76    "*File to save `recentf-list' into."    "*File to save the recent list into."
77    :group 'recentf    :group 'recentf
78    :type 'file)    :type 'file)
79    
80  (defcustom recentf-exclude nil  (defcustom recentf-exclude nil
81    "*List of regexps for filenames excluded from `recentf-list'."    "*List of regexps for filenames excluded from the recent list."
82    :group 'recentf    :group 'recentf
83    :type '(repeat regexp))    :type '(repeat regexp))
84    
85    (defun recentf-menu-customization-changed (variable value)
86      "Function called when the recentf menu customization has changed.
87    Set VARIABLE with VALUE, and force a rebuild of the recentf menu."
88      (when (featurep 'recentf)
89        ;; Unavailable until recentf has been loaded.
90        (recentf-clear-data))
91      (set-default variable value))
92    
93  (defcustom recentf-menu-title "Open Recent"  (defcustom recentf-menu-title "Open Recent"
94    "*Name of the recentf menu."    "*Name of the recentf menu."
95    :group 'recentf    :group 'recentf
# Line 118  If nil add it at end of menu (see also ` Line 114  If nil add it at end of menu (see also `
114    
115  (defcustom recentf-menu-action 'recentf-find-file  (defcustom recentf-menu-action 'recentf-find-file
116    "*Function to invoke with a filename item of the recentf menu.    "*Function to invoke with a filename item of the recentf menu.
117  The default action `recentf-find-file' calls `find-file' to edit an  The default is to call `recentf-find-file' to edit the selected file."
 existing file.  If the file does not exist or is not readable, it is  
 not edited and its name is removed from `recentf-list'.  You can use  
 `find-file' instead to open non-existing files and keep them in the  
 list of recently opened files."  
118    :group 'recentf    :group 'recentf
119    :type 'function    :type 'function
120    :set 'recentf-menu-customization-changed)    :set 'recentf-menu-customization-changed)
# Line 137  list of recently opened files." Line 129  list of recently opened files."
129    "*Function used to filter files displayed in the recentf menu.    "*Function used to filter files displayed in the recentf menu.
130  nil means no filter.  The following functions are predefined:  nil means no filter.  The following functions are predefined:
131    
132  - `recentf-sort-ascending' to sort menu items in ascending order.  - `recentf-sort-ascending'
133  - `recentf-sort-descending' to sort menu items in descending order.      Sort menu items in ascending order.
134  - `recentf-sort-basenames-ascending' to sort file names in descending order.  - `recentf-sort-descending'
135  - `recentf-sort-basenames-descending' to sort file names in descending order.      Sort menu items in descending order.
136  - `recentf-sort-directories-ascending' to sort directories in ascending order.  - `recentf-sort-basenames-ascending'
137  - `recentf-sort-directories-descending' to sort directories in descending order.      Sort menu items by filenames sans directory in ascending order.
138  - `recentf-show-basenames' to show file names (no directories) in menu items.  - `recentf-sort-basenames-descending'
139  - `recentf-show-basenames-ascending' to show file names in ascending order.      Sort menu items by filenames sans directory in descending order.
140  - `recentf-show-basenames-descending' to show file names in descending order.  - `recentf-sort-directories-ascending'
141  - `recentf-relative-filter' to show file names relative to `default-directory'.      Sort menu items by directories in ascending order.
142  - `recentf-arrange-by-rule' to show sub-menus following user defined rules.  - `recentf-sort-directories-descending'
143  - `recentf-arrange-by-mode' to show a sub-menu for each major mode.      Sort menu items by directories in descending order.
144  - `recentf-arrange-by-dir' to show a sub-menu for each directory.  - `recentf-show-basenames'
145  - `recentf-filter-changer' to manage a ring of filters.      Show filenames sans directory in menu items.
146    - `recentf-show-basenames-ascending'
147  The filter function is called with one argument, the list of menu elements      Show filenames sans directory in ascending order.
148  used to build the menu and must return a new list of menu elements (see  - `recentf-show-basenames-descending'
149  `recentf-make-menu-element' for menu element form)."      Show filenames sans directory in descending order.
150    - `recentf-relative-filter'
151        Show filenames relative to `default-directory'.
152    - `recentf-arrange-by-rule'
153        Show sub-menus following user defined rules.
154    - `recentf-arrange-by-mode'
155        Show a sub-menu for each major mode.
156    - `recentf-arrange-by-dir'
157        Show a sub-menu for each directory.
158    - `recentf-filter-changer'
159        Manage a ring of filters.
160    
161    The filter function is called with one argument, the list of menu
162    elements used to build the menu and must return a new list of menu
163    elements (see `recentf-make-menu-element' for menu element form)."
164    :group 'recentf    :group 'recentf
165    :type '(radio (const nil)    :type '(radio (const nil)
166                  (function-item recentf-sort-ascending)                  (function-item recentf-sort-ascending)
167                  (function-item recentf-sort-descending)                  (function-item recentf-sort-descending)
168                  (function-item recentf-sort-basenames-ascending)                  (function-item recentf-sort-basenames-ascending)
169                  (function-item recentf-sort-basenames-descending)                  (function-item recentf-sort-basenames-descending)
170                  (function-item recentf-sort-directories-ascending)                  (function-item recentf-sort-directories-ascending)
171                  (function-item recentf-sort-directories-descending)                  (function-item recentf-sort-directories-descending)
172                  (function-item recentf-show-basenames)                  (function-item recentf-show-basenames)
173                  (function-item recentf-show-basenames-ascending)                  (function-item recentf-show-basenames-ascending)
174                  (function-item recentf-show-basenames-descending)                  (function-item recentf-show-basenames-descending)
175                  (function-item recentf-relative-filter)                  (function-item recentf-relative-filter)
176                  (function-item recentf-arrange-by-rule)                  (function-item recentf-arrange-by-rule)
177                  (function-item recentf-arrange-by-mode)                  (function-item recentf-arrange-by-mode)
178                  (function-item recentf-arrange-by-dir)                  (function-item recentf-arrange-by-dir)
179                  (function-item recentf-filter-changer)                  (function-item recentf-filter-changer)
180                  function)                  function)
181    :set 'recentf-menu-customization-changed)    :set 'recentf-menu-customization-changed)
182    
183  (defcustom recentf-menu-append-commands-p t  (defcustom recentf-menu-append-commands-flag t
184    "*If not-nil command items are appended to the menu."    "*non-nil means to append command items to the menu."
185    :group 'recentf    :group 'recentf
186    :type 'boolean    :type 'boolean
187    :set 'recentf-menu-customization-changed)    :set 'recentf-menu-customization-changed)
188    
189  (defcustom recentf-keep-non-readable-files-p nil  (defvaralias 'recentf-menu-append-commands-p
190    "*If nil (default), non-readable files are not kept in `recentf-list'."    'recentf-menu-append-commands-flag)
191    (make-obsolete-variable 'recentf-menu-append-commands-p
192                            'recentf-menu-append-commands-flag
193                            "21.4")
194    
195    (defcustom recentf-keep-non-readable-files-flag nil
196      "*non-nil means to keep non readable files in the recent list."
197    :group 'recentf    :group 'recentf
198    :type 'boolean    :type 'boolean)
199    :require 'recentf  
200    :initialize 'custom-initialize-default  (defvaralias 'recentf-keep-non-readable-files-p
201    :set (lambda (sym val)    'recentf-keep-non-readable-files-flag)
202           (if val  (make-obsolete-variable 'recentf-keep-non-readable-files-p
203               (remove-hook 'kill-buffer-hook 'recentf-remove-file-hook)                          'recentf-keep-non-readable-files-flag
204             (add-hook 'kill-buffer-hook 'recentf-remove-file-hook))                          "21.4")
205           (custom-set-default sym val)))  
206    (defcustom recentf-auto-cleanup 'mode
207      "*Define when to automatically cleanup the recent list.
208    The following values can be set:
209    
210    - `mode'
211        Cleanup when turning the mode on (default).
212    - `never'
213        Never cleanup the list automatically.
214    - A number
215        Cleanup each time Emacs has been idle that number of seconds.
216    - A time string
217        Cleanup at specified time string, for example at \"11:00pm\".
218    
219    Setting this variable directly does not take effect;
220    use \\[customize].
221    
222    See also the command `recentf-cleanup', that can be used to manually
223    cleanup the list."
224      :group 'recentf
225      :type '(radio (const  :tag "When mode enabled"
226                            :value mode)
227                    (const  :tag "Never"
228                            :value never)
229                    (number :tag "When idle that seconds"
230                            :value 300)
231                    (string :tag "At time"
232                            :value "11:00pm"))
233      :set (lambda (variable value)
234             (set-default variable value)
235             (when (featurep 'recentf)
236               ;; Unavailable until recentf has been loaded.
237               (recentf-auto-cleanup))))
238    
239  (defcustom recentf-load-hook nil  (defcustom recentf-load-hook nil
240     "*Normal hook run at end of loading the `recentf' package."     "*Normal hook run at end of loading the `recentf' package."
241    :group 'recentf    :group 'recentf
242    :type 'hook)    :type 'hook)
243    
244  ;;;;  (defcustom recentf-filename-handler nil
245  ;;;; Common functions    "Function to call to process filename handled by recentf.
246  ;;;;  It is passed a filename to give a chance to transform it.
247    If it returns nil, the filename is left unchanged."
248      :group 'recentf
249      :type 'function)
250    
251    ;;; Utilities
252    ;;
253  (defconst recentf-case-fold-search  (defconst recentf-case-fold-search
254    (memq system-type '(vax-vms windows-nt cygwin))    (memq system-type '(vax-vms windows-nt cygwin))
255    "Non-nil if recentf searches and matches should ignore case.")    "Non-nil if recentf searches and matches should ignore case.")
256    
257    (defsubst recentf-string-equal (s1 s2)
258      "Return non-nil if strings S1 and S2 have identical contents.
259    Ignore case if `recentf-case-fold-search' is non-nil."
260      (if recentf-case-fold-search
261          (string-equal (downcase s1) (downcase s2))
262        (string-equal s1 s2)))
263    
264    (defsubst recentf-string-lessp (s1 s2)
265      "Return non-nil if string S1 is less than S2 in lexicographic order.
266    Ignore case if `recentf-case-fold-search' is non-nil."
267      (if recentf-case-fold-search
268          (string-lessp (downcase s1) (downcase s2))
269        (string-lessp s1 s2)))
270    
271    (defun recentf-string-member (elt list)
272      "Return non-nil if ELT is an element of LIST.
273    The value is actually the tail of LIST whose car is ELT.
274    ELT must be a string and LIST a list of strings.
275    Ignore case if `recentf-case-fold-search' is non-nil."
276      (while (and list (not (recentf-string-equal elt (car list))))
277        (setq list (cdr list)))
278      list)
279    
280    (defsubst recentf-trunc-list (l n)
281      "Return from L the list of its first N elements."
282      (let (nl)
283        (while (and l (> n 0))
284          (setq nl (cons (car l) nl)
285                n  (1- n)
286                l  (cdr l)))
287        (nreverse nl)))
288    
289    (defun recentf-dump-variable (variable &optional limit)
290      "Insert a \"(setq VARIABLE value)\" in the current buffer.
291    When the value of VARIABLE is a list, optional argument LIMIT
292    specifies a maximum number of elements to insert.  By default insert
293    the full list."
294      (let ((value (symbol-value variable)))
295        (if (atom value)
296            (insert (format "\n(setq %S %S)\n" variable value))
297          (when (and (integerp limit) (> limit 0))
298            (setq value (recentf-trunc-list value limit)))
299          (insert (format "\n(setq %S\n      '(" variable))
300          (dolist (e value)
301            (insert (format "\n        %S" e)))
302          (insert "\n        ))\n"))))
303    
304    (defvar recentf-auto-cleanup-timer nil
305      "Timer used to automatically cleanup the recent list.
306    See also the option `recentf-auto-cleanup'.")
307    
308    (defun recentf-auto-cleanup ()
309      "Automatic cleanup of the recent list."
310      (when (timerp recentf-auto-cleanup-timer)
311        (cancel-timer recentf-auto-cleanup-timer))
312      (when recentf-mode
313        (setq recentf-auto-cleanup-timer
314              (cond
315               ((eq 'mode recentf-auto-cleanup)
316                (recentf-cleanup)
317                nil)
318               ((numberp recentf-auto-cleanup)
319                (run-with-idle-timer
320                 recentf-auto-cleanup t 'recentf-cleanup))
321               ((stringp recentf-auto-cleanup)
322                (run-at-time
323                 recentf-auto-cleanup nil 'recentf-cleanup))))))
324    
325    ;;; File functions
326    ;;
327    (defsubst recentf-push (filename)
328      "Push FILENAME into the recent list, if it isn't there yet.
329    If it is there yet, move it at the beginning of the list.
330    If `recentf-case-fold-search' is non-nil, ignore case when comparing
331    filenames."
332      (let ((m (recentf-string-member filename recentf-list)))
333        (and m (setq recentf-list (delq (car m) recentf-list)))
334        (push filename recentf-list)))
335    
336    (defsubst recentf-expand-file-name (name)
337      "Convert filename NAME to absolute, and canonicalize it.
338    See also the function `expand-file-name'.
339    If defined, call the function `recentf-filename-handler' to post
340    process the canonical name."
341      (let* ((filename (expand-file-name name)))
342        (or (and recentf-filename-handler
343                 (funcall recentf-filename-handler filename))
344            filename)))
345    
346  (defun recentf-include-p (filename)  (defun recentf-include-p (filename)
347    "Return t if FILENAME match none of the `recentf-exclude' regexps."    "Return t if FILENAME match none of the `recentf-exclude' regexps."
348    (let ((case-fold-search recentf-case-fold-search)    (let ((case-fold-search recentf-case-fold-search)
# Line 212  used to build the menu and must return a Line 351  used to build the menu and must return a
351        (setq rl (cdr rl)))        (setq rl (cdr rl)))
352      (null rl)))      (null rl)))
353    
354  (defun recentf-add-file (filename)  (defsubst recentf-add-file (filename)
355    "Add or move FILENAME at the beginning of `recentf-list'.    "Add or move FILENAME at the beginning of the recent list.
356  Does nothing if FILENAME matches one of the `recentf-exclude' regexps."  Does nothing it if it matches any of the `recentf-exclude' regexps."
357    (let ((filename (expand-file-name filename)))    (setq filename (recentf-expand-file-name filename))
358      (when (recentf-include-p filename)    (when (recentf-include-p filename)
359        (setq recentf-list (cons filename (delete filename recentf-list)))      (recentf-push filename)))
360        (setq recentf-update-menu-p t))))  
361    (defsubst recentf-remove-if-non-readable (filename)
362  (defun recentf-remove-if-non-readable (filename)    "Remove FILENAME from the recent list, if file is not readable.
363    "Remove FILENAME from `recentf-list' if not readable."  Return non-nil if FILENAME has been removed."
364    (unless (file-readable-p filename)    (unless (file-readable-p filename)
365      (setq recentf-list (delete filename recentf-list))      (let ((m (recentf-string-member
366      (setq recentf-update-menu-p t)))                (recentf-expand-file-name filename) recentf-list)))
367          (and m (setq recentf-list (delq (car m) recentf-list))))))
368    
369  (defun recentf-find-file (filename)  (defun recentf-find-file (filename)
370    "Edit file FILENAME using `find-file'.    "Edit file FILENAME using `find-file'.
371  If FILENAME is not readable it is removed from `recentf-list'."  If the file does not exist or is non readable, and
372    (if (file-readable-p filename)  `recentf-keep-non-readable-files-flag' is nil, it is not edited and
373        (find-file filename)  its name is removed from the recent list."
374      (progn    (if (and (not recentf-keep-non-readable-files-flag)
375        (message "File `%s' not found." filename)             (recentf-remove-if-non-readable filename))
376        (setq recentf-list (delete filename recentf-list))        (message "File `%s' not found" filename)
377        (setq recentf-update-menu-p t))))      (find-file filename)))
378    
379  (defun recentf-trunc-list (l n)  (defsubst recentf-directory-compare (f1 f2)
380    "Return a list of the first N elements of L."    "Compare absolute filenames F1 and F2.
381    (let ((lh nil))  First compare directories, then filenames sans directory.
382      (while (and l (> n 0))  Return non-nil if F1 is less than F2."
383        (setq lh (cons (car l) lh))    (let ((d1 (file-name-directory f1))
384        (setq n (1- n))          (d2 (file-name-directory f2)))
385        (setq l (cdr l)))      (if (recentf-string-equal d1 d2)
386      (nreverse lh)))          (recentf-string-lessp (file-name-nondirectory f1)
387                                  (file-name-nondirectory f2))
388          (recentf-string-lessp d1 d2))))
389    
390    ;;; Menu building
391    ;;
392    (defvar recentf-menu-items-for-commands
393      (list ["Cleanup list"
394             recentf-cleanup
395             :help "Remove all non-readable and excluded files from the recent list"
396             :active t]
397            ["Edit list..."
398             recentf-edit-list
399             :help "Edit the files that are kept in the recent list"
400             :active t]
401            ["Save list now"
402             recentf-save-list
403             :help "Save the list of recently opened files now"
404             :active t]
405            ["Options..."
406             (customize-group "recentf")
407             :help "Customize recently opened files menu and options"
408             :active t]
409            )
410      "List of menu items for recentf commands.")
411    
412  (defun recentf-elements (n)  (defvar recentf-menu-filter-commands nil
413    "Return a list of the first N elements of `recentf-list'."    "This variable can be used by menu filters to setup their own command menu.
414    If non-nil it must contain a list of valid menu-items to be appended
415    to the recent file list part of the menu.  Before calling a menu
416    filter function this variable is reset to nil.")
417    
418    (defsubst recentf-elements (n)
419      "Return a list of the first N elements of the recent list."
420    (recentf-trunc-list recentf-list n))    (recentf-trunc-list recentf-list n))
421    
422  (defun recentf-make-menu-element (menu-item menu-value)  (defsubst recentf-make-menu-element (menu-item menu-value)
423    "Create a new menu-element.    "Create a new menu-element.
424    A menu element is a pair (MENU-ITEM . MENU-VALUE), where MENU-ITEM is
425  A menu element is a pair (MENU-ITEM . MENU-VALUE) where:  the menu item string displayed.  MENU-VALUE is the file to be open
426    when the corresponding MENU-ITEM is selected.  Or it is a
427  - - MENU-ITEM  is the menu item string displayed.  pair (SUB-MENU-TITLE . MENU-ELEMENTS) where SUB-MENU-TITLE is a
428  - - MENU-VALUE is the path used to open the file when the  sub-menu title and MENU-ELEMENTS is the list of menu elements in the
429                 corresponding MENU-ITEM is selected.  Or it is  sub-menu."
                a pair (SUB-MENU-TITLE . MENU-ELEMENTS) where  
                SUB-MENU-TITLE is a sub-menu title and  
                MENU-ELEMENTS is the list of menu elements in  
                the sub-menu."  
430    (cons menu-item menu-value))    (cons menu-item menu-value))
431    
432  (defun recentf-menu-element-item (e)  (defsubst recentf-menu-element-item (e)
433    "Return the item part of the menu-element E."    "Return the item part of the menu-element E."
434    (car e))    (car e))
435    
436  (defun recentf-menu-element-value (e)  (defsubst recentf-menu-element-value (e)
437    "Return the value part of the menu-element E."    "Return the value part of the menu-element E."
438    (cdr e))    (cdr e))
439    
440  (defun recentf-set-menu-element-item (e item)  (defsubst recentf-set-menu-element-item (e item)
441    "Change the item part of menu-element E to ITEM."    "Change the item part of menu-element E to ITEM."
442    (setcar e item))    (setcar e item))
443    
444  (defun recentf-set-menu-element-value (e value)  (defsubst recentf-set-menu-element-value (e value)
445    "Change the value part of menu-element E to VALUE."    "Change the value part of menu-element E to VALUE."
446    (setcdr e value))    (setcdr e value))
447    
448  (defun recentf-sub-menu-element-p (e)  (defsubst recentf-sub-menu-element-p (e)
449    "Return non-nil if menu-element E defines a sub-menu."    "Return non-nil if menu-element E defines a sub-menu."
450    (consp (recentf-menu-element-value e)))    (consp (recentf-menu-element-value e)))
451    
452  (defun recentf-make-default-menu-element (file-path)  (defsubst recentf-make-default-menu-element (file)
453    "Make a new default menu element (MENU-ITEM . MENU-VALUE).    "Make a new default menu element with FILE.
454  Do so for the given recent file path FILE-PATH.  MENU-ITEM and  This a menu element (FILE . FILE)."
455  MENU-VALUE are set to FILE-PATH.  See also    (recentf-make-menu-element file file))
 `recentf-make-menu-element'."  
   (recentf-make-menu-element file-path file-path))  
456    
457  (defun recentf-menu-elements (n)  (defsubst recentf-menu-elements (n)
458    "Return a list of the first N default menu elements from `recentf-list'.    "Return a list of the first N default menu elements from the recent list.
459  See also `recentf-make-default-menu-element'."  See also `recentf-make-default-menu-element'."
460    (mapcar 'recentf-make-default-menu-element    (mapcar 'recentf-make-default-menu-element
461            (recentf-elements n)))            (recentf-elements n)))
# Line 301  See also `recentf-make-default-menu-elem Line 465  See also `recentf-make-default-menu-elem
465  It takes care of sub-menu elements in L and recursively apply FILTER  It takes care of sub-menu elements in L and recursively apply FILTER
466  to them.  It is guaranteed that FILTER receives only a list of single  to them.  It is guaranteed that FILTER receives only a list of single
467  menu-elements (no sub-menu)."  menu-elements (no sub-menu)."
468    (if (and (functionp filter) l)    (if (and l (functionp filter))
469        (let ((case-fold-search recentf-case-fold-search)        (let ((case-fold-search recentf-case-fold-search)
470              menu-element sub-menu-elements single-elements)              elts others)
471          ;; split L in two sub-listes:          ;; split L into two sub-listes, one of sub-menus elements and
472          ;;   one of sub-menus elements and          ;; another of single menu elements.
473          ;;   one of single menu elements          (dolist (elt l)
474          (while l            (if (recentf-sub-menu-element-p elt)
475            (setq menu-element (car l))                (push elt elts)
476            (if (recentf-sub-menu-element-p menu-element)              (push elt others)))
477                (setq sub-menu-elements          ;; Apply FILTER to single elements.
478                      (cons menu-element sub-menu-elements))          (when others
479              (setq single-elements            (setq others (funcall filter (nreverse others))))
480                    (cons menu-element single-elements)))          ;; Apply FILTER to sub-menu elements.
481            (setq l (cdr l)))          (setq l nil)
482          ;; apply FILTER to the list of single menu elements          (dolist (elt elts)
         (if single-elements  
             (setq single-elements (funcall filter  
                                            (nreverse single-elements))))  
         ;; apply FILTER to sub-menu menu element list  
         (setq l sub-menu-elements)  
         (setq sub-menu-elements nil)  
         (while l  
           (setq menu-element (car l))  
483            (recentf-set-menu-element-value            (recentf-set-menu-element-value
484             menu-element             elt (recentf-apply-menu-filter
485             (recentf-apply-menu-filter                  filter (recentf-menu-element-value elt)))
486              filter            (push elt l))
487              (recentf-menu-element-value menu-element)))          ;; Return the new filtered menu element list.
488            (setq sub-menu-elements (cons menu-element sub-menu-elements))          (nconc l others))
           (setq l (cdr l)))  
         ;; build and return the new filtered menu element list  
         (nconc sub-menu-elements single-elements))  
489      l))      l))
490    
 (defvar recentf-menu-items-for-commands  
   (list ["Cleanup list"  
          recentf-cleanup  
          :help "Remove all non-readable and excluded files from the recent list"  
          :active t]  
         ["Edit list..."  
          recentf-edit-list  
          :help "Edit the files that are kept in the recent list"  
          :active t]  
         ["Save list now"  
          recentf-save-list  
          :help "Save the list of recently opened files now"  
          :active t]  
         ["Options..."  
          (customize-group "recentf")  
          :help "Customize recently opened files menu and options"  
          :active t]  
         )  
   "List of menu items for recentf commands.")  
   
 (defvar recentf-menu-filter-commands nil  
   "This variable can be used by menu filters to setup their own command menu.  
   
 If non-nil it must contain a list of valid menu-items to be appended  
 to the recent file list part of the menu.  Before calling a menu  
 filter function this variable is reset to nil.")  
   
491  (defun recentf-make-menu-items ()  (defun recentf-make-menu-items ()
492    "Make menu items from `recentf-list'."    "Make menu items from the recent list."
493    (setq recentf-menu-filter-commands nil)    (setq recentf-menu-filter-commands nil)
494    (let ((file-items    (let ((file-items
495           (mapcar 'recentf-make-menu-item           (mapcar 'recentf-make-menu-item
# Line 380  filter function this variable is reset t Line 506  filter function this variable is reset t
506              (and recentf-menu-filter-commands              (and recentf-menu-filter-commands
507                   (cons "---"                   (cons "---"
508                         recentf-menu-filter-commands))                         recentf-menu-filter-commands))
509              (and recentf-menu-append-commands-p              (and recentf-menu-append-commands-flag
510                   (cons "---"                   (cons "---"
511                         recentf-menu-items-for-commands)))))                         recentf-menu-items-for-commands)))))
512    
513  (defun recentf-make-menu-item (menu-element)  (defsubst recentf-make-menu-item (elt)
514    "Make a menu item from MENU-ELEMENT (see `recentf-make-menu-element')."    "Make a menu item from menu element ELT."
515    (let ((menu-item  (recentf-menu-element-item  menu-element))    (let ((item  (recentf-menu-element-item  elt))
516          (menu-value (recentf-menu-element-value menu-element)))          (value (recentf-menu-element-value elt)))
517      (if (recentf-sub-menu-element-p menu-element)      (if (recentf-sub-menu-element-p elt)
518          (cons menu-item (mapcar 'recentf-make-menu-item menu-value))          (cons item (mapcar 'recentf-make-menu-item value))
519        (vector menu-item        (vector item (list recentf-menu-action value)
520                (list recentf-menu-action menu-value)                :help (concat "Open " value)
               :help (concat "Open " menu-value)  
521                :active t))))                :active t))))
522    
523  ;;;;  (defun recentf-clear-data ()
524  ;;;; Predefined menu filter functions    "Clear data used to build the recentf menu.
525  ;;;;  This force a rebuild of the menu."
526      (easy-menu-remove-item nil recentf-menu-path recentf-menu-title)
527  (defun recentf-sort-ascending (l)    (setq recentf-data-cache nil))
528    
529    ;;; Predefined menu filters
530    ;;
531    (defsubst recentf-sort-ascending (l)
532    "Sort the list of menu elements L in ascending order.    "Sort the list of menu elements L in ascending order.
533  The MENU-ITEM part of each menu element is compared."  The MENU-ITEM part of each menu element is compared."
534    (sort (copy-sequence l)    (sort (copy-sequence l)
535          (function          #'(lambda (e1 e2)
536           (lambda (e1 e2)              (recentf-string-lessp
537             (string-lessp (recentf-menu-element-item e1)               (recentf-menu-element-item e1)
538                           (recentf-menu-element-item e2))))))               (recentf-menu-element-item e2)))))
539    
540  (defun recentf-sort-descending (l)  (defsubst recentf-sort-descending (l)
541    "Sort the list of menu elements L in descending order.    "Sort the list of menu elements L in descending order.
542  The MENU-ITEM part of each menu element is compared."  The MENU-ITEM part of each menu element is compared."
543    (sort (copy-sequence l)    (sort (copy-sequence l)
544          (function          #'(lambda (e1 e2)
545           (lambda (e1 e2)              (recentf-string-lessp
546             (string-lessp (recentf-menu-element-item e2)               (recentf-menu-element-item e2)
547                           (recentf-menu-element-item e1))))))               (recentf-menu-element-item e1)))))
548    
549  (defun recentf-sort-basenames-ascending (l)  (defsubst recentf-sort-basenames-ascending (l)
550    "Sort the list of menu elements L in ascending order.    "Sort the list of menu elements L in ascending order.
551  Only file names (without directories) are compared."  Only filenames sans directory are compared."
552    (sort (copy-sequence l)    (sort (copy-sequence l)
553          (function          #'(lambda (e1 e2)
554           (lambda (e1 e2)              (recentf-string-lessp
555             (string-lessp               (file-name-nondirectory (recentf-menu-element-value e1))
556              (file-name-nondirectory (recentf-menu-element-value e1))               (file-name-nondirectory (recentf-menu-element-value e2))))))
             (file-name-nondirectory (recentf-menu-element-value e2)))))))  
557    
558  (defun recentf-sort-basenames-descending (l)  (defsubst recentf-sort-basenames-descending (l)
559    "Sort the list of menu elements L in descending order.    "Sort the list of menu elements L in descending order.
560  Only file names (without directories) are compared."  Only filenames sans directory are compared."
561    (sort (copy-sequence l)    (sort (copy-sequence l)
562          (function          #'(lambda (e1 e2)
563           (lambda (e1 e2)              (recentf-string-lessp
564             (string-lessp               (file-name-nondirectory (recentf-menu-element-value e2))
565              (file-name-nondirectory (recentf-menu-element-value e2))               (file-name-nondirectory (recentf-menu-element-value e1))))))
             (file-name-nondirectory (recentf-menu-element-value e1)))))))  
   
 (defun recentf-directory-compare (p1 p2)  
   "Compare directories then filenames in paths P1 and P2.  
 Return non-nil if P1 is less than P2."  
   (let ((d1 (file-name-directory    p1))  
         (f1 (file-name-nondirectory p1))  
         (d2 (file-name-directory    p2))  
         (f2 (file-name-nondirectory p2)))  
     (if (string= d1 d2)  
         (string-lessp f1 f2)  
       (string-lessp d1 d2))))  
566    
567  (defun recentf-sort-directories-ascending (l)  (defsubst recentf-sort-directories-ascending (l)
568    "Sort the list of menu elements L in ascending order.    "Sort the list of menu elements L in ascending order.
569  Compares directories then filenames to order the list."  Compares directories then filenames to order the list."
570    (sort (copy-sequence l)    (sort (copy-sequence l)
571          (function          #'(lambda (e1 e2)
572           (lambda (e1 e2)              (recentf-directory-compare
573             (recentf-directory-compare (recentf-menu-element-value e1)               (recentf-menu-element-value e1)
574                                        (recentf-menu-element-value e2))))))               (recentf-menu-element-value e2)))))
575    
576  (defun recentf-sort-directories-descending (l)  (defsubst recentf-sort-directories-descending (l)
577    "Sort the list of menu elements L in descending order.    "Sort the list of menu elements L in descending order.
578  Compares directories then filenames to order the list."  Compares directories then filenames to order the list."
579    (sort (copy-sequence l)    (sort (copy-sequence l)
580          (function          #'(lambda (e1 e2)
581           (lambda (e1 e2)              (recentf-directory-compare
582             (recentf-directory-compare (recentf-menu-element-value e2)               (recentf-menu-element-value e2)
583                                        (recentf-menu-element-value e1))))))               (recentf-menu-element-value e1)))))
584    
585  (defun recentf-show-basenames (l)  (defun recentf-show-basenames (l &optional no-dir)
586    "Filter the list of menu elements L to show only file names (no directories)    "Filter the list of menu elements L to show filenames sans directory.
587  in the menu.  When file names are duplicated their directory component is added."  When a filename is duplicated, it is appended a sequence number if
588    (let ((names  (mapcar (function  optional argument NO-DIR is non-nil, or its directory otherwise."
589                           (lambda (item)    (let (filtered-names filtered-list full name counters sufx)
590                             (file-name-nondirectory      (dolist (elt l (nreverse filtered-list))
591                              (recentf-menu-element-value item))))        (setq full (recentf-menu-element-value elt)
592                          l))              name (file-name-nondirectory full))
593          (dirs   (mapcar (function        (if (not (member name filtered-names))
594                           (lambda (item)            (push name filtered-names)
595                             (file-name-directory          (if no-dir
596                              (recentf-menu-element-value item))))              (if (setq sufx (assoc name counters))
597                          l))                  (setcdr sufx (1+ (cdr sufx)))
598          (pathes (mapcar 'recentf-menu-element-value l))                (setq sufx 1)
599          (pos    -1)                (push (cons name sufx) counters))
600          item filtered-items filtered-list)            (setq sufx (file-name-directory full)))
601      (while names          (setq name (format "%s(%s)" name sufx)))
602        (setq item  (car names))        (push (recentf-make-menu-element name full) filtered-list))))
603        (setq names (cdr names))  
604        (setq pos   (1+ pos))  (defsubst recentf-show-basenames-ascending (l)
605        (setq filtered-list    "Filter the list of menu elements L to show filenames sans directory.
606              (cons (recentf-make-menu-element  Filenames are sorted in ascending order.
607                     (if (or (member item names) (member item filtered-items))  This filter combines the `recentf-sort-basenames-ascending' and
                        (concat item " (" (nth pos dirs) ")")  
                      item)  
                    (nth pos pathes))  
                   filtered-list))  
       (setq filtered-items (cons item filtered-items)))  
     (nreverse filtered-list)))  
   
 (defun recentf-show-basenames-ascending (l)  
   "Filter the list of menu elements L.  
 Show only file names in the menu, sorted in ascending order.  This  
 filter combines the `recentf-sort-basenames-ascending' and  
608  `recentf-show-basenames' filters."  `recentf-show-basenames' filters."
609    (recentf-show-basenames (recentf-sort-basenames-ascending l)))    (recentf-show-basenames (recentf-sort-basenames-ascending l)))
610    
611  (defun recentf-show-basenames-descending (l)  (defsubst recentf-show-basenames-descending (l)
612    "Filter the list of menu elements L.    "Filter the list of menu elements L to show filenames sans directory.
613  Show only file names in the menu, sorted in descending order.  This  Filenames are sorted in descending order.
614  filter combines the `recentf-sort-basenames-descending' and  This filter combines the `recentf-sort-basenames-descending' and
615  `recentf-show-basenames' filters."  `recentf-show-basenames' filters."
616    (recentf-show-basenames (recentf-sort-basenames-descending l)))    (recentf-show-basenames (recentf-sort-basenames-descending l)))
617    
618  (defun recentf-relative-filter (l)  (defun recentf-relative-filter (l)
619    "Filter the list of `recentf-menu-elements' L.    "Filter the list of menu-elements L to show relative filenames.
620  Show filenames relative to `default-directory'."  Filenames are relative to the `default-directory'."
621    (setq recentf-update-menu-p t)        ; force menu update    (mapcar #'(lambda (menu-element)
622    (mapcar (function                (let* ((ful (recentf-menu-element-value menu-element))
623             (lambda (menu-element)                       (rel (file-relative-name ful default-directory)))
624               (let* ((ful-path (recentf-menu-element-value menu-element))                  (if (string-match "^\\.\\." rel)
625                      (rel-path (file-relative-name ful-path)))                      menu-element
626                 (if (string-match "^\\.\\." rel-path)                    (recentf-make-menu-element rel ful))))
                    menu-element  
                  (recentf-make-menu-element rel-path ful-path)))))  
627            l))            l))
628    
629    ;;; Rule based menu filters
630    ;;
631  (defcustom recentf-arrange-rules  (defcustom recentf-arrange-rules
632    '(    '(
633      ("Elisp files (%d)" ".\\.el$")      ("Elisp files (%d)" ".\\.el$")
# Line 561  defined." Line 666  defined."
666    :set 'recentf-menu-customization-changed)    :set 'recentf-menu-customization-changed)
667    
668  (defcustom recentf-arrange-by-rule-subfilter nil  (defcustom recentf-arrange-by-rule-subfilter nil
669    "*Function used by `recentf-arrange-by-rule' to filter sub-menu elements.    "*Function called by a rule based filter to filter sub-menu elements.
670  nil means no filter.  See also `recentf-menu-filter'.  You can't use  nil means no filter.  See also `recentf-menu-filter'.
671  `recentf-arrange-by-rule' itself here!"  You can't use another rule based filter here."
672    :group 'recentf-filters    :group 'recentf-filters
673    :type '(choice (const nil) function)    :type '(choice (const nil) function)
674    :set (lambda (sym val)    :set (lambda (variable value)
675           (if (eq val 'recentf-arrange-by-rule)           (when (memq value '(recentf-arrange-by-rule
676               (error "Can't use `recentf-arrange-by-rule' itself here!")                               recentf-arrange-by-mode
677             (recentf-menu-customization-changed sym val))))                               recentf-arrange-by-dir))
678               (error "Recursive use of a rule based filter"))
679             (recentf-menu-customization-changed variable value)))
680    
681  (defun recentf-match-rule-p (matcher file-path)  (defun recentf-match-rule-p (matcher filename)
682    "Return non-nil if FILE-PATH match the rule specified by MATCHER.    "Return non-nil if the rule specified by MATCHER match FILENAME.
683  See `recentf-arrange-rules' for details on MATCHER."  See `recentf-arrange-rules' for details on MATCHER."
684    (if (stringp matcher)    (if (stringp matcher)
685        (string-match matcher file-path)        (string-match matcher filename)
686      (while (and (consp matcher)      (while (and (consp matcher)
687                  (not (string-match (car matcher) file-path)))                  (not (string-match (car matcher) filename)))
688        (setq matcher (cdr matcher)))        (setq matcher (cdr matcher)))
689      matcher))      matcher))
690    
691  (defun recentf-arrange-by-rule (l)  (defun recentf-arrange-by-rule (l)
692    "Filter the list of menu-elements L.    "Filter the list of menu-elements L.
693  Arrange them in sub-menus following rules in `recentf-arrange-rules'."  Arrange them in sub-menus following rules in `recentf-arrange-rules'."
694    (let ((sub-menus-number (length recentf-arrange-rules)))    (if (not recentf-arrange-rules)
695      (if (> sub-menus-number 0)        l
696          (let ((sub-menus (apply 'vector      (let ((menus (mapcar #'(lambda (r) (list (car r)))
697                                  (mapcar (function                           recentf-arrange-rules))
698                                           (lambda (pair)            menu others min file rules elts count)
699                                             (list (car pair))))        (dolist (elt l)
700                                          recentf-arrange-rules)))          (setq file  (recentf-menu-element-value elt)
701                other-menu-elements index min-size)                rules recentf-arrange-rules
702            (while l                elts  menus
703              (let* ((menu-element (car l))                menu  nil)
704                     (file-path    (recentf-menu-element-value menu-element))          (while (and (not menu) rules)
705                     (rules        recentf-arrange-rules)            (when (recentf-match-rule-p (cdar rules) file)
706                     (found        nil))              (setq menu (car elts))
707                (setq index 0)              (recentf-set-menu-element-value
708                (while (and (not found) rules)               menu (cons elt (recentf-menu-element-value menu))))
709                  (if (recentf-match-rule-p (cdar rules) file-path)            (setq rules (cdr rules)
710                      (let ((sub-menu (aref sub-menus index)))                  elts  (cdr elts)))
711                        (setq found t)          (unless menu
712                        (recentf-set-menu-element-value            (push elt others)))
713                         sub-menu        
714                         (cons menu-element (recentf-menu-element-value sub-menu)))        (setq l nil
715                        ))              min (if (natnump recentf-arrange-by-rules-min-items)
716                  (setq index (1+  index))                      recentf-arrange-by-rules-min-items 0))
717                  (setq rules (cdr rules)))        (dolist (menu menus)
718                (or found          (when (setq elts (recentf-menu-element-value menu))
719                    (setq other-menu-elements            (setq count (length elts))
720                          (cons menu-element other-menu-elements)))            (if (< count min)
721                (setq l (cdr l))))                (setq others (nconc elts others))
722            (setq index    0)              (recentf-set-menu-element-item
723            (setq l        nil)               menu (format (recentf-menu-element-item menu) count))
724            (setq min-size (if (integerp recentf-arrange-by-rules-min-items)              (recentf-set-menu-element-value
725                               (max 0 recentf-arrange-by-rules-min-items)               menu (recentf-apply-menu-filter
726                             0))                     recentf-arrange-by-rule-subfilter (nreverse elts)))
727            (while (< index sub-menus-number)              (push menu l))))
728              (let* ((sub-menu          (aref sub-menus index))        
729                     (sub-menu-title    (recentf-menu-element-item  sub-menu))        (if (and (stringp recentf-arrange-by-rule-others) others)
730                     (sub-menu-elements (recentf-menu-element-value sub-menu))            (nreverse
731                     (sub-menu-length   (length sub-menu-elements)))             (cons
732                (if (> sub-menu-length 0)              (recentf-make-menu-element
733                    (cond               (format recentf-arrange-by-rule-others (length others))
734                     ((< sub-menu-length min-size)               (recentf-apply-menu-filter
735                      (setq other-menu-elements                recentf-arrange-by-rule-subfilter (nreverse others)))
736                            (nconc sub-menu-elements other-menu-elements)))              l))
737                     ((>= sub-menu-length min-size)          (nconc
738                      (recentf-set-menu-element-item           (nreverse l)
739                       sub-menu           (recentf-apply-menu-filter
740                       (format sub-menu-title sub-menu-length))            recentf-arrange-by-rule-subfilter (nreverse others)))))
741                      (recentf-set-menu-element-value      ))
742                       sub-menu  
743                       (recentf-apply-menu-filter  ;;; Predefined rule based menu filters
744                        recentf-arrange-by-rule-subfilter  ;;
                       (nreverse sub-menu-elements)))  
                     (setq   l (cons sub-menu l)))))  
               (setq index (1+ index))))  
           (if (and (stringp recentf-arrange-by-rule-others)  
                    other-menu-elements)  
               (setq l  
                     (nreverse  
                      (cons (recentf-make-menu-element  
                             (format recentf-arrange-by-rule-others  
                                     (length other-menu-elements))  
                             (recentf-apply-menu-filter  
                              recentf-arrange-by-rule-subfilter  
                              (nreverse other-menu-elements)))  
                            l)))  
             (setq l (nconc (nreverse l)  
                            (recentf-apply-menu-filter  
                             recentf-arrange-by-rule-subfilter  
                             (nreverse other-menu-elements)))))))  
     l))  
   
745  (defun recentf-build-mode-rules ()  (defun recentf-build-mode-rules ()
746    "Convert `auto-mode-alist' to `recentf-arrange-rules' format."    "Convert `auto-mode-alist' to menu filter rules.
747    Rules obey `recentf-arrange-rules' format."
748    (let ((case-fold-search recentf-case-fold-search)    (let ((case-fold-search recentf-case-fold-search)
749          (modes auto-mode-alist)          regexp rule-name rule rules)
750          regexp mode rule-name rule rules)      (dolist (mode auto-mode-alist)
751      (while modes        (setq regexp (car mode)
752        (setq regexp (caar modes))              mode   (cdr mode))
       (setq mode   (cdar modes))  
753        (when (symbolp mode)        (when (symbolp mode)
754          (setq rule-name (symbol-name mode))          (setq rule-name (symbol-name mode))
755          (if (string-match "\\(.*\\)-mode$" rule-name)          (if (string-match "\\(.*\\)-mode$" rule-name)
756              (setq rule-name (match-string 1 rule-name)))              (setq rule-name (match-string 1 rule-name)))
757          (setq rule-name (concat rule-name " (%d)"))          (setq rule-name (concat rule-name " (%d)")
758          (setq rule (assoc rule-name rules))                rule (assoc rule-name rules))
759          (if rule          (if rule
760              (setcdr rule (cons regexp (cdr rule)))              (setcdr rule (cons regexp (cdr rule)))
761            (setq rules (cons (list rule-name regexp) rules))))            (push (list rule-name regexp) rules))))
       (setq modes (cdr modes)))  
762      ;; It is important to preserve auto-mode-alist order      ;; It is important to preserve auto-mode-alist order
763      ;; to ensure the right file <-> mode association      ;; to ensure the right file <-> mode association
764      (nreverse rules)))      (nreverse rules)))
765    
766  (defun recentf-arrange-by-mode (l)  (defun recentf-arrange-by-mode (l)
767    "Filter the list of menu-elements L to build sub-menus for each major mode."    "Split the list of menu-elements L into sub-menus by major mode."
768    (let ((recentf-arrange-rules (recentf-build-mode-rules))    (let ((recentf-arrange-rules (recentf-build-mode-rules))
769          (recentf-arrange-by-rule-others "others (%d)"))          (recentf-arrange-by-rule-others "others (%d)"))
770      (recentf-arrange-by-rule l)))      (recentf-arrange-by-rule l)))
771    
772  (defun recentf-build-dir-rules (l)  (defun recentf-build-dir-rules (l)
773    "Convert directories in menu-elements L to rules in `recentf-arrange-rules' format."    "Convert directories in menu-elements L to menu filter rules.
774    Rules obey `recentf-arrange-rules' format."
775    (let (dirs)    (let (dirs)
776      (mapc (function      (mapcar #'(lambda (e)
777             (lambda (e)                  (let ((dir (file-name-directory
778               (let ((dir (file-name-directory                              (recentf-menu-element-value e))))
779                           (recentf-menu-element-value e))))                    (or (recentf-string-member dir dirs)
780                 (or (member dir dirs)                        (push dir dirs))))
781                     (setq dirs (cons dir dirs))))))              l)
782            l)      (mapcar #'(lambda (d)
783      (mapcar (function                  (cons (concat d " (%d)")
784               (lambda (d)                        (concat "\\`" d)))
785                 (cons (concat d " (%d)")              (nreverse (sort dirs 'recentf-string-lessp)))))
                      (concat "\\`" d))))  
             (nreverse (sort dirs 'string-lessp)))))  
786    
787  (defun recentf-file-name-nondir (l)  (defun recentf-file-name-nondir (l)
788    "Filter the list of menu-elements L to show only filenames.    "Filter the list of menu-elements L to show filenames sans directory.
789  This simplified version of `recentf-show-basenames' does not handle  This simplified version of `recentf-show-basenames' does not handle
790  duplicates.  It is used by `recentf-arrange-by-dir' as its  duplicates.  It is used by `recentf-arrange-by-dir' as its
791  `recentf-arrange-by-rule-subfilter'."  `recentf-arrange-by-rule-subfilter'."
792    (mapcar (function    (mapcar #'(lambda (e)
793             (lambda (e)                (recentf-make-menu-element
794               (recentf-make-menu-element                 (file-name-nondirectory (recentf-menu-element-value e))
795                (file-name-nondirectory (recentf-menu-element-value e))                 (recentf-menu-element-value e)))
               (recentf-menu-element-value e))))  
796            l))            l))
797    
798  (defun recentf-arrange-by-dir (l)  (defun recentf-arrange-by-dir (l)
799    "Filter the list of menu-elements L to build sub-menus for each directory."    "Split the list of menu-elements L into sub-menus by directory."
800    (let ((recentf-arrange-rules (recentf-build-dir-rules l))    (let ((recentf-arrange-rules (recentf-build-dir-rules l))
801          (recentf-arrange-by-rule-subfilter 'recentf-file-name-nondir)          (recentf-arrange-by-rule-subfilter 'recentf-file-name-nondir)
802          recentf-arrange-by-rule-others)          recentf-arrange-by-rule-others)
803      (nreverse (recentf-arrange-by-rule l))))      (nreverse (recentf-arrange-by-rule l))))
804    
805    ;;; Ring of menu filters
806    ;;
807  (defvar recentf-filter-changer-state nil  (defvar recentf-filter-changer-state nil
808    "Used by `recentf-filter-changer' to hold its state.")    "Used by `recentf-filter-changer' to hold its state.")
809    
# Line 728  duplicates.  It is used by `recentf-arra Line 814  duplicates.  It is used by `recentf-arra
814      (recentf-arrange-by-rule . "*Files by User Rule*")      (recentf-arrange-by-rule . "*Files by User Rule*")
815      )      )
816    "*List of filters managed by `recentf-filter-changer'.    "*List of filters managed by `recentf-filter-changer'.
817  Each filter is defined by a pair (FILTER-FUN . FILTER-LBL) where:  Each filter is defined by a pair (FUNCTION . LABEL), where FUNCTION is
818    the filter function, and LABEL is the menu item displayed to select
819  - - FILTER-FUN is the function that filters menu-elements  that filter."
 - - FILTER-LBL is the menu item used to activate the filter"  
820    :group 'recentf-filters    :group 'recentf-filters
821    :type '(repeat (cons function string))    :type '(repeat (cons function string))
822    :set (lambda (sym val)    :set (lambda (variable value)
823           (setq recentf-filter-changer-state nil)           (setq recentf-filter-changer-state nil)
824           (recentf-menu-customization-changed sym val)))           (recentf-menu-customization-changed variable value)))
825    
826  (defun recentf-filter-changer-goto-next ()  (defun recentf-filter-changer-goto-next ()
827    "Go to the next filter available (see `recentf-filter-changer')."    "Go to the next filter available.
828    (and (consp recentf-filter-changer-state)  See `recentf-filter-changer'."
829         (setq recentf-filter-changer-state    (setq recentf-filter-changer-state (cdr recentf-filter-changer-state))
830               (cdr recentf-filter-changer-state)))    (recentf-clear-data))
831    (setq recentf-update-menu-p t))  
832    (defsubst recentf-filter-changer-get-current ()
833  (defun recentf-filter-changer-get-current ()    "Get the current filter available.
834    "Get the current filter available (see `recentf-filter-changer')."  See `recentf-filter-changer'."
835    (if (null recentf-filter-changer-state)    (unless recentf-filter-changer-state
836        (setq recentf-filter-changer-state recentf-filter-changer-alist))      (setq recentf-filter-changer-state recentf-filter-changer-alist))
837    (and (consp recentf-filter-changer-state)    (car recentf-filter-changer-state))
838         (car recentf-filter-changer-state)))  
839    (defsubst recentf-filter-changer-get-next ()
840  (defun recentf-filter-changer-get-next ()    "Get the next filter available.
841    "Get the next filter available (see `recentf-filter-changer')."  See `recentf-filter-changer'."
842    (let ((filters recentf-filter-changer-state))    ;; At this point the current filter is the first element of
843      (cond ((consp filters)    ;; `recentf-filter-changer-state'.
844             (setq filters (cdr filters))    (car (or (cdr recentf-filter-changer-state)
845             (if (null filters)             ;; There is no next element in
846                 (setq filters recentf-filter-changer-alist)))             ;; `recentf-filter-changer-state', so loop back to the
847            (t             ;; first element of `recentf-filter-changer-alist'.
848             (setq filters recentf-filter-changer-alist)             recentf-filter-changer-alist)))
            (if (consp filters)  
                (setq filters (cdr filters)))))  
     (if (consp filters)  
         (car filters))))  
849    
850  (defun recentf-filter-changer (l)  (defun recentf-filter-changer (l)
851    "Manage a ring of filters.    "Manage a ring of menu filters.
852  `recentf-filter-changer-alist' defines the filters in the ring.  `recentf-filter-changer-alist' defines the filters in the ring.
853  Actual filtering of L is delegated to the current filter in the  Filtering of L is delegated to the current filter in the ring.  A
854  ring.  A filter menu item is displayed allowing to dynamically activate  filter menu item is displayed allowing to dynamically activate the
855  the next filter in the ring.  If the filter ring is empty L is left  next filter in the ring.  If the filter ring is empty, L is left
856  unchanged."  unchanged."
857    (let ((current-filter-item (recentf-filter-changer-get-current))    (let ((filter (recentf-filter-changer-get-current)))
858          (next-filter-item    (recentf-filter-changer-get-next)))      (when filter
859      (when current-filter-item        (setq l (recentf-apply-menu-filter (car filter) l)
860        (setq l (recentf-apply-menu-filter (car current-filter-item) l))              filter (recentf-filter-changer-get-next))
861        (if next-filter-item        (when filter
862            (setq recentf-menu-filter-commands          (setq recentf-menu-filter-commands
863                  (list (vector (cdr next-filter-item)                (list (vector (cdr filter)
864                                '(recentf-filter-changer-goto-next)                              '(recentf-filter-changer-goto-next)
865                                :active t)))))                              t)))))
866      l))      l))
867    
868  ;;;;  ;;; Common dialog stuff
869  ;;;; Dialogs stuff  ;;
 ;;;;  
   
870  (defun recentf-cancel-dialog (&rest ignore)  (defun recentf-cancel-dialog (&rest ignore)
871    "Cancel the current dialog.    "Cancel the current dialog.
872  Used by `recentf-edit-list' and `recentf-open-files' dialogs."  Used internally by recentf dialogs.
873    IGNORE arguments."
874    (interactive)    (interactive)
875    (kill-buffer (current-buffer))    (kill-buffer (current-buffer))
876    (message "Dialog canceled"))    (message "Dialog canceled"))
877    
878  (defvar recentf-dialog-mode-map nil  (defvar recentf-dialog-mode-map
879    "`recentf-dialog-mode' keymap.")    (let ((km (make-sparse-keymap)))
880        (define-key km "q" 'recentf-cancel-dialog)
881  (if recentf-dialog-mode-map      (define-key km [down-mouse-1] 'widget-button-click)
882      ()      (set-keymap-parent km widget-keymap)
883    (setq recentf-dialog-mode-map (make-sparse-keymap))      km)
884    (define-key recentf-dialog-mode-map "q" 'recentf-cancel-dialog)    "Keymap used in recentf dialogs.")
   (define-key recentf-dialog-mode-map [down-mouse-1] 'widget-button-click)  
   (set-keymap-parent recentf-dialog-mode-map widget-keymap))  
885    
886  (defun recentf-dialog-mode ()  (defun recentf-dialog-mode ()
887    "Major mode used in recentf dialogs.    "Major mode of recentf dialogs.
888    
889  These are the special commands of `recentf-dialog-mode' mode:  \\{recentf-dialog-mode-map}"
     q -- cancel this dialog."  
890    (interactive)    (interactive)
891    (setq major-mode 'recentf-dialog-mode)    (setq major-mode 'recentf-dialog-mode)
892    (setq mode-name "recentf-dialog")    (setq mode-name "recentf-dialog")
893    (use-local-map recentf-dialog-mode-map))    (use-local-map recentf-dialog-mode-map))
894    
895  ;;;;  ;;; Hooks
896  ;;;; Hooks and Commands  ;;
897  ;;;;  (defun recentf-track-opened-file ()
898      "Insert the name of the file just opened or written into the recent list."
899  (defun recentf-add-file-hook ()    (and buffer-file-name
900    "Insert the name of the file just opened or written into `recentf-list'."         (recentf-add-file buffer-file-name))
901    (and buffer-file-name (recentf-add-file buffer-file-name))    ;; Must return nil because it is run from `write-file-functions'.
   nil)  
   
 (defun recentf-remove-file-hook ()  
   "When a buffer is killed remove a non readable file from `recentf-list'."  
   (and buffer-file-name (recentf-remove-if-non-readable buffer-file-name))  
902    nil)    nil)
903    
904  (defun recentf-update-menu-hook ()  (defun recentf-track-closed-file ()
905    "Update the recentf menu from the current `recentf-list'."    "Update the recent list when a buffer is killed.
906    (when recentf-update-menu-p  That is, remove a non readable file from the recent list, if
907      (condition-case nil  `recentf-keep-non-readable-files-flag' is nil."
908          (progn    (and buffer-file-name
909            (setq recentf-update-menu-p nil)         (not recentf-keep-non-readable-files-flag)
910           (recentf-remove-if-non-readable buffer-file-name)))
911    
912    (defun recentf-update-menu ()
913      "Update the recentf menu from the current recent list."
914      (let ((cache (cons default-directory recentf-list)))
915        ;; Does nothing, if nothing has changed.
916        (unless (equal recentf-data-cache cache)
917          (setq recentf-data-cache cache)
918          (condition-case err
919            (easy-menu-change recentf-menu-path            (easy-menu-change recentf-menu-path
920                              recentf-menu-title                              recentf-menu-title
921                              (recentf-make-menu-items)                              (recentf-make-menu-items)
922                              recentf-menu-before))                              recentf-menu-before)
923        (error nil))))          (error
924             (message "recentf update menu failed: %s"
925                      (error-message-string err)))))))
926    
927  (defun recentf-dump-variable (variable &optional limit)  (defconst recentf-used-hooks
928    "Insert a \"(setq VARIABLE value)\" in the current buffer.    '(
929  Optional argument LIMIT specifies a maximum length when VARIABLE value      (find-file-hook       recentf-track-opened-file)
930  is a list (default to the full list)."      (write-file-functions recentf-track-opened-file)
931    (let ((value (symbol-value variable)))      (kill-buffer-hook     recentf-track-closed-file)
932      (if (listp value)      (menu-bar-update-hook recentf-update-menu)
933          (progn      (kill-emacs-hook      recentf-save-list)
934            (when (and (integerp limit) (> limit 0))      )
935              (setq value (recentf-trunc-list value limit)))    "Hooks used by recentf.")
           (insert (format "(setq %S '(" variable))  
           (mapc (lambda (e) (insert (format "\n%S" e))) value)  
           (insert "))\n"))  
       (insert (format "(setq %S %S)\n" variable value)))))  
   
 ;;;###autoload  
 (defun recentf-save-list ()  
   "Save the current `recentf-list' to the file `recentf-save-file'."  
   (interactive)  
   (with-temp-buffer  
     (erase-buffer)  
     (insert (format recentf-save-file-header (current-time-string)))  
     (recentf-dump-variable 'recentf-list recentf-max-saved-items)  
     (recentf-dump-variable 'recentf-filter-changer-state)  
     (if (file-writable-p recentf-save-file)  
         (write-region (point-min) (point-max) recentf-save-file))  
     (kill-buffer (current-buffer)))  
   nil)  
936    
937    (defsubst recentf-enabled-p ()
938      "Return non-nil if recentf mode is currently enabled."
939      (memq 'recentf-update-menu menu-bar-update-hook))
940    
941    ;;; Commands
942    ;;
943  (defvar recentf-edit-selected-items nil  (defvar recentf-edit-selected-items nil
944    "Used by `recentf-edit-list'.    "List of files to be deleted from the recent list.
945  Holds list of files to be deleted from `recentf-list'.")  Used internally by `recentf-edit-list'.")
946    
947  (defun recentf-edit-list-action (widget &rest ignore)  (defun recentf-edit-list-action (widget &rest ignore)
948    "Checkbox WIDGET action used by `recentf-edit-list' to select/unselect a file."    "Checkbox WIDGET action that toogles a file selection.
949    Used internally by `recentf-edit-list'.
950    IGNORE other arguments."
951    (let ((value (widget-get widget ':tag)))    (let ((value (widget-get widget ':tag)))
952      ;; if value is already in the selected items      ;; if value is already in the selected items
953      (if (memq value recentf-edit-selected-items)      (if (memq value recentf-edit-selected-items)
# Line 882  Holds list of files to be deleted from ` Line 955  Holds list of files to be deleted from `
955          (progn          (progn
956            (setq recentf-edit-selected-items            (setq recentf-edit-selected-items
957                  (delq value recentf-edit-selected-items))                  (delq value recentf-edit-selected-items))
958            (message "%s removed from selection." value))            (message "%s removed from selection" value))
959        ;; else add it        ;; else add it
960        (progn        (push value recentf-edit-selected-items)
961          (setq recentf-edit-selected-items        (message "%s added to selection" value))))
               (nconc (list value) recentf-edit-selected-items))  
         (message "%s added to selection." value)))))  
962    
 ;;;###autoload  
963  (defun recentf-edit-list ()  (defun recentf-edit-list ()
964    "Allow the user to edit the files that are kept in the recent list."    "Show a dialog buffer to edit the recent list.
965    That is to select files to be deleted from the recent list."
966    (interactive)    (interactive)
967    (with-current-buffer (get-buffer-create (concat "*" recentf-menu-title " - Edit list*"))    (with-current-buffer
968          (get-buffer-create (format "*%s - Edit list*" recentf-menu-title))
969      (switch-to-buffer (current-buffer))      (switch-to-buffer (current-buffer))
970        ;; Cleanup buffer
971      (kill-all-local-variables)      (kill-all-local-variables)
972      (let ((inhibit-read-only t))      (let ((inhibit-read-only t)
973        (erase-buffer))            (ol (overlay-lists)))
974      (let ((all (overlay-lists)))        (erase-buffer)
975        ;; Delete all the overlays.        ;; Delete all the overlays.
976        (mapc 'delete-overlay (car all))        (mapc 'delete-overlay (car ol))
977        (mapc 'delete-overlay (cdr all)))        (mapc 'delete-overlay (cdr ol)))
978      (setq recentf-edit-selected-items nil)      (setq recentf-edit-selected-items nil)
979      ;; Insert the dialog header      ;; Insert the dialog header
980      (widget-insert "Select the files to be deleted from the 'recentf-list'.\n\n")      (widget-insert
981      (widget-insert "Click on Ok to update the list. ")       "\
982      (widget-insert "Click on Cancel or type \"q\" to quit.\n")  Select the files to be deleted from the recent list.\n\n\
983    Click on Ok to update the list. \
984    Click on Cancel or type \"q\" to quit.\n")
985      ;; Insert the list of files as checkboxes      ;; Insert the list of files as checkboxes
986      (mapc (function      (dolist (item recentf-list)
987             (lambda (item)        (widget-create
988               (widget-create 'checkbox         'checkbox
989                              :value nil  ; unselected checkbox         :value nil                       ; unselected checkbox
990                              :format "\n %[%v%]  %t"         :format "\n %[%v%]  %t"
991                              :tag item         :tag item
992                              :notify 'recentf-edit-list-action)))         :notify 'recentf-edit-list-action))
           recentf-list)  
993      (widget-insert "\n\n")      (widget-insert "\n\n")
994      ;; Insert the Ok button      ;; Insert the Ok button
995      (widget-create 'push-button      (widget-create
996                     :notify (lambda (&rest ignore)       'push-button
997                               (if recentf-edit-selected-items       :notify (lambda (&rest ignore)
998                                   (progn (kill-buffer (current-buffer))                 (if recentf-edit-selected-items
999                                          (mapc (function                     (let ((i 0))
1000                                                 (lambda (item)                       (kill-buffer (current-buffer))
1001                                                   (setq recentf-list                       (dolist (e recentf-edit-selected-items)
1002                                                         (delq item recentf-list))))                         (setq recentf-list (delq e recentf-list)
1003                                                recentf-edit-selected-items)                               i (1+ i)))
1004                                          (message "%S file(s) removed from the list"                       (message "%S file(s) removed from the list" i))
1005                                                   (length recentf-edit-selected-items))                   (message "No file selected")))
1006                                          (setq recentf-update-menu-p t))       "Ok")
                                (message "No file selected.")))  
                    "Ok")  
1007      (widget-insert " ")      (widget-insert " ")
1008      ;; Insert the Cancel button      ;; Insert the Cancel button
1009      (widget-create 'push-button      (widget-create
1010                     :notify 'recentf-cancel-dialog       'push-button
1011                     "Cancel")       :notify 'recentf-cancel-dialog
1012         "Cancel")
1013      (recentf-dialog-mode)      (recentf-dialog-mode)
1014      (widget-setup)      (widget-setup)
1015      (goto-char (point-min))))      (goto-char (point-min))))
1016    
 ;;;###autoload  
 (defun recentf-cleanup ()  
   "Remove all non-readable and excluded files from `recentf-list'."  
   (interactive)  
   (let ((count (length recentf-list)))  
     (setq recentf-list  
           (delq nil  
                 (mapcar (function  
                          (lambda (filename)  
                            (and (file-readable-p filename)  
                                 (recentf-include-p filename)  
                                 filename)))  
                         recentf-list)))  
     (setq count (- count (length recentf-list)))  
     (message "%s removed from the list"  
              (cond ((= count 0) "No file")  
                    ((= count 1) "One file")  
                    (t (format "%d files" count)))))  
   (setq recentf-update-menu-p t))  
   
1017  (defun recentf-open-files-action (widget &rest ignore)  (defun recentf-open-files-action (widget &rest ignore)
1018    "Button WIDGET action used by `recentf-open-files' to open a file."    "Button WIDGET action that open a file.
1019    Used internally by `recentf-open-files'.
1020    IGNORE other arguments."
1021    (kill-buffer (current-buffer))    (kill-buffer (current-buffer))
1022    (funcall recentf-menu-action (widget-value widget)))    (funcall recentf-menu-action (widget-value widget)))
1023    
1024  (defvar recentf-open-files-item-shift ""  (defvar recentf-open-files-item-shift ""
1025    "String used by `recentf-open-files' to shift right sub-menu items.")    "Amount of space to shift right sub-menu items.
1026    Used internally by `recentf-open-files'.")
1027    
1028  (defun recentf-open-files-item (menu-element)  (defun recentf-open-files-item (menu-element)
1029    "Insert MENU-ELEMENT item in the current interaction buffer."    "Insert an item widget for MENU-ELEMENT in the current dialog buffer.
1030    (let ((menu-item (car menu-element))  Used internally by `recentf-open-files'."
1031          (file-path (cdr menu-element)))    (let ((item (car menu-element))
1032      (if (consp file-path)               ; This is a sub-menu          (file (cdr menu-element)))
1033        (if (consp file)               ; This is a sub-menu
1034          (let* ((shift recentf-open-files-item-shift)          (let* ((shift recentf-open-files-item-shift)
1035                 (recentf-open-files-item-shift (concat shift "  ")))                 (recentf-open-files-item-shift (concat shift "  ")))
1036            (widget-create 'item            (widget-create
1037                           :tag menu-item             'item
1038                           :sample-face 'bold             :tag item
1039                           :format (concat shift "%{%t%}:\n"))             :sample-face 'bold
1040            (mapc 'recentf-open-files-item             :format (concat shift "%{%t%}:\n"))
1041                  file-path)            (mapc 'recentf-open-files-item file)
1042            (widget-insert "\n"))            (widget-insert "\n"))
1043        (widget-create 'push-button        (widget-create
1044                       :button-face 'default         'push-button
1045                       :tag menu-item         :button-face 'default
1046                       :help-echo (concat "Open " file-path)         :tag item
1047                       :format (concat recentf-open-files-item-shift "%[%t%]")         :help-echo (concat "Open " file)
1048                       :notify 'recentf-open-files-action         :format (concat recentf-open-files-item-shift "%[%t%]")
1049                       file-path)         :notify 'recentf-open-files-action
1050           file)
1051        (widget-insert "\n"))))        (widget-insert "\n"))))
1052    
 ;;;###autoload  
1053  (defun recentf-open-files (&optional files buffer-name)  (defun recentf-open-files (&optional files buffer-name)
1054    "Display buffer allowing user to choose a file from recently-opened list.    "Show a dialog buffer to open a recent file.
1055  The optional argument FILES may be used to specify the list, otherwise  If optional argument FILES is non-nil, it specifies the list of
1056  `recentf-list' is used.  The optional argument BUFFER-NAME specifies  recently-opened files to choose from.  It is the whole recent list
1057  which buffer to use for the interaction."  otherwise.
1058    If optional argument BUFFER-NAME is non-nil, it specifies which buffer
1059    name to use for the interaction.  It is \"*`recentf-menu-title'*\" by
1060    default."
1061    (interactive)    (interactive)
1062    (if (null files)    (unless files
1063        (setq files recentf-list))      (setq files recentf-list))
1064    (if (null buffer-name)    (unless buffer-name
1065        (setq buffer-name (concat "*" recentf-menu-title "*")))      (setq buffer-name (format "*%s*" recentf-menu-title)))
1066    (with-current-buffer (get-buffer-create buffer-name)    (with-current-buffer (get-buffer-create buffer-name)
1067      (switch-to-buffer (current-buffer))      (switch-to-buffer (current-buffer))
1068        ;; Cleanup buffer
1069      (kill-all-local-variables)      (kill-all-local-variables)
1070      (let ((inhibit-read-only t))      (let ((inhibit-read-only t)
1071        (erase-buffer))            (ol (overlay-lists)))
1072      (let ((all (overlay-lists)))        (erase-buffer)
1073        ;; Delete all the overlays.        ;; Delete all the overlays.
1074        (mapc 'delete-overlay (car all))        (mapc 'delete-overlay (car ol))
1075        (mapc 'delete-overlay (cdr all)))        (mapc 'delete-overlay (cdr ol)))
1076      ;; Insert the dialog header      ;; Insert the dialog header
1077      (widget-insert "Click on a file to open it. ")      (widget-insert "Click on a file to open it. ")
1078      (widget-insert "Click on Cancel or type \"q\" to quit.\n\n" )      (widget-insert "Click on Cancel or type \"q\" to quit.\n\n" )
# Line 1023  which buffer to use for the interaction. Line 1084  which buffer to use for the interaction.
1084               (mapcar 'recentf-make-default-menu-element files))))               (mapcar 'recentf-make-default-menu-element files))))
1085      (widget-insert "\n")      (widget-insert "\n")
1086      ;; Insert the Cancel button      ;; Insert the Cancel button
1087      (widget-create 'push-button      (widget-create
1088                     :notify 'recentf-cancel-dialog       'push-button
1089                     "Cancel")       :notify 'recentf-cancel-dialog
1090         "Cancel")
1091      (recentf-dialog-mode)      (recentf-dialog-mode)
1092      (widget-setup)      (widget-setup)
1093      (goto-char (point-min))))      (goto-char (point-min))))
1094    
 ;;;###autoload  
1095  (defun recentf-open-more-files ()  (defun recentf-open-more-files ()
1096    "Allow the user to open files that are not in the menu."    "Show a dialog buffer to open a recent file that is not in the menu."
1097    (interactive)    (interactive)
1098    (recentf-open-files (nthcdr recentf-max-menu-items recentf-list)    (recentf-open-files (nthcdr recentf-max-menu-items recentf-list)
1099                        (concat "*" recentf-menu-title " - More*")))                        (format "*%s - More*" recentf-menu-title)))
1100    
1101    (defconst recentf-save-file-header
1102      ";;; Automatically generated by `recentf' on %s.\n"
1103      "Header to be written into the `recentf-save-file'.")
1104    
1105    (defun recentf-save-list ()
1106      "Save the recent list.
1107    Write data into the file specified by `recentf-save-file'."
1108      (interactive)
1109      (with-temp-file (expand-file-name recentf-save-file)
1110        (erase-buffer)
1111        (insert (format recentf-save-file-header (current-time-string)))
1112        (recentf-dump-variable 'recentf-list recentf-max-saved-items)
1113        (recentf-dump-variable 'recentf-filter-changer-state)
1114        nil))
1115    
1116    (defun recentf-load-list ()
1117      "Load a previously saved recent list.
1118    Read data from the file specified by `recentf-save-file'."
1119      (interactive)
1120      (let ((file (expand-file-name recentf-save-file)))
1121        (when (file-readable-p file)
1122          (load-file file))))
1123    
1124    (defun recentf-cleanup ()
1125      "Remove all non-readable and excluded files from the recent list."
1126      (interactive)
1127      (message "Cleaning up the recentf list...")
1128      (let (newlist)
1129        (dolist (f recentf-list)
1130          (if (and (file-readable-p f) (recentf-include-p f))
1131              (push f newlist)
1132            (message "File %s removed from the recentf list" f)))
1133        (setq recentf-list (nreverse newlist))
1134        (message "Cleaning up the recentf list...done")))
1135    
 ;;; Note this definition must be at the end of the file, because  
 ;;; `define-minor-mode' actually calls the mode-function if the  
 ;;; associated variable is non-nil, which requires that all needed  
 ;;; functions be already defined.  [This is arguably a bug in d-m-m]  
1136  ;;;###autoload  ;;;###autoload
1137  (define-minor-mode recentf-mode  (define-minor-mode recentf-mode
1138    "Toggle recentf mode.    "Toggle recentf mode.
1139  With prefix argument ARG, turn on if positive, otherwise off.  With prefix argument ARG, turn on if positive, otherwise off.
1140  Returns non-nil if the new state is enabled.  Returns non-nil if the new state is enabled.
1141    
1142  When recentf mode is enabled, it maintains a menu for visiting files that  When recentf mode is enabled, it maintains a menu for visiting files
1143  were operated on recently."  that were operated on recently."
1144    :global t    :global t
1145    :group 'recentf    :group 'recentf
1146    (if recentf-mode    (unless (and recentf-mode (recentf-enabled-p))
1147        (unless recentf-initialized-p      (if recentf-mode
1148          (setq recentf-initialized-p t)          (recentf-load-list)
1149          (if (file-readable-p recentf-save-file)        (recentf-save-list))
1150              (load-file recentf-save-file))      (recentf-auto-cleanup)
1151          (setq recentf-update-menu-p t)      (recentf-clear-data)
1152          (add-hook 'find-file-hooks       'recentf-add-file-hook)      (let ((hook-setup (if recentf-mode 'add-hook 'remove-hook)))
1153          (add-hook 'write-file-hooks      'recentf-add-file-hook)        (dolist (hook recentf-used-hooks)
1154          (add-hook 'menu-bar-update-hook  'recentf-update-menu-hook)          (apply hook-setup hook)))
1155          (add-hook 'kill-emacs-hook       'recentf-save-list))      (run-hooks 'recentf-mode-hook)
1156      (when recentf-initialized-p      (when (interactive-p)
1157        (setq recentf-initialized-p nil)        (message "Recentf mode %sabled" (if recentf-mode "en" "dis"))))
1158        (recentf-save-list)    recentf-mode)
       (easy-menu-remove-item nil recentf-menu-path recentf-menu-title)  
       (remove-hook 'find-file-hooks       'recentf-add-file-hook)  
       (remove-hook 'write-file-hooks      'recentf-add-file-hook)  
       (remove-hook 'menu-bar-update-hook  'recentf-update-menu-hook)  
       (remove-hook 'kill-emacs-hook       'recentf-save-list))))  
   
1159    
1160  (provide 'recentf)  (provide 'recentf)
1161    

Legend:
Removed from v.1.22  
changed lines
  Added in v.1.23

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26