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