home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.006 / xemacs-1 / lib / xemacs-19.13 / lisp / packages / recent-files.el < prev    next >
Encoding:
Text File  |  1995-04-17  |  25.4 KB  |  670 lines

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