Mercurial > emacs
comparison lisp/recentf.el @ 67417:29df8eb9daf1
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.
author | David Ponce <david@dponce.com> |
---|---|
date | Fri, 09 Dec 2005 08:16:04 +0000 |
parents | c4aae786a4e4 |
children | afb90762aa99 39bb10ce301a |
comparison
equal
deleted
inserted
replaced
67416:2336a32dc592 | 67417:29df8eb9daf1 |
---|---|
44 ;;; Internal data | 44 ;;; Internal data |
45 ;; | 45 ;; |
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 ;; |
55 (defgroup recentf nil | 55 (defgroup recentf nil |
56 "Maintain a menu of recently opened files." | 56 "Maintain a menu of recently opened files." |
109 :type '(repeat (choice regexp function))) | 109 :type '(repeat (choice regexp function))) |
110 | 110 |
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." |
121 :group 'recentf | 124 :group 'recentf |
122 :type 'string | 125 :type 'string |
140 | 143 |
141 (defcustom recentf-menu-action 'find-file | 144 (defcustom recentf-menu-action 'find-file |
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. |
156 A nil value means no filter. The following functions are predefined: | 157 A nil value means no filter. The following functions are predefined: |
157 | 158 |
180 - `recentf-arrange-by-mode' | 181 - `recentf-arrange-by-mode' |
181 Show a sub-menu for each major mode. | 182 Show a sub-menu for each major mode. |
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 |
189 elements (see `recentf-make-menu-element' for menu element form)." | 190 elements (see `recentf-make-menu-element' for menu element form)." |
190 :group 'recentf | 191 :group 'recentf |
201 (function-item recentf-relative-filter) | 202 (function-item recentf-relative-filter) |
202 (function-item recentf-arrange-by-rule) | 203 (function-item recentf-arrange-by-rule) |
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 |
224 "22.1") | 222 "22.1") |
225 | 223 |
329 When the value of VARIABLE is a list, optional argument LIMIT | 327 When the value of VARIABLE is a list, optional argument LIMIT |
330 specifies a maximum number of elements to insert. By default insert | 328 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)) |
338 (dolist (e value) | 336 (dolist (e value) |
339 (insert (format "\n %S" e))) | 337 (insert (format "\n %S" e))) |
574 l)) | 572 l)) |
575 | 573 |
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)) |
611 (if (string-equal name (nth i recentf-list)) | 614 (if (string-equal name (nth i recentf-list)) |
612 (progn | 615 (progn |
637 | 640 |
638 (defsubst recentf-menu-bar () | 641 (defsubst recentf-menu-bar () |
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 ;; |
651 (defsubst recentf-sort-ascending (l) | 659 (defsubst recentf-sort-ascending (l) |
652 "Sort the list of menu elements L in ascending order. | 660 "Sort the list of menu elements L in ascending order. |
748 | 756 |
749 ;;; Rule based menu filters | 757 ;;; Rule based menu filters |
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. |
769 This is for the menu where items that don't match any | 782 This is for the menu where items that don't match any |
770 `recentf-arrange-rules' are displayed. If nil these items are | 783 `recentf-arrange-rules' are displayed. If nil these items are |
771 displayed in the main recent files menu. A '%d' `format' pattern in | 784 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. |
780 If the number of items in a sub-menu is less than this value the | 792 If the number of items in a sub-menu is less than this value the |
781 corresponding sub-menu items are displayed in the main recent files | 793 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. |
790 A nil value means no filter. See also `recentf-menu-filter'. | 801 A nil value means no filter. See also `recentf-menu-filter'. |
791 You can't use another rule based filter here." | 802 You can't use another rule based filter here." |
794 :set (lambda (variable value) | 805 :set (lambda (variable value) |
795 (when (memq value '(recentf-arrange-by-rule | 806 (when (memq value '(recentf-arrange-by-rule |
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." |
877 (let ((case-fold-search recentf-case-fold-search) | 889 (let ((case-fold-search recentf-case-fold-search) |
878 regexp rule-name rule rules) | 890 regexp rule-name rule rules) |
884 ;; Build a special "strip suffix" rule from entries of the | 896 ;; Build a special "strip suffix" rule from entries of the |
885 ;; form (REGEXP FUNCTION NON-NIL). Notice that FUNCTION is | 897 ;; form (REGEXP FUNCTION NON-NIL). Notice that FUNCTION is |
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) |
893 (setq rule-name (match-string 1 rule-name))) | 905 (setq rule-name (match-string 1 rule-name))) |
894 (setq rule-name (concat rule-name " (%d)")))) | 906 (setq rule-name (concat rule-name " (%d)")))) |
904 "Split the list of menu-elements L into sub-menus by major mode." | 916 "Split the list of menu-elements L into sub-menus by major mode." |
905 (let ((recentf-arrange-rules (recentf-build-mode-rules)) | 917 (let ((recentf-arrange-rules (recentf-build-mode-rules)) |
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 |
927 duplicates. It is used by `recentf-arrange-by-dir' as its | 924 duplicates. It is used by `recentf-arrange-by-dir' as its |
928 `recentf-arrange-by-rule-subfilter'." | 925 `recentf-arrange-by-rule-subfilter'." |
930 (recentf-make-menu-element | 927 (recentf-make-menu-element |
931 (file-name-nondirectory (recentf-menu-element-value e)) | 928 (file-name-nondirectory (recentf-menu-element-value e)) |
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 |
955 the filter function, and LABEL is the menu item displayed to select | 956 the filter function, and LABEL is the menu item displayed to select |
956 that filter." | 957 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 |
963 (defun recentf-filter-changer-goto-next () | 964 (defun recentf-filter-changer-select (filter) |
964 "Go to the next filter available. | 965 "Select FILTER as the current menu filter. |
965 See `recentf-filter-changer'." | 966 See `recentf-filter-changer'." |
966 (setq recentf-filter-changer-state (cdr recentf-filter-changer-state)) | 967 (setq recentf-filter-changer-current filter)) |
967 (recentf-clear-data)) | |
968 | |
969 (defsubst recentf-filter-changer-get-current () | |
970 "Get the current filter available. | |
971 See `recentf-filter-changer'." | |
972 (unless recentf-filter-changer-state | |
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 ;; |
1007 (defun recentf-track-opened-file () | 996 (defun recentf-track-opened-file () |
1008 "Insert the name of the file just opened or written into the recent list." | 997 "Insert the name of the file just opened or written into the recent list." |
1015 "Update the recent list when a buffer is killed. | 1004 "Update the recent list when a buffer is killed. |
1016 That is, remove a non kept file from the recent list." | 1005 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 ;; |
1052 | 1020 |
1053 ;;; Common dialog stuff | 1021 ;;; Common dialog stuff |
1124 (let ((i 0)) | 1092 (let ((i 0)) |
1125 (dolist (e recentf-edit-list) | 1093 (dolist (e recentf-edit-list) |
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 () |
1134 "Show a dialog to delete selected files from the recent list." | 1101 "Show a dialog to delete selected files from the recent list." |
1135 (interactive) | 1102 (interactive) |
1290 (with-temp-buffer | 1257 (with-temp-buffer |
1291 (erase-buffer) | 1258 (erase-buffer) |
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") |
1299 (write-file (expand-file-name recentf-save-file)) | 1266 (write-file (expand-file-name recentf-save-file)) |
1300 (when recentf-save-file-modes | 1267 (when recentf-save-file-modes |
1352 :global t | 1319 :global t |
1353 :group 'recentf | 1320 :group 'recentf |
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))) |
1364 (run-hooks 'recentf-mode-hook) | 1333 (run-hooks 'recentf-mode-hook) |
1365 (when (interactive-p) | 1334 (when (interactive-p) |