diff options
| author | David Ponce | 2005-12-09 08:16:04 +0000 |
|---|---|---|
| committer | David Ponce | 2005-12-09 08:16:04 +0000 |
| commit | 52d2876f3c0435d567cb11078ef22c23c4db6dad (patch) | |
| tree | 0f33293318b870703ae183d1962b32edf7d5d602 | |
| parent | 5a8781ad99c65568fe6c3dcbcb9dfa25b5fafec5 (diff) | |
| download | emacs-52d2876f3c0435d567cb11078ef22c23c4db6dad.tar.gz emacs-52d2876f3c0435d567cb11078ef22c23c4db6dad.zip | |
Improvement of the menu code.
(recentf-enabled-p): Move before first use. Use `kill-emacs-hook'
instead of menu hook.
(recentf-show-menu, recentf-hide-menu): New functions.
(recentf-menu-customization-changed, recentf-mode): Use them.
(recentf-menu-action, recentf-max-menu-items)
(recentf-menu-open-all-flag, recentf-menu-append-commands-flag)
(recentf-arrange-by-rule-others)
(recentf-arrange-by-rules-min-items)
(recentf-arrange-by-rule-subfilter) : Don't use
`recentf-menu-customization-changed'.
(recentf-arrange-rules): Likewise. Accept functions to compute
sub-menu titles.
(recentf-menu-filter): Likewise. Doc fix.
(recentf-menu-value-shortcut): Doc fix.
(recentf-dump-variable): Quote atom value.
(recentf-make-menu-items): Update to use it as a menu filter.
(recentf-match-rule): New function.
(recentf-arrange-by-rule): Use it.
(recentf-indirect-mode-rule): New function.
(recentf-build-mode-rules): Use it.
(recentf-dir-rule): New function.
(recentf-arrange-by-dir): Use it.
(recentf-filter-changer-current): Rename from
`recentf-filter-changer-state'. All references updated.
(recentf-filter-changer-alist): Update filter names.
(recentf-filter-changer-select): New function.
(recentf-filter-changer): Use it. Make a sub-menu from filters
available in `recentf-filter-changer-alist'.
(recentf-data-cache, recentf-clear-data)
(recentf-update-menu): Remove. All references updated.
(recentf-match-rule-p, recentf-build-dir-rules)
(recentf-filter-changer-goto-next)
(recentf-filter-changer-get-current)
(recentf-filter-changer-get-next): Remove.
| -rw-r--r-- | lisp/recentf.el | 385 |
1 files changed, 177 insertions, 208 deletions
diff --git a/lisp/recentf.el b/lisp/recentf.el index 287ab3014cb..d92bc92f6ee 100644 --- a/lisp/recentf.el +++ b/lisp/recentf.el | |||
| @@ -46,9 +46,9 @@ | |||
| 46 | (defvar recentf-list nil | 46 | (defvar recentf-list nil |
| 47 | "List of recently opened files.") | 47 | "List of recently opened files.") |
| 48 | 48 | ||
| 49 | (defvar recentf-data-cache nil | 49 | (defsubst recentf-enabled-p () |
| 50 | "Cache of data used to build the recentf menu. | 50 | "Return non-nil if recentf mode is currently enabled." |
| 51 | The menu is rebuilt when this data has changed.") | 51 | (memq 'recentf-save-list kill-emacs-hook)) |
| 52 | 52 | ||
| 53 | ;;; Customization | 53 | ;;; Customization |
| 54 | ;; | 54 | ;; |
| @@ -111,10 +111,13 @@ remote access." | |||
| 111 | (defun recentf-menu-customization-changed (variable value) | 111 | (defun recentf-menu-customization-changed (variable value) |
| 112 | "Function called when the recentf menu customization has changed. | 112 | "Function called when the recentf menu customization has changed. |
| 113 | Set VARIABLE with VALUE, and force a rebuild of the recentf menu." | 113 | Set VARIABLE with VALUE, and force a rebuild of the recentf menu." |
| 114 | (when (featurep 'recentf) | 114 | (if (and (featurep 'recentf) (recentf-enabled-p)) |
| 115 | ;; Unavailable until recentf has been loaded. | 115 | (progn |
| 116 | (recentf-clear-data)) | 116 | ;; Unavailable until recentf has been loaded. |
| 117 | (set-default variable value)) | 117 | (recentf-hide-menu) |
| 118 | (set-default variable value) | ||
| 119 | (recentf-show-menu)) | ||
| 120 | (set-default variable value))) | ||
| 118 | 121 | ||
| 119 | (defcustom recentf-menu-title "Open Recent" | 122 | (defcustom recentf-menu-title "Open Recent" |
| 120 | "*Name of the recentf menu." | 123 | "*Name of the recentf menu." |
| @@ -142,14 +145,12 @@ If nil add it at end of menu (see also `easy-menu-add-item')." | |||
| 142 | "*Function to invoke with a filename item of the recentf menu. | 145 | "*Function to invoke with a filename item of the recentf menu. |
| 143 | The default is to call `find-file' to edit the selected file." | 146 | The default is to call `find-file' to edit the selected file." |
| 144 | :group 'recentf | 147 | :group 'recentf |
| 145 | :type 'function | 148 | :type 'function) |
| 146 | :set 'recentf-menu-customization-changed) | ||
| 147 | 149 | ||
| 148 | (defcustom recentf-max-menu-items 10 | 150 | (defcustom recentf-max-menu-items 10 |
| 149 | "*Maximum number of items in the recentf menu." | 151 | "*Maximum number of items in the recentf menu." |
| 150 | :group 'recentf | 152 | :group 'recentf |
| 151 | :type 'integer | 153 | :type 'integer) |
| 152 | :set 'recentf-menu-customization-changed) | ||
| 153 | 154 | ||
| 154 | (defcustom recentf-menu-filter nil | 155 | (defcustom recentf-menu-filter nil |
| 155 | "*Function used to filter files displayed in the recentf menu. | 156 | "*Function used to filter files displayed in the recentf menu. |
| @@ -182,7 +183,7 @@ A nil value means no filter. The following functions are predefined: | |||
| 182 | - `recentf-arrange-by-dir' | 183 | - `recentf-arrange-by-dir' |
| 183 | Show a sub-menu for each directory. | 184 | Show a sub-menu for each directory. |
| 184 | - `recentf-filter-changer' | 185 | - `recentf-filter-changer' |
| 185 | Manage a ring of filters. | 186 | Manage a menu of filters. |
| 186 | 187 | ||
| 187 | The filter function is called with one argument, the list of menu | 188 | The filter function is called with one argument, the list of menu |
| 188 | elements used to build the menu and must return a new list of menu | 189 | elements used to build the menu and must return a new list of menu |
| @@ -203,21 +204,18 @@ elements (see `recentf-make-menu-element' for menu element form)." | |||
| 203 | (function-item recentf-arrange-by-mode) | 204 | (function-item recentf-arrange-by-mode) |
| 204 | (function-item recentf-arrange-by-dir) | 205 | (function-item recentf-arrange-by-dir) |
| 205 | (function-item recentf-filter-changer) | 206 | (function-item recentf-filter-changer) |
| 206 | function) | 207 | function)) |
| 207 | :set 'recentf-menu-customization-changed) | ||
| 208 | 208 | ||
| 209 | (defcustom recentf-menu-open-all-flag nil | 209 | (defcustom recentf-menu-open-all-flag nil |
| 210 | "*Non-nil means to show an \"All...\" item in the menu. | 210 | "*Non-nil means to show an \"All...\" item in the menu. |
| 211 | This item will replace the \"More...\" item." | 211 | This item will replace the \"More...\" item." |
| 212 | :group 'recentf | 212 | :group 'recentf |
| 213 | :type 'boolean | 213 | :type 'boolean) |
| 214 | :set 'recentf-menu-customization-changed) | ||
| 215 | 214 | ||
| 216 | (defcustom recentf-menu-append-commands-flag t | 215 | (defcustom recentf-menu-append-commands-flag t |
| 217 | "*Non-nil means to append command items to the menu." | 216 | "*Non-nil means to append command items to the menu." |
| 218 | :group 'recentf | 217 | :group 'recentf |
| 219 | :type 'boolean | 218 | :type 'boolean) |
| 220 | :set 'recentf-menu-customization-changed) | ||
| 221 | 219 | ||
| 222 | (define-obsolete-variable-alias 'recentf-menu-append-commands-p | 220 | (define-obsolete-variable-alias 'recentf-menu-append-commands-p |
| 223 | 'recentf-menu-append-commands-flag | 221 | 'recentf-menu-append-commands-flag |
| @@ -331,7 +329,7 @@ specifies a maximum number of elements to insert. By default insert | |||
| 331 | the full list." | 329 | the full list." |
| 332 | (let ((value (symbol-value variable))) | 330 | (let ((value (symbol-value variable))) |
| 333 | (if (atom value) | 331 | (if (atom value) |
| 334 | (insert (format "\n(setq %S %S)\n" variable value)) | 332 | (insert (format "\n(setq %S '%S)\n" variable value)) |
| 335 | (when (and (integerp limit) (> limit 0)) | 333 | (when (and (integerp limit) (> limit 0)) |
| 336 | (setq value (recentf-trunc-list value limit))) | 334 | (setq value (recentf-trunc-list value limit))) |
| 337 | (insert (format "\n(setq %S\n '(" variable)) | 335 | (insert (format "\n(setq %S\n '(" variable)) |
| @@ -576,35 +574,40 @@ menu-elements (no sub-menu)." | |||
| 576 | ;; Count the number of assigned menu shortcuts. | 574 | ;; Count the number of assigned menu shortcuts. |
| 577 | (defvar recentf-menu-shortcuts) | 575 | (defvar recentf-menu-shortcuts) |
| 578 | 576 | ||
| 579 | (defun recentf-make-menu-items () | 577 | (defun recentf-make-menu-items (&optional menu) |
| 580 | "Make menu items from the recent list." | 578 | "Make menu items from the recent list. |
| 579 | This is a menu filter function which ignores the MENU argument." | ||
| 581 | (setq recentf-menu-filter-commands nil) | 580 | (setq recentf-menu-filter-commands nil) |
| 582 | (let* ((recentf-menu-shortcuts 0) | 581 | (let* ((recentf-menu-shortcuts 0) |
| 583 | (file-items | 582 | (file-items |
| 584 | (mapcar 'recentf-make-menu-item | 583 | (condition-case err |
| 585 | (recentf-apply-menu-filter | 584 | (mapcar 'recentf-make-menu-item |
| 586 | recentf-menu-filter | 585 | (recentf-apply-menu-filter |
| 587 | (recentf-menu-elements recentf-max-menu-items))))) | 586 | recentf-menu-filter |
| 588 | (append (or file-items (list ["No files" t | 587 | (recentf-menu-elements recentf-max-menu-items))) |
| 589 | :help "No recent file to open" | 588 | (error |
| 590 | :active nil])) | 589 | (message "recentf update menu failed: %s" |
| 591 | (if recentf-menu-open-all-flag | 590 | (error-message-string err)))))) |
| 592 | (list ["All..." recentf-open-files | 591 | (append |
| 593 | :help "Open recent files through a dialog" | 592 | (or file-items |
| 594 | :active t]) | 593 | '(["No files" t |
| 595 | (and (< recentf-max-menu-items (length recentf-list)) | 594 | :help "No recent file to open" |
| 596 | (list ["More..." recentf-open-more-files | 595 | :active nil])) |
| 597 | :help "Open files not in the menu through a dialog" | 596 | (if recentf-menu-open-all-flag |
| 598 | :active t]))) | 597 | '(["All..." recentf-open-files |
| 599 | (and recentf-menu-filter-commands | 598 | :help "Open recent files through a dialog" |
| 600 | (cons "---" | 599 | :active t]) |
| 601 | recentf-menu-filter-commands)) | 600 | (and (< recentf-max-menu-items (length recentf-list)) |
| 602 | (and recentf-menu-append-commands-flag | 601 | '(["More..." recentf-open-more-files |
| 603 | (cons "---" | 602 | :help "Open files not in the menu through a dialog" |
| 604 | recentf-menu-items-for-commands))))) | 603 | :active t]))) |
| 604 | (and recentf-menu-filter-commands '("---")) | ||
| 605 | recentf-menu-filter-commands | ||
| 606 | (and recentf-menu-items-for-commands '("---")) | ||
| 607 | recentf-menu-items-for-commands))) | ||
| 605 | 608 | ||
| 606 | (defun recentf-menu-value-shortcut (name) | 609 | (defun recentf-menu-value-shortcut (name) |
| 607 | "Return a shorcut digit for file NAME. | 610 | "Return a shortcut digit for file NAME. |
| 608 | Return nil if file NAME is not one of the ten more recent." | 611 | Return nil if file NAME is not one of the ten more recent." |
| 609 | (let ((i 0) k) | 612 | (let ((i 0) k) |
| 610 | (while (and (not k) (< i 10)) | 613 | (while (and (not k) (< i 10)) |
| @@ -639,12 +642,17 @@ Return nil if file NAME is not one of the ten more recent." | |||
| 639 | "Return the keymap of the global menu bar." | 642 | "Return the keymap of the global menu bar." |
| 640 | (lookup-key global-map [menu-bar])) | 643 | (lookup-key global-map [menu-bar])) |
| 641 | 644 | ||
| 642 | (defun recentf-clear-data () | 645 | (defun recentf-show-menu () |
| 643 | "Clear data used to build the recentf menu. | 646 | "Show the menu of recently opened files." |
| 644 | This forces a rebuild of the menu." | 647 | (easy-menu-add-item |
| 645 | (easy-menu-remove-item (recentf-menu-bar) | 648 | (recentf-menu-bar) recentf-menu-path |
| 646 | recentf-menu-path recentf-menu-title) | 649 | (list recentf-menu-title :filter 'recentf-make-menu-items) |
| 647 | (setq recentf-data-cache nil)) | 650 | recentf-menu-before)) |
| 651 | |||
| 652 | (defun recentf-hide-menu () | ||
| 653 | "Hide the menu of recently opened files." | ||
| 654 | (easy-menu-remove-item (recentf-menu-bar) recentf-menu-path | ||
| 655 | recentf-menu-title)) | ||
| 648 | 656 | ||
| 649 | ;;; Predefined menu filters | 657 | ;;; Predefined menu filters |
| 650 | ;; | 658 | ;; |
| @@ -750,19 +758,24 @@ Filenames are relative to the `default-directory'." | |||
| 750 | ;; | 758 | ;; |
| 751 | (defcustom recentf-arrange-rules | 759 | (defcustom recentf-arrange-rules |
| 752 | '( | 760 | '( |
| 753 | ("Elisp files (%d)" ".\\.el$") | 761 | ("Elisp files (%d)" ".\\.el\\'") |
| 754 | ("Java files (%d)" ".\\.java$") | 762 | ("Java files (%d)" ".\\.java\\'") |
| 755 | ("C/C++ files (%d)" "c\\(pp\\)?$") | 763 | ("C/C++ files (%d)" "c\\(pp\\)?\\'") |
| 756 | ) | 764 | ) |
| 757 | "*List of rules used by `recentf-arrange-by-rule' to build sub-menus. | 765 | "*List of rules used by `recentf-arrange-by-rule' to build sub-menus. |
| 758 | A rule is a pair (SUB-MENU-TITLE . MATCHER). SUB-MENU-TITLE is the | 766 | A rule is a pair (SUB-MENU-TITLE . MATCHER). SUB-MENU-TITLE is the |
| 759 | displayed title of the sub-menu where a '%d' `format' pattern is | 767 | displayed title of the sub-menu where a '%d' `format' pattern is |
| 760 | replaced by the number of items in the sub-menu. MATCHER is a regexp | 768 | replaced by the number of items in the sub-menu. MATCHER is a regexp |
| 761 | or a list of regexps. Items matching one of the regular expressions in | 769 | or a list of regexps. Items matching one of the regular expressions in |
| 762 | MATCHER are added to the corresponding sub-menu." | 770 | MATCHER are added to the corresponding sub-menu. |
| 771 | SUB-MENU-TITLE can be a function. It is passed every items that | ||
| 772 | matched the corresponding MATCHER, and it must return a | ||
| 773 | pair (SUB-MENU-TITLE . ITEM). SUB-MENU-TITLE is a computed sub-menu | ||
| 774 | title that can be another function. ITEM is the received item which | ||
| 775 | may have been modified to match another rule." | ||
| 763 | :group 'recentf-filters | 776 | :group 'recentf-filters |
| 764 | :type '(repeat (cons string (repeat regexp))) | 777 | :type '(repeat (cons (choice string function) |
| 765 | :set 'recentf-menu-customization-changed) | 778 | (repeat regexp)))) |
| 766 | 779 | ||
| 767 | (defcustom recentf-arrange-by-rule-others "Other files (%d)" | 780 | (defcustom recentf-arrange-by-rule-others "Other files (%d)" |
| 768 | "*Title of the `recentf-arrange-by-rule' sub-menu. | 781 | "*Title of the `recentf-arrange-by-rule' sub-menu. |
| @@ -772,8 +785,7 @@ displayed in the main recent files menu. A '%d' `format' pattern in | |||
| 772 | the title is replaced by the number of items in the sub-menu." | 785 | the title is replaced by the number of items in the sub-menu." |
| 773 | :group 'recentf-filters | 786 | :group 'recentf-filters |
| 774 | :type '(choice (const :tag "Main menu" nil) | 787 | :type '(choice (const :tag "Main menu" nil) |
| 775 | (string :tag "Title")) | 788 | (string :tag "Title"))) |
| 776 | :set 'recentf-menu-customization-changed) | ||
| 777 | 789 | ||
| 778 | (defcustom recentf-arrange-by-rules-min-items 0 | 790 | (defcustom recentf-arrange-by-rules-min-items 0 |
| 779 | "*Minimum number of items in a `recentf-arrange-by-rule' sub-menu. | 791 | "*Minimum number of items in a `recentf-arrange-by-rule' sub-menu. |
| @@ -782,8 +794,7 @@ corresponding sub-menu items are displayed in the main recent files | |||
| 782 | menu or in the `recentf-arrange-by-rule-others' sub-menu if | 794 | menu or in the `recentf-arrange-by-rule-others' sub-menu if |
| 783 | defined." | 795 | defined." |
| 784 | :group 'recentf-filters | 796 | :group 'recentf-filters |
| 785 | :type 'number | 797 | :type 'number) |
| 786 | :set 'recentf-menu-customization-changed) | ||
| 787 | 798 | ||
| 788 | (defcustom recentf-arrange-by-rule-subfilter nil | 799 | (defcustom recentf-arrange-by-rule-subfilter nil |
| 789 | "*Function called by a rule based filter to filter sub-menu elements. | 800 | "*Function called by a rule based filter to filter sub-menu elements. |
| @@ -796,81 +807,82 @@ You can't use another rule based filter here." | |||
| 796 | recentf-arrange-by-mode | 807 | recentf-arrange-by-mode |
| 797 | recentf-arrange-by-dir)) | 808 | recentf-arrange-by-dir)) |
| 798 | (error "Recursive use of a rule based filter")) | 809 | (error "Recursive use of a rule based filter")) |
| 799 | (recentf-menu-customization-changed variable value))) | 810 | (set-default variable value))) |
| 800 | 811 | ||
| 801 | (defun recentf-match-rule-p (matcher filename) | 812 | (defun recentf-match-rule (file) |
| 802 | "Return non-nil if the rule specified by MATCHER match FILENAME. | 813 | "Return the rule that match FILE." |
| 803 | See `recentf-arrange-rules' for details on MATCHER." | 814 | (let ((rules recentf-arrange-rules) |
| 804 | (if (stringp matcher) | 815 | match found) |
| 805 | (string-match matcher filename) | 816 | (while (and (not found) rules) |
| 806 | (while (and (consp matcher) | 817 | (setq match (cdar rules)) |
| 807 | (not (string-match (car matcher) filename))) | 818 | (when (stringp match) |
| 808 | (setq matcher (cdr matcher))) | 819 | (setq match (list match))) |
| 809 | matcher)) | 820 | (while (and match (not (string-match (car match) file))) |
| 821 | (setq match (cdr match))) | ||
| 822 | (if match | ||
| 823 | (setq found (cons (caar rules) file)) | ||
| 824 | (setq rules (cdr rules)))) | ||
| 825 | found)) | ||
| 810 | 826 | ||
| 811 | (defun recentf-arrange-by-rule (l) | 827 | (defun recentf-arrange-by-rule (l) |
| 812 | "Filter the list of menu-elements L. | 828 | "Filter the list of menu-elements L. |
| 813 | Arrange them in sub-menus following rules in `recentf-arrange-rules'." | 829 | Arrange them in sub-menus following rules in `recentf-arrange-rules'." |
| 814 | (if (not recentf-arrange-rules) | 830 | (when recentf-arrange-rules |
| 815 | l | 831 | (let (menus others menu file min count) |
| 816 | (let* ((strip (assq t recentf-arrange-rules)) | ||
| 817 | (rules (remq strip recentf-arrange-rules)) | ||
| 818 | (menus (mapcar #'(lambda (r) (list (car r))) rules)) | ||
| 819 | others l1 l2 menu file min count) | ||
| 820 | ;; Put menu items into sub-menus as defined by rules. | 832 | ;; Put menu items into sub-menus as defined by rules. |
| 821 | (dolist (elt l) | 833 | (dolist (elt l) |
| 822 | (setq l1 menus ;; List of sub-menus | 834 | (setq file (recentf-menu-element-value elt) |
| 823 | l2 rules ;; List of corresponding matchers. | 835 | menu (recentf-match-rule file)) |
| 824 | file (recentf-menu-element-value elt) | 836 | (while (functionp (car menu)) |
| 825 | menu nil) | 837 | (setq menu (funcall (car menu) (cdr menu)))) |
| 826 | ;; Apply the strip suffix rule. | 838 | (if (not (stringp (car menu))) |
| 827 | (while (recentf-match-rule-p (cdr strip) file) | 839 | (push elt others) |
| 828 | (setq file (substring file 0 (match-beginning 0)))) | 840 | (setq menu (or (assoc (car menu) menus) |
| 829 | ;; Search which sub-menu to put the menu item into. | 841 | (car (push (list (car menu)) menus)))) |
| 830 | (while (and (not menu) l2) | 842 | (recentf-set-menu-element-value |
| 831 | (when (recentf-match-rule-p (cdar l2) file) | 843 | menu (cons elt (recentf-menu-element-value menu))))) |
| 832 | (setq menu (car l1)) | 844 | ;; Finalize each sub-menu: |
| 833 | (recentf-set-menu-element-value | ||
| 834 | menu (cons elt (recentf-menu-element-value menu)))) | ||
| 835 | (setq l1 (cdr l1) | ||
| 836 | l2 (cdr l2))) | ||
| 837 | ;; Put unmatched menu items in the `others' bin. | ||
| 838 | (or menu (push elt others))) | ||
| 839 | ;; Finalize the sub-menus. That is, for each one: | ||
| 840 | ;; - truncate it depending on the value of | 845 | ;; - truncate it depending on the value of |
| 841 | ;; `recentf-arrange-by-rules-min-items', | 846 | ;; `recentf-arrange-by-rules-min-items', |
| 842 | ;; - replace %d by the number of menu items, | 847 | ;; - replace %d by the number of menu items, |
| 843 | ;; - apply `recentf-arrange-by-rule-subfilter' to menu items. | 848 | ;; - apply `recentf-arrange-by-rule-subfilter' to menu items. |
| 844 | (setq min (if (natnump recentf-arrange-by-rules-min-items) | 849 | (setq min (if (natnump recentf-arrange-by-rules-min-items) |
| 845 | recentf-arrange-by-rules-min-items 0) | 850 | recentf-arrange-by-rules-min-items 0) |
| 846 | l2 nil) | 851 | l nil) |
| 847 | (dolist (menu menus) | 852 | (dolist (elt menus) |
| 848 | (when (setq l1 (recentf-menu-element-value menu)) | 853 | (setq menu (recentf-menu-element-value elt) |
| 849 | (setq count (length l1)) | 854 | count (length menu)) |
| 850 | (if (< count min) | 855 | (if (< count min) |
| 851 | (setq others (nconc l1 others)) | 856 | (setq others (nconc menu others)) |
| 852 | (recentf-set-menu-element-item | 857 | (recentf-set-menu-element-item |
| 853 | menu (format (recentf-menu-element-item menu) count)) | 858 | elt (format (recentf-menu-element-item elt) count)) |
| 854 | (recentf-set-menu-element-value | 859 | (recentf-set-menu-element-value |
| 855 | menu (recentf-apply-menu-filter | 860 | elt (recentf-apply-menu-filter |
| 856 | recentf-arrange-by-rule-subfilter (nreverse l1))) | 861 | recentf-arrange-by-rule-subfilter (nreverse menu))) |
| 857 | (push menu l2)))) | 862 | (push elt l))) |
| 858 | ;; Add the menu items remaining in the `others' bin. | 863 | ;; Add the menu items remaining in the `others' bin. |
| 859 | (if (and (stringp recentf-arrange-by-rule-others) others) | 864 | (when (setq others (nreverse others)) |
| 860 | (nreverse | 865 | (setq l (nconc |
| 861 | (cons | 866 | l |
| 862 | (recentf-make-menu-element | 867 | ;; Put items in an sub menu. |
| 863 | (format recentf-arrange-by-rule-others (length others)) | 868 | (if (stringp recentf-arrange-by-rule-others) |
| 864 | (recentf-apply-menu-filter | 869 | (list |
| 865 | recentf-arrange-by-rule-subfilter (nreverse others))) | 870 | (recentf-make-menu-element |
| 866 | l2)) | 871 | (format recentf-arrange-by-rule-others |
| 867 | (nconc | 872 | (length others)) |
| 868 | (nreverse l2) | 873 | (recentf-apply-menu-filter |
| 869 | (recentf-apply-menu-filter | 874 | recentf-arrange-by-rule-subfilter others))) |
| 870 | recentf-arrange-by-rule-subfilter (nreverse others))))))) | 875 | ;; Append items to the main menu. |
| 876 | (recentf-apply-menu-filter | ||
| 877 | recentf-arrange-by-rule-subfilter others))))))) | ||
| 878 | l) | ||
| 871 | 879 | ||
| 872 | ;;; Predefined rule based menu filters | 880 | ;;; Predefined rule based menu filters |
| 873 | ;; | 881 | ;; |
| 882 | (defun recentf-indirect-mode-rule (file) | ||
| 883 | "Apply a second level `auto-mode-alist' regexp to FILE." | ||
| 884 | (recentf-match-rule (substring file 0 (match-beginning 0)))) | ||
| 885 | |||
| 874 | (defun recentf-build-mode-rules () | 886 | (defun recentf-build-mode-rules () |
| 875 | "Convert `auto-mode-alist' to menu filter rules. | 887 | "Convert `auto-mode-alist' to menu filter rules. |
| 876 | Rules obey `recentf-arrange-rules' format." | 888 | Rules obey `recentf-arrange-rules' format." |
| @@ -886,7 +898,7 @@ Rules obey `recentf-arrange-rules' format." | |||
| 886 | ;; ignored by the menu filter. So in some corner cases a | 898 | ;; ignored by the menu filter. So in some corner cases a |
| 887 | ;; wrong mode could be guessed. | 899 | ;; wrong mode could be guessed. |
| 888 | ((and (consp mode) (cadr mode)) | 900 | ((and (consp mode) (cadr mode)) |
| 889 | (setq rule-name t)) | 901 | (setq rule-name 'recentf-indirect-mode-rule)) |
| 890 | ((and mode (symbolp mode)) | 902 | ((and mode (symbolp mode)) |
| 891 | (setq rule-name (symbol-name mode)) | 903 | (setq rule-name (symbol-name mode)) |
| 892 | (if (string-match "\\(.*\\)-mode$" rule-name) | 904 | (if (string-match "\\(.*\\)-mode$" rule-name) |
| @@ -906,21 +918,6 @@ Rules obey `recentf-arrange-rules' format." | |||
| 906 | (recentf-arrange-by-rule-others "others (%d)")) | 918 | (recentf-arrange-by-rule-others "others (%d)")) |
| 907 | (recentf-arrange-by-rule l))) | 919 | (recentf-arrange-by-rule l))) |
| 908 | 920 | ||
| 909 | (defun recentf-build-dir-rules (l) | ||
| 910 | "Convert directories in menu-elements L to menu filter rules. | ||
| 911 | Rules obey `recentf-arrange-rules' format." | ||
| 912 | (let (dirs) | ||
| 913 | (mapcar #'(lambda (e) | ||
| 914 | (let ((dir (file-name-directory | ||
| 915 | (recentf-menu-element-value e)))) | ||
| 916 | (or (recentf-string-member dir dirs) | ||
| 917 | (push dir dirs)))) | ||
| 918 | l) | ||
| 919 | (mapcar #'(lambda (d) | ||
| 920 | (cons (concat d " (%d)") | ||
| 921 | (concat "\\`" d))) | ||
| 922 | (nreverse (sort dirs 'recentf-string-lessp))))) | ||
| 923 | |||
| 924 | (defun recentf-file-name-nondir (l) | 921 | (defun recentf-file-name-nondir (l) |
| 925 | "Filter the list of menu-elements L to show filenames sans directory. | 922 | "Filter the list of menu-elements L to show filenames sans directory. |
| 926 | This simplified version of `recentf-show-basenames' does not handle | 923 | This simplified version of `recentf-show-basenames' does not handle |
| @@ -932,23 +929,27 @@ duplicates. It is used by `recentf-arrange-by-dir' as its | |||
| 932 | (recentf-menu-element-value e))) | 929 | (recentf-menu-element-value e))) |
| 933 | l)) | 930 | l)) |
| 934 | 931 | ||
| 932 | (defun recentf-dir-rule (file) | ||
| 933 | "Return as a sub-menu, the directory FILE belongs to." | ||
| 934 | (cons (file-name-directory file) file)) | ||
| 935 | |||
| 935 | (defun recentf-arrange-by-dir (l) | 936 | (defun recentf-arrange-by-dir (l) |
| 936 | "Split the list of menu-elements L into sub-menus by directory." | 937 | "Split the list of menu-elements L into sub-menus by directory." |
| 937 | (let ((recentf-arrange-rules (recentf-build-dir-rules l)) | 938 | (let ((recentf-arrange-rules '((recentf-dir-rule . ".*"))) |
| 938 | (recentf-arrange-by-rule-subfilter 'recentf-file-name-nondir) | 939 | (recentf-arrange-by-rule-subfilter 'recentf-file-name-nondir) |
| 939 | recentf-arrange-by-rule-others) | 940 | recentf-arrange-by-rule-others) |
| 940 | (nreverse (recentf-arrange-by-rule l)))) | 941 | (recentf-arrange-by-rule l))) |
| 941 | 942 | ||
| 942 | ;;; Ring of menu filters | 943 | ;;; Menu of menu filters |
| 943 | ;; | 944 | ;; |
| 944 | (defvar recentf-filter-changer-state nil | 945 | (defvar recentf-filter-changer-current nil |
| 945 | "Used by `recentf-filter-changer' to hold its state.") | 946 | "Current filter used by `recentf-filter-changer'.") |
| 946 | 947 | ||
| 947 | (defcustom recentf-filter-changer-alist | 948 | (defcustom recentf-filter-changer-alist |
| 948 | '( | 949 | '( |
| 949 | (recentf-arrange-by-mode . "*Files by Mode*") | 950 | (recentf-arrange-by-mode . "Grouped by Mode") |
| 950 | (recentf-arrange-by-dir . "*Files by Directory*") | 951 | (recentf-arrange-by-dir . "Grouped by Directory") |
| 951 | (recentf-arrange-by-rule . "*Files by User Rule*") | 952 | (recentf-arrange-by-rule . "Grouped by Custom Rules") |
| 952 | ) | 953 | ) |
| 953 | "*List of filters managed by `recentf-filter-changer'. | 954 | "*List of filters managed by `recentf-filter-changer'. |
| 954 | Each filter is defined by a pair (FUNCTION . LABEL), where FUNCTION is | 955 | Each filter is defined by a pair (FUNCTION . LABEL), where FUNCTION is |
| @@ -957,50 +958,38 @@ that filter." | |||
| 957 | :group 'recentf-filters | 958 | :group 'recentf-filters |
| 958 | :type '(repeat (cons function string)) | 959 | :type '(repeat (cons function string)) |
| 959 | :set (lambda (variable value) | 960 | :set (lambda (variable value) |
| 960 | (setq recentf-filter-changer-state nil) | 961 | (setq recentf-filter-changer-current nil) |
| 961 | (recentf-menu-customization-changed variable value))) | 962 | (set-default variable value))) |
| 962 | |||
| 963 | (defun recentf-filter-changer-goto-next () | ||
| 964 | "Go to the next filter available. | ||
| 965 | See `recentf-filter-changer'." | ||
| 966 | (setq recentf-filter-changer-state (cdr recentf-filter-changer-state)) | ||
| 967 | (recentf-clear-data)) | ||
| 968 | 963 | ||
| 969 | (defsubst recentf-filter-changer-get-current () | 964 | (defun recentf-filter-changer-select (filter) |
| 970 | "Get the current filter available. | 965 | "Select FILTER as the current menu filter. |
| 971 | See `recentf-filter-changer'." | 966 | See `recentf-filter-changer'." |
| 972 | (unless recentf-filter-changer-state | 967 | (setq recentf-filter-changer-current filter)) |
| 973 | (setq recentf-filter-changer-state recentf-filter-changer-alist)) | ||
| 974 | (car recentf-filter-changer-state)) | ||
| 975 | |||
| 976 | (defsubst recentf-filter-changer-get-next () | ||
| 977 | "Get the next filter available. | ||
| 978 | See `recentf-filter-changer'." | ||
| 979 | ;; At this point the current filter is the first element of | ||
| 980 | ;; `recentf-filter-changer-state'. | ||
| 981 | (car (or (cdr recentf-filter-changer-state) | ||
| 982 | ;; There is no next element in | ||
| 983 | ;; `recentf-filter-changer-state', so loop back to the | ||
| 984 | ;; first element of `recentf-filter-changer-alist'. | ||
| 985 | recentf-filter-changer-alist))) | ||
| 986 | 968 | ||
| 987 | (defun recentf-filter-changer (l) | 969 | (defun recentf-filter-changer (l) |
| 988 | "Manage a ring of menu filters. | 970 | "Manage a sub-menu of menu filters. |
| 989 | `recentf-filter-changer-alist' defines the filters in the ring. | 971 | `recentf-filter-changer-alist' defines the filters in the menu. |
| 990 | Filtering of L is delegated to the current filter in the ring. A | 972 | Filtering of L is delegated to the selected filter in the menu." |
| 991 | filter menu item is displayed allowing to dynamically activate the | 973 | (unless recentf-filter-changer-current |
| 992 | next filter in the ring. If the filter ring is empty, L is left | 974 | (setq recentf-filter-changer-current |
| 993 | unchanged." | 975 | (caar recentf-filter-changer-alist))) |
| 994 | (let ((filter (recentf-filter-changer-get-current))) | 976 | (if (not recentf-filter-changer-current) |
| 995 | (when filter | 977 | l |
| 996 | (setq l (recentf-apply-menu-filter (car filter) l) | 978 | (setq recentf-menu-filter-commands |
| 997 | filter (recentf-filter-changer-get-next)) | 979 | (list |
| 998 | (when filter | 980 | `("Show files" |
| 999 | (setq recentf-menu-filter-commands | 981 | ,@(mapcar |
| 1000 | (list (vector (cdr filter) | 982 | #'(lambda (f) |
| 1001 | '(recentf-filter-changer-goto-next) | 983 | `[,(cdr f) |
| 1002 | t))))) | 984 | (setq recentf-filter-changer-current ',(car f)) |
| 1003 | l)) | 985 | ;;:active t |
| 986 | :style radio ;;radio Don't work with GTK :-( | ||
| 987 | :selected (eq recentf-filter-changer-current | ||
| 988 | ',(car f)) | ||
| 989 | ;;:help ,(cdr f) | ||
| 990 | ]) | ||
| 991 | recentf-filter-changer-alist)))) | ||
| 992 | (recentf-apply-menu-filter recentf-filter-changer-current l))) | ||
| 1004 | 993 | ||
| 1005 | ;;; Hooks | 994 | ;;; Hooks |
| 1006 | ;; | 995 | ;; |
| @@ -1017,35 +1006,14 @@ That is, remove a non kept file from the recent list." | |||
| 1017 | (and buffer-file-name | 1006 | (and buffer-file-name |
| 1018 | (recentf-remove-if-non-kept buffer-file-name))) | 1007 | (recentf-remove-if-non-kept buffer-file-name))) |
| 1019 | 1008 | ||
| 1020 | (defun recentf-update-menu () | ||
| 1021 | "Update the recentf menu from the current recent list." | ||
| 1022 | (let ((cache (cons default-directory recentf-list))) | ||
| 1023 | ;; Does nothing, if nothing has changed. | ||
| 1024 | (unless (equal recentf-data-cache cache) | ||
| 1025 | (setq recentf-data-cache cache) | ||
| 1026 | (condition-case err | ||
| 1027 | (easy-menu-add-item | ||
| 1028 | (recentf-menu-bar) recentf-menu-path | ||
| 1029 | (easy-menu-create-menu recentf-menu-title | ||
| 1030 | (recentf-make-menu-items)) | ||
| 1031 | recentf-menu-before) | ||
| 1032 | (error | ||
| 1033 | (message "recentf update menu failed: %s" | ||
| 1034 | (error-message-string err))))))) | ||
| 1035 | |||
| 1036 | (defconst recentf-used-hooks | 1009 | (defconst recentf-used-hooks |
| 1037 | '( | 1010 | '( |
| 1038 | (find-file-hook recentf-track-opened-file) | 1011 | (find-file-hook recentf-track-opened-file) |
| 1039 | (write-file-functions recentf-track-opened-file) | 1012 | (write-file-functions recentf-track-opened-file) |
| 1040 | (kill-buffer-hook recentf-track-closed-file) | 1013 | (kill-buffer-hook recentf-track-closed-file) |
| 1041 | (menu-bar-update-hook recentf-update-menu) | ||
| 1042 | (kill-emacs-hook recentf-save-list) | 1014 | (kill-emacs-hook recentf-save-list) |
| 1043 | ) | 1015 | ) |
| 1044 | "Hooks used by recentf.") | 1016 | "Hooks used by recentf.") |
| 1045 | |||
| 1046 | (defsubst recentf-enabled-p () | ||
| 1047 | "Return non-nil if recentf mode is currently enabled." | ||
| 1048 | (memq 'recentf-update-menu menu-bar-update-hook)) | ||
| 1049 | 1017 | ||
| 1050 | ;;; Commands | 1018 | ;;; Commands |
| 1051 | ;; | 1019 | ;; |
| @@ -1126,8 +1094,7 @@ IGNORE arguments." | |||
| 1126 | (setq recentf-list (delq e recentf-list) | 1094 | (setq recentf-list (delq e recentf-list) |
| 1127 | i (1+ i))) | 1095 | i (1+ i))) |
| 1128 | (kill-buffer (current-buffer)) | 1096 | (kill-buffer (current-buffer)) |
| 1129 | (message "%S file(s) removed from the list" i) | 1097 | (message "%S file(s) removed from the list" i)) |
| 1130 | (recentf-clear-data)) | ||
| 1131 | (message "No file selected"))) | 1098 | (message "No file selected"))) |
| 1132 | 1099 | ||
| 1133 | (defun recentf-edit-list () | 1100 | (defun recentf-edit-list () |
| @@ -1292,7 +1259,7 @@ Write data into the file specified by `recentf-save-file'." | |||
| 1292 | (set-buffer-file-coding-system recentf-save-file-coding-system) | 1259 | (set-buffer-file-coding-system recentf-save-file-coding-system) |
| 1293 | (insert (format recentf-save-file-header (current-time-string))) | 1260 | (insert (format recentf-save-file-header (current-time-string))) |
| 1294 | (recentf-dump-variable 'recentf-list recentf-max-saved-items) | 1261 | (recentf-dump-variable 'recentf-list recentf-max-saved-items) |
| 1295 | (recentf-dump-variable 'recentf-filter-changer-state) | 1262 | (recentf-dump-variable 'recentf-filter-changer-current) |
| 1296 | (insert "\n\n;;; Local Variables:\n" | 1263 | (insert "\n\n;;; Local Variables:\n" |
| 1297 | (format ";;; coding: %s\n" recentf-save-file-coding-system) | 1264 | (format ";;; coding: %s\n" recentf-save-file-coding-system) |
| 1298 | ";;; End:\n") | 1265 | ";;; End:\n") |
| @@ -1354,10 +1321,12 @@ that were operated on recently. | |||
| 1354 | :keymap recentf-mode-map | 1321 | :keymap recentf-mode-map |
| 1355 | (unless (and recentf-mode (recentf-enabled-p)) | 1322 | (unless (and recentf-mode (recentf-enabled-p)) |
| 1356 | (if recentf-mode | 1323 | (if recentf-mode |
| 1357 | (recentf-load-list) | 1324 | (progn |
| 1325 | (recentf-load-list) | ||
| 1326 | (recentf-show-menu)) | ||
| 1327 | (recentf-hide-menu) | ||
| 1358 | (recentf-save-list)) | 1328 | (recentf-save-list)) |
| 1359 | (recentf-auto-cleanup) | 1329 | (recentf-auto-cleanup) |
| 1360 | (recentf-clear-data) | ||
| 1361 | (let ((hook-setup (if recentf-mode 'add-hook 'remove-hook))) | 1330 | (let ((hook-setup (if recentf-mode 'add-hook 'remove-hook))) |
| 1362 | (dolist (hook recentf-used-hooks) | 1331 | (dolist (hook recentf-used-hooks) |
| 1363 | (apply hook-setup hook))) | 1332 | (apply hook-setup hook))) |