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)