From: "Drew Adams" <drew.adams@oracle.com>
To: "Emacs-Devel" <emacs-devel@gnu.org>
Subject: patch to imenu.el and lisp-mode.el for better menu in Lisp modes
Date: Sat, 14 Jul 2007 08:28:27 -0700 [thread overview]
Message-ID: <BDEIJAFNGDOAGCJIPKPBEEMFCFAA.drew.adams@oracle.com> (raw)
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'
next reply other threads:[~2007-07-14 15:28 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-07-14 15:28 Drew Adams [this message]
2007-07-14 19:51 ` patch to imenu.el and lisp-mode.el for better menu in Lisp modes Stefan Monnier
2007-07-14 22:54 ` Drew Adams
2007-07-14 22:33 ` Richard Stallman
2007-07-14 22:33 ` Richard Stallman
2007-07-14 23:02 ` Drew Adams
2007-07-15 22:54 ` Richard Stallman
2007-07-16 0:39 ` Drew Adams
2007-07-17 3:35 ` Richard Stallman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=BDEIJAFNGDOAGCJIPKPBEEMFCFAA.drew.adams@oracle.com \
--to=drew.adams@oracle.com \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.