From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: "Drew Adams" Newsgroups: gmane.emacs.devel Subject: patch to imenu.el and lisp-mode.el for better menu in Lisp modes Date: Sat, 14 Jul 2007 08:28:27 -0700 Message-ID: NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit X-Trace: sea.gmane.org 1184427038 11670 80.91.229.12 (14 Jul 2007 15:30:38 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Sat, 14 Jul 2007 15:30:38 +0000 (UTC) To: "Emacs-Devel" Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat Jul 14 17:30:36 2007 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1I9jZn-0002KP-O3 for ged-emacs-devel@m.gmane.org; Sat, 14 Jul 2007 17:30:32 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1I9jZn-0002SB-1O for ged-emacs-devel@m.gmane.org; Sat, 14 Jul 2007 11:30:31 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1I9jZj-0002Q9-02 for emacs-devel@gnu.org; Sat, 14 Jul 2007 11:30:27 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1I9jZh-0002OE-E5 for emacs-devel@gnu.org; Sat, 14 Jul 2007 11:30:25 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1I9jZh-0002Nh-1h for emacs-devel@gnu.org; Sat, 14 Jul 2007 11:30:25 -0400 Original-Received: from agminet01.oracle.com ([141.146.126.228]) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1I9jZg-0008Mn-50 for emacs-devel@gnu.org; Sat, 14 Jul 2007 11:30:24 -0400 Original-Received: from agmgw1.us.oracle.com (agmgw1.us.oracle.com [152.68.180.212]) by agminet01.oracle.com (Switch-3.2.4/Switch-3.1.7) with ESMTP id l6EFTnY9002692 for ; Sat, 14 Jul 2007 10:29:49 -0500 Original-Received: from acsmt351.oracle.com (acsmt351.oracle.com [141.146.40.151]) by agmgw1.us.oracle.com (Switch-3.2.0/Switch-3.2.0) with ESMTP id l6EFTmw1023496 for ; Sat, 14 Jul 2007 09:29:48 -0600 Original-Received: from dhcp-amer-csvpn-gw1-141-144-64-122.vpn.oracle.com by acsmt350.oracle.com with ESMTP id 3040596081184426916; Sat, 14 Jul 2007 08:28:36 -0700 X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook IMO, Build 9.0.6604 (9.0.2911.0) Importance: Normal X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.3138 X-Brightmail-Tracker: AAAAAQAAAAI= X-Brightmail-Tracker: AAAAAQAAAAI= X-Whitelist: TRUE X-Whitelist: TRUE X-detected-kernel: Linux 2.4-2.6 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:74766 Archived-At: Below are patches to imenu.el and lisp-mode.el. They divide Lisp definitions in the Index imenu into submenus. For Emacs Lisp, the submenus are: `Faces', `User Options', (other) `Variables', `Functions', `Macros', `Keys', `Keys in Maps', and `Other', the last being a catch-all. For other Lisps, the submenus are: `Variables', `Functions', `Types', and `Other'. The essential changes are these: lisp-mode.el - 1. Factored `lisp-imenu-generic-expression' into submenus. 2. Added variables `lisp-imenu-var-defn-regexp', `lisp-imenu-fn-defn-regexp', `lisp-imenu-type-defn-regexp', `lisp-imenu-macro-defn-regexp', `lisp-imenu-other-defn-regexp', `emacs-lisp-imenu-face-defn-regexp', `emacs-lisp-imenu-option-defn-regexp', `emacs-lisp-imenu-key-defn-regexp1', `emacs-lisp-imenu-key-defn-regexp2', `emacs-lisp-imenu-generic-expression'. 3. In `emacs-lisp-mode', set `imenu-generic-expression' to `emacs-lisp-imenu-generic-expression'. imenu.el - 1. Added functions `imenu-toggle-sort' (with alias `toggle-imenu-sort') and `imenu--sort-submenu'. Added variable `imenu-last-sort-function'. 2. `imenu-sort-function': Changed default value from nil to `imenu--sort-by-name'. Mention `toggle-imenu-sort' in doc string. 3. `imenu-mouse-menu': Sort each submenu before, instead of after, splitting submenus. Mention TITLE arg in doc string. 4. `imenu-update-menubar': Sort each submenu before, instead of after, splitting submenus. Added doc string. Notes/questions: 1. Question: Isn't `imenu-generic-expression' in the wrong section of `imenu.el'? It is not a customizable variable, but it is in the `Customizable variables' section. 2. Note: `defgroup' definitions are indexed in both the `Faces' submenu and the `Options' submenu. I think this makes more sense than putting them in only one or the other or putting them in submenu `Other'. 3. To do: add toggling of sorting to the `Index' menu as a `*Toggle Sorting*' item, at the end with the `*Rescan*' item, for easy access. Would someone like to do this? ------------8<----------- lisp-mode.el patch ---------------- *** lisp-mode-CVS-2007-07-13.el Fri Jul 13 17:45:54 2007 --- lisp-mode-CVS-patched-2007-07-13.el Fri Jul 13 19:03:18 2007 *************** *** 88,129 **** (define-abbrev-table 'lisp-mode-abbrev-table ()) ! (defvar lisp-imenu-generic-expression ! (list ! (list nil (purecopy (concat "^\\s-*(" (eval-when-compile (regexp-opt ! '("defun" "defun*" "defsubst" "defmacro" ! "defadvice" "define-skeleton" ! "define-minor-mode" "define-global-minor-mode" ! "define-globalized-minor-mode" ! "define-derived-mode" "define-generic-mode" ! "define-compiler-macro" "define-modify-macro" ! "defsetf" "define-setf-expander" ! "define-method-combination" ! "defgeneric" "defmethod") t)) "\\s-+\\(\\(\\sw\\|\\s_\\)+\\)")) ! 2) ! (list (purecopy "Variables") (purecopy (concat "^\\s-*(" (eval-when-compile ! (regexp-opt ! '("defvar" "defconst" "defconstant" "defcustom" ! "defparameter" "define-symbol-macro") t)) ! "\\s-+\\(\\(\\sw\\|\\s_\\)+\\)")) ! 2) ! (list (purecopy "Types") (purecopy (concat "^\\s-*(" (eval-when-compile (regexp-opt ! '("defgroup" "deftheme" "deftype" "defstruct" ! "defclass" "define-condition" "define-widget" ! "defface" "defpackage") t)) ! "\\s-+'?\\(\\(\\sw\\|\\s_\\)+\\)")) ! 2)) - "Imenu generic expression for Lisp mode. See `imenu-generic-expression'.") ;; This was originally in autoload.el and is still used there. (put 'autoload 'doc-string-elt 3) --- 88,184 ---- (define-abbrev-table 'lisp-mode-abbrev-table ()) ! (defvar lisp-imenu-other-defn-regexp (purecopy (concat "^\\s-*(" (eval-when-compile (regexp-opt ! '("define-condition" "define-widget" "defpackage" "deftheme") t)) "\\s-+\\(\\(\\sw\\|\\s_\\)+\\)")) ! "*Regexp that recognizes other (miscellaneous) Lisp definitions.") ! ! (defvar lisp-imenu-macro-defn-regexp ! (purecopy (concat "\\s-*(" ! (eval-when-compile ! (regexp-opt '("defmacro" "define-compiler-macro" "define-modify-macro" ! "define-symbol-macro") t)) ! "\\s-+\\([^ \t()]+\\)")) ! "*Regexp that recognizes Lisp macro definitions.") ! ! (defvar lisp-imenu-type-defn-regexp (purecopy (concat "^\\s-*(" (eval-when-compile ! (regexp-opt '("deftype" "defstruct" "defclass") t)) ! "\\s-+'?\\(\\(\\sw\\|\\s_\\)+\\)")) ! "*Regexp that recognizes Lisp type definitions.") ! ! (defvar lisp-imenu-fn-defn-regexp (purecopy (concat "^\\s-*(" (eval-when-compile (regexp-opt ! '("defun" "defun*" "defsubst" "defadvice" "define-skeleton" ! "define-minor-mode" "define-global-minor-mode" "define-derived-mode" ! "define-generic-mode" "defsetf" "define-setf-expander" ! "define-method-combination" "defgeneric" "defmethod") t)) ! "\\s-+\\(\\sw\\(\\sw\\|\\s_\\)+\\)")) ! "*Regexp that recognizes Lisp function definitions.") ! ! (defvar lisp-imenu-var-defn-regexp ! (purecopy (concat "^\\s-*(" ! (eval-when-compile ! (regexp-opt '("defvar" "defconst" "defconstant" "defparameter") t)) ! "\\s-+\\(\\(\\sw\\|\\s_\\)+\\)")) ! "*Regexp that recognizes global Lisp variable definitions. ! This does not include user options (defcustom).") ! ! (defvar lisp-imenu-generic-expression ! (list ! (list (purecopy "Other") lisp-imenu-other-defn-regexp 2) ! (list (purecopy "Macros") lisp-imenu-macro-defn-regexp 2) ! (list (purecopy "Types") lisp-imenu-type-defn-regexp 2) ! (list (purecopy "Functions") lisp-imenu-fn-defn-regexp 2) ! (list (purecopy "Variables") lisp-imenu-var-defn-regexp 2) ! ) ! "*Imenu generic expression for Lisp mode. ! See `imenu-generic-expression'.") ! ! (defvar emacs-lisp-imenu-key-defn-regexp-1 ! (purecopy (concat "\\s-*(" ! (eval-when-compile ! (regexp-opt '("global-set-key" "local-set-key" "global-unset-key" ! "local-unset-key" "undefine-keys-bound-to") t)) ! "\\s-*\\(\"[^\"]+\"\\|[[][^]]+[]]\\)")) ! "*Regexp that recognizes Emacs key definitions. ! See also `emacs-lisp-imenu-key-defn-regexp-2'.") ! ! (defvar emacs-lisp-imenu-key-defn-regexp-2 ! (purecopy "(\\s-*\\(define-key\\(-after\\)?\\s-+\\|substitute-key-definition\\s-+'\\)\ ! \\(\\S-+\\)\\s-*'?\\(\"[^\"]+\"\\|[[][^]]+[]]\\)") ! "*Regexp that recognizes Emacs key definitions in specific maps. ! See also `emacs-lisp-imenu-key-defn-regexp-1'.") ! ! (defvar emacs-lisp-imenu-face-defn-regexp ! (purecopy "(\\s-*\\(defface\\|defgroup\\)\\s-+\\([^ \t()]+\\)") ! "*Regexp for Emacs face definitions (defface).") ! ! (defvar emacs-lisp-imenu-option-defn-regexp ! (purecopy "(\\s-*\\(defcustom\\|defgroup\\)\\s-+\\([^ \t()]+\\)") ! "*Regexp for Emacs user option definitions (defcustom).") ! ! (defvar emacs-lisp-imenu-generic-expression ! (list ! (list "Other" lisp-imenu-other-defn-regexp 2) ! (list "Keys in Maps" emacs-lisp-imenu-key-defn-regexp-2 4) ! (list "Keys" emacs-lisp-imenu-key-defn-regexp-1 4) ! (list "Macros" lisp-imenu-macro-defn-regexp 2) ! (list "Functions" lisp-imenu-fn-defn-regexp 2) ! (list "Variables" lisp-imenu-var-defn-regexp 2) ! (list "User Options" emacs-lisp-imenu-option-defn-regexp 2) ! (list "Faces" emacs-lisp-imenu-face-defn-regexp 2) ! ) ! "*Imenu generic expression for Emacs Lisp mode. ! See `imenu-generic-expression'.") ! ;; This was originally in autoload.el and is still used there. (put 'autoload 'doc-string-elt 3) *************** *** 359,364 **** --- 414,421 ---- (setq major-mode 'emacs-lisp-mode) (setq mode-name "Emacs-Lisp") (lisp-mode-variables) + (make-local-variable 'imenu-generic-expression) + (setq imenu-generic-expression emacs-lisp-imenu-generic-expression) (setq imenu-case-fold-search nil) (run-mode-hooks 'emacs-lisp-mode-hook)) (put 'emacs-lisp-mode 'custom-mode-group 'lisp) ------------8<------------- imenu.el patch ------------------ *** imenu-CVS-2007-07-13.el Fri Jul 13 15:39:26 2007 --- imenu-CVS-patched-2007-07-13.el Fri Jul 13 19:19:46 2007 *************** *** 138,144 **** :group 'imenu) ;;;###autoload ! (defcustom imenu-sort-function nil "*The function to use for sorting the index mouse-menu. Affects only the mouse index menu. --- 138,144 ---- :group 'imenu) ;;;###autoload ! (defcustom imenu-sort-function 'imenu--sort-by-name "*The function to use for sorting the index mouse-menu. Affects only the mouse index menu. *************** *** 151,157 **** The function should take two arguments and return t if the first element should come before the second. The arguments are cons cells; ! \(NAME . POSITION). Look at `imenu--sort-by-name' for an example." :type '(choice (const :tag "No sorting" nil) (const :tag "Sort by name" imenu--sort-by-name) (function :tag "Another function")) --- 151,160 ---- The function should take two arguments and return t if the first element should come before the second. The arguments are cons cells; ! \(NAME . POSITION). Look at `imenu--sort-by-name' for an example. ! ! You can toggle this value (without saving it) at any time, using ! command `toggle-imenu-sort'." :type '(choice (const :tag "No sorting" nil) (const :tag "Sort by name" imenu--sort-by-name) (function :tag "Another function")) *************** *** 188,193 **** --- 191,197 ---- :type 'string :group 'imenu) + ;; Why does this belong here? It's not a customizable variable. ;;;###autoload (defvar imenu-generic-expression nil "The regex pattern to use for creating a buffer index. *************** *** 263,269 **** ;;;###autoload (make-variable-buffer-local 'imenu-default-goto-function) - (defun imenu--subalist-p (item) (and (consp (cdr item)) (listp (cadr item)) (not (eq (car (cadr item)) 'lambda)))) --- 267,272 ---- *************** *** 420,425 **** --- 423,431 ---- ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (defvar imenu-last-sort-function nil + "The last non-nil value for `imenu-sort-function' during this session.") + ;; The item to use in the index for rescanning the buffer. (defconst imenu--rescan-item '("*Rescan*" . -99)) *************** *** 885,895 **** (defun imenu--mouse-menu (index-alist event &optional title) "Let the user select from a buffer index from a mouse menu. ! ! INDEX-ALIST is the buffer index and EVENT is a mouse event. ! ! Returns t for rescan and otherwise an element or subelement of INDEX-ALIST." ! (setq index-alist (imenu--split-submenus index-alist)) (let* ((menu (imenu--split-menu index-alist (or title (buffer-name)))) (map (imenu--create-keymap (car menu) (cdr (if (< 1 (length (cdr menu))) --- 891,906 ---- (defun imenu--mouse-menu (index-alist event &optional title) "Let the user select from a buffer index from a mouse menu. ! INDEX-ALIST is the buffer index. ! EVENT is a mouse event. ! TITLE is the menu title. ! Returns t for rescan, or else an element or subelement of INDEX-ALIST." ! (setq index-alist ! (imenu--split-submenus ! (if imenu-sort-function ! (mapcar (lambda (sm) (imenu--sort-submenu sm imenu-sort-function)) ! index-alist) ! index-alist))) (let* ((menu (imenu--split-menu index-alist (or title (buffer-name)))) (map (imenu--create-keymap (car menu) (cdr (if (< 1 (length (cdr menu))) *************** *** 897,902 **** --- 908,922 ---- (car (cdr menu))))))) (popup-menu map event))) + (defun imenu--sort-submenu (submenu predicate) + "Create an imenu SUBMENU, sorting with PREDICATE." + (let ((menu-name (car submenu)) + (menu-items (cdr submenu))) + (cons menu-name (if (and (consp menu-items) + (consp (cdr menu-items))) + (sort menu-items predicate) + menu-items)))) + (defun imenu-choose-buffer-index (&optional prompt alist) "Let the user select from a buffer index and return the chosen index. *************** *** 972,977 **** --- 992,998 ---- (make-variable-buffer-local 'imenu-menubar-modified-tick) (defun imenu-update-menubar () + "Update the imenu. Use as `menu-bar-update-hook'." (when (and (current-local-map) (keymapp (lookup-key (current-local-map) [menu-bar index])) (/= (buffer-chars-modified-tick) imenu-menubar-modified-tick)) *************** *** 982,990 **** (unless (equal index-alist imenu--last-menubar-index-alist) (let (menu menu1 old) (setq imenu--last-menubar-index-alist index-alist) ! (setq index-alist (imenu--split-submenus index-alist)) ! (setq menu (imenu--split-menu index-alist ! (buffer-name))) (setq menu1 (imenu--create-keymap (car menu) (cdr (if (< 1 (length (cdr menu))) menu --- 1003,1015 ---- (unless (equal index-alist imenu--last-menubar-index-alist) (let (menu menu1 old) (setq imenu--last-menubar-index-alist index-alist) ! (setq index-alist ! (imenu--split-submenus ! (if imenu-sort-function ! (mapcar (lambda (sm) (imenu--sort-submenu sm imenu-sort-function)) ! index-alist) ! index-alist))) ! (setq menu (imenu--split-menu index-alist (buffer-name))) (setq menu1 (imenu--create-keymap (car menu) (cdr (if (< 1 (length (cdr menu))) menu *************** *** 1020,1025 **** --- 1045,1069 ---- (goto-char position)) ;;;###autoload + (defalias 'toggle-imenu-sort 'imenu-toggle-sort) + (defun imenu-toggle-sort (force-p) + "Toggle imenu between sorting menus and not. + Non-nil prefix FORCE-P => Sort iff FORCE-P >= 0." + (interactive "P") + (cond (imenu-sort-function + (setq imenu-last-sort-function imenu-sort-function) ; Save it. + (when (or (null force-p) (<= (prefix-numeric-value force-p) 0)) + (setq imenu-sort-function nil))) ; Don't sort. + ((or (null force-p) (> (prefix-numeric-value force-p) 0)) ; Ask to sort + (if imenu-last-sort-function ; Sort using saved sort fn. + (setq imenu-sort-function imenu-last-sort-function) + (error "You first need to set `imenu-sort-function'")))) + (imenu--menubar-select imenu--rescan-item) + (if imenu-sort-function + (message "Imenus are now being sorted via `%s'." imenu-sort-function) + (message "Imenus are in buffer order (not sorted)."))) + + ;;;###autoload (defun imenu (index-item) "Jump to a place in the buffer chosen using a buffer menu or mouse menu. INDEX-ITEM specifies the position. See `imenu-choose-buffer-index'