forked from Github/emacs
Add tool-bar and menu-bar menu for Isearch (Bug#32990)
* etc/NEWS (Search and Replace): Mention this change. * lisp/isearch.el: Declare the new, non-autoloaded function 'tmm-menubar-keymap'. (isearch-tmm-menubar): New function. (isearch-menu-bar-commands): New variable. (isearch-menu-bar-yank-map, isearch-menu-bar-map): New variables. (isearch-mode-map): Define a menu-bar search menu and remap 'tmm-menubar' bindings to point to 'isearch-tmm-menubar'. (isearch-tool-bar-old-map): New variable. (isearch-tool-bar-image): New function. (isearch-tool-bar-map): New variable. (minor-mode-map-alist): Add an entry for Isearch so that 'isearch-menu-bar-map' shows during search. (isearch-mode, isearch-done): Save and restore possible buffer-local 'tool-bar-map' using 'isearch-tool-bar-old-map'. (iseacrh-mouse-commands): New variable. (isearch-mouse-leave-buffer): Allow commands in isearch-mouse-commands. (with-isearch-suspended): Only push changed states of Isearch after running the body argument of this macro. (isearch-pre-command-hook): Additionally allow bindings in 'isearch-tool-bar-map' to pass through, as well as commands in isearch-menu-bar-commands. (isearch-post-command-hook): Call 'force-mode-line-update' at its end to make sure the menu- and tool-bars are up-to-date. * lisp/tmm.el (tmm-menubar-keymap): New function factored out from 'tmm-menubar'. (tmm-menubar): Use 'tmm-menubar-keymap'. (tmm-prompt): New optional argument 'no-execute'.
This commit is contained in:
parent
4ef9bcd0ff
commit
57b14370cd
3 changed files with 278 additions and 22 deletions
3
etc/NEWS
3
etc/NEWS
|
|
@ -687,6 +687,9 @@ the shift key.
|
|||
*** Isearch now remembers the regexp-based search mode for words/symbols
|
||||
and case-sensitivity together with search strings in the search ring.
|
||||
|
||||
---
|
||||
*** Isearch now has its own tool-bar and menu-bar menu.
|
||||
|
||||
** Debugger
|
||||
|
||||
+++
|
||||
|
|
|
|||
255
lisp/isearch.el
255
lisp/isearch.el
|
|
@ -54,6 +54,7 @@
|
|||
;;; Code:
|
||||
|
||||
(eval-when-compile (require 'cl-lib))
|
||||
(declare-function tmm-menubar-keymap "tmm.el")
|
||||
|
||||
;; Some additional options and constants.
|
||||
|
||||
|
|
@ -489,6 +490,164 @@ This is like `describe-bindings', but displays only Isearch keys."
|
|||
|
||||
;; Define isearch-mode keymap.
|
||||
|
||||
(defun isearch-tmm-menubar ()
|
||||
"Run `tmm-menubar' while `isearch-mode' is enabled."
|
||||
(interactive)
|
||||
(require 'tmm)
|
||||
(run-hooks 'menu-bar-update-hook)
|
||||
(let ((command nil))
|
||||
(let ((menu-bar (tmm-menubar-keymap)))
|
||||
(with-isearch-suspended
|
||||
(setq command (let ((isearch-mode t)) ; Show bindings from
|
||||
; `isearch-mode-map' in
|
||||
; tmm's prompt.
|
||||
(tmm-prompt menu-bar nil nil t)))))
|
||||
(call-interactively command)))
|
||||
|
||||
(defvar isearch-menu-bar-commands
|
||||
'(isearch-tmm-menubar menu-bar-open mouse-minor-mode-menu)
|
||||
"List of commands that can open a menu during Isearch.")
|
||||
|
||||
(defvar isearch-menu-bar-yank-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map [isearch-yank-pop]
|
||||
'(menu-item "Previous kill" isearch-yank-pop
|
||||
:help "Replace previous yanked kill on search string"))
|
||||
(define-key map [isearch-yank-kill]
|
||||
'(menu-item "Current kill" isearch-yank-kill
|
||||
:help "Append current kill to search string"))
|
||||
(define-key map [isearch-yank-line]
|
||||
'(menu-item "Rest of line" isearch-yank-line
|
||||
:help "Yank the rest of the current line on search string"))
|
||||
(define-key map [isearch-yank-symbol-or-char]
|
||||
'(menu-item "Symbol/char"
|
||||
isearch-yank-symbol-or-char
|
||||
:help "Yank next symbol or char on search string"))
|
||||
(define-key map [isearch-yank-word-or-char]
|
||||
'(menu-item "Word/char"
|
||||
isearch-yank-word-or-char
|
||||
:help "Yank next word or char on search string"))
|
||||
(define-key map [isearch-yank-char]
|
||||
'(menu-item "Char" isearch-yank-char
|
||||
:help "Yank char at point on search string"))
|
||||
map))
|
||||
|
||||
(defvar isearch-menu-bar-map
|
||||
(let ((map (make-sparse-keymap "Isearch")))
|
||||
(define-key map [isearch-complete]
|
||||
'(menu-item "Complete current search string" isearch-complete
|
||||
:help "Complete current search string over search history"))
|
||||
(define-key map [isearch-complete-separator]
|
||||
'(menu-item "--"))
|
||||
(define-key map [isearch-query-replace-regexp]
|
||||
'(menu-item "Replace search string as regexp" isearch-query-replace-regexp
|
||||
:help "Replace matches for current search string as regexp"))
|
||||
(define-key map [isearch-query-replace]
|
||||
'(menu-item "Replace search string" isearch-query-replace
|
||||
:help "Replace matches for current search string"))
|
||||
(define-key map [isearch-occur]
|
||||
'(menu-item "Show all matches for search string" isearch-occur
|
||||
:help "Show all matches for current search string"))
|
||||
(define-key map [isearch-highlight-regexp]
|
||||
'(menu-item "Highlight all matches for search string"
|
||||
isearch-highlight-regexp
|
||||
:help "Highlight all matches for current search string"))
|
||||
(define-key map [isearch-search-replace-separator]
|
||||
'(menu-item "--"))
|
||||
(define-key map [isearch-toggle-specified-input-method]
|
||||
'(menu-item "Turn on specific input method"
|
||||
isearch-toggle-specified-input-method
|
||||
:help "Turn on specific input method for search"))
|
||||
(define-key map [isearch-toggle-input-method]
|
||||
'(menu-item "Toggle input method" isearch-toggle-input-method
|
||||
:help "Toggle input method for search"))
|
||||
(define-key map [isearch-input-method-separator]
|
||||
'(menu-item "--"))
|
||||
(define-key map [isearch-char-by-name]
|
||||
'(menu-item "Search for char by name" isearch-char-by-name
|
||||
:help "Search for character by name"))
|
||||
(define-key map [isearch-quote-char]
|
||||
'(menu-item "Search for literal char" isearch-quote-char
|
||||
:help "Search for literal char"))
|
||||
(define-key map [isearch-special-char-separator]
|
||||
'(menu-item "--"))
|
||||
(define-key map [isearch-toggle-word]
|
||||
'(menu-item "Word matching" isearch-toggle-word
|
||||
:help "Word matching"
|
||||
:button (:toggle
|
||||
. (eq isearch-regexp-function 'word-search-regexp))))
|
||||
(define-key map [isearch-toggle-symbol]
|
||||
'(menu-item "Symbol matching" isearch-toggle-symbol
|
||||
:help "Symbol matching"
|
||||
:button (:toggle
|
||||
. (eq isearch-regexp-function
|
||||
'isearch-symbol-regexp))))
|
||||
(define-key map [isearch-toggle-regexp]
|
||||
'(menu-item "Regexp matching" isearch-toggle-regexp
|
||||
:help "Regexp matching"
|
||||
:button (:toggle . isearch-regexp)))
|
||||
(define-key map [isearch-toggle-invisible]
|
||||
'(menu-item "Invisible text matching" isearch-toggle-invisible
|
||||
:help "Invisible text matching"
|
||||
:button (:toggle . isearch-invisible)))
|
||||
(define-key map [isearch-toggle-char-fold]
|
||||
'(menu-item "Character folding matching" isearch-toggle-char-fold
|
||||
:help "Character folding matching"
|
||||
:button (:toggle
|
||||
. (eq isearch-regexp-function
|
||||
'char-fold-to-regexp))))
|
||||
(define-key map [isearch-toggle-case-fold]
|
||||
'(menu-item "Case folding matching" isearch-toggle-case-fold
|
||||
:help "Case folding matching"
|
||||
:button (:toggle . isearch-case-fold-search)))
|
||||
(define-key map [isearch-toggle-lax-whitespace]
|
||||
'(menu-item "Lax whitespace matching" isearch-toggle-lax-whitespace
|
||||
:help "Lax whitespace matching"
|
||||
:button (:toggle . isearch-lax-whitespace)))
|
||||
(define-key map [isearch-toggle-separator]
|
||||
'(menu-item "--"))
|
||||
(define-key map [isearch-yank-menu]
|
||||
`(menu-item "Yank on search string" ,isearch-menu-bar-yank-map))
|
||||
(define-key map [isearch-edit-string]
|
||||
'(menu-item "Edit current search string" isearch-edit-string
|
||||
:help "Edit current search string"))
|
||||
(define-key map [isearch-ring-retreat]
|
||||
'(menu-item "Edit previous search string" isearch-ring-retreat
|
||||
:help "Edit previous search string in Isearch history"))
|
||||
(define-key map [isearch-ring-advance]
|
||||
'(menu-item "Edit next search string" isearch-ring-advance
|
||||
:help "Edit next search string in Isearch history"))
|
||||
(define-key map [isearch-del-char]
|
||||
'(menu-item "Delete last char from search string" isearch-del-char
|
||||
:help "Delete last character from search string"))
|
||||
(define-key map [isearch-delete-char]
|
||||
'(menu-item "Undo last input item" isearch-delete-char
|
||||
:help "Undo the effect of the last Isearch command"))
|
||||
(define-key map [isearch-repeat-backward]
|
||||
'(menu-item "Repeat search backward" isearch-repeat-backward
|
||||
:help "Repeat current search backward"))
|
||||
(define-key map [isearch-repeat-forward]
|
||||
'(menu-item "Repeat search forward" isearch-repeat-forward
|
||||
:help "Repeat current search forward"))
|
||||
(define-key map [isearch-nonincremental]
|
||||
'(menu-item "Nonincremental search" isearch-exit
|
||||
:help "Start nonincremental search"
|
||||
:visible (string-equal isearch-string "")))
|
||||
(define-key map [isearch-exit]
|
||||
'(menu-item "Finish search" isearch-exit
|
||||
:help "Finish search leaving point where it is"
|
||||
:visible (not (string-equal isearch-string ""))))
|
||||
(define-key map [isearch-abort]
|
||||
'(menu-item "Remove characters not found" isearch-abort
|
||||
:help "Quit current search"
|
||||
:visible (not isearch-success)))
|
||||
(define-key map [isearch-cancel]
|
||||
`(menu-item "Cancel search" isearch-cancel
|
||||
:help "Cancel current search and return to starting point"
|
||||
:filter ,(lambda (binding)
|
||||
(if isearch-success 'isearch-abort binding))))
|
||||
map))
|
||||
|
||||
(defvar isearch-mode-map
|
||||
(let ((i 0)
|
||||
(map (make-keymap)))
|
||||
|
|
@ -598,9 +757,59 @@ This is like `describe-bindings', but displays only Isearch keys."
|
|||
;; characters to the search string. See iso-transl.el.
|
||||
(define-key map "\C-x8\r" 'isearch-char-by-name)
|
||||
|
||||
(define-key map [menu-bar search-menu]
|
||||
(list 'menu-item "Isearch" isearch-menu-bar-map))
|
||||
(define-key map [remap tmm-menubar] 'isearch-tmm-menubar)
|
||||
|
||||
map)
|
||||
"Keymap for `isearch-mode'.")
|
||||
|
||||
(defvar isearch-tool-bar-old-map nil
|
||||
"Variable holding the old local value of `tool-bar-map', if any.")
|
||||
|
||||
(defun isearch-tool-bar-image (image-name)
|
||||
"Return an image specification for IMAGE-NAME."
|
||||
(eval (tool-bar--image-expression image-name)))
|
||||
|
||||
(defvar isearch-tool-bar-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map [isearch-describe-mode]
|
||||
(list 'menu-item "Help" 'isearch-describe-mode
|
||||
:help "Get help for Isearch"
|
||||
:image '(isearch-tool-bar-image "help")))
|
||||
(define-key map [isearch-occur]
|
||||
(list 'menu-item "Show hits" 'isearch-occur
|
||||
:help "Show each search hit"
|
||||
:image '(isearch-tool-bar-image "index")))
|
||||
(define-key map [isearch-query-replace]
|
||||
(list 'menu-item "Replace" 'isearch-query-replace
|
||||
:help "Replace search string"
|
||||
:image '(isearch-tool-bar-image "search-replace")))
|
||||
(define-key map [isearch-delete-char]
|
||||
(list 'menu-item "Undo" 'isearch-delete-char
|
||||
:help "Undo last input item"
|
||||
:image '(isearch-tool-bar-image "undo")))
|
||||
(define-key map [isearch-exit]
|
||||
(list 'menu-item "Finish" 'isearch-exit
|
||||
:help "Finish search leaving point where it is"
|
||||
:image '(isearch-tool-bar-image "exit")
|
||||
:visible '(not (string-equal isearch-string ""))))
|
||||
(define-key map [isearch-cancel]
|
||||
(list 'menu-item "Abort" 'isearch-cancel
|
||||
:help "Abort search"
|
||||
:image '(isearch-tool-bar-image "close")
|
||||
:filter (lambda (binding)
|
||||
(if isearch-success 'isearch-abort binding))))
|
||||
(define-key map [isearch-repeat-forward]
|
||||
(list 'menu-item "Repeat forward" 'isearch-repeat-forward
|
||||
:help "Repeat search forward"
|
||||
:image '(isearch-tool-bar-image "right-arrow")))
|
||||
(define-key map [isearch-repeat-backward]
|
||||
(list 'menu-item "Repeat backward" 'isearch-repeat-backward
|
||||
:help "Repeat search backward"
|
||||
:image '(isearch-tool-bar-image "left-arrow")))
|
||||
map))
|
||||
|
||||
(defvar minibuffer-local-isearch-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(set-keymap-parent map minibuffer-local-map)
|
||||
|
|
@ -731,11 +940,19 @@ Each element is an `isearch--state' struct where the slots are
|
|||
|
||||
;; Minor-mode-alist changes - kind of redundant with the
|
||||
;; echo area, but if isearching in multiple windows, it can be useful.
|
||||
;; Also, clicking the mode-line indicator pops up
|
||||
;; `isearch-menu-bar-map'.
|
||||
|
||||
(or (assq 'isearch-mode minor-mode-alist)
|
||||
(nconc minor-mode-alist
|
||||
(list '(isearch-mode isearch-mode))))
|
||||
|
||||
;; We add an entry for `isearch-mode' to `minor-mode-map-alist' so
|
||||
;; that `isearch-menu-bar-map' can show on the menu bar.
|
||||
(or (assq 'isearch-mode minor-mode-map-alist)
|
||||
(nconc minor-mode-map-alist
|
||||
(list (cons 'isearch-mode isearch-mode-map))))
|
||||
|
||||
(defvar-local isearch-mode nil) ;; Name of the minor mode, if non-nil.
|
||||
|
||||
(define-key global-map "\C-s" 'isearch-forward)
|
||||
|
|
@ -989,6 +1206,10 @@ used to set the value of `isearch-regexp-function'."
|
|||
isearch-original-minibuffer-message-timeout minibuffer-message-timeout
|
||||
minibuffer-message-timeout nil)
|
||||
|
||||
(if (local-variable-p 'tool-bar-map)
|
||||
(setq isearch-tool-bar-old-map tool-bar-map))
|
||||
(setq-local tool-bar-map isearch-tool-bar-map)
|
||||
|
||||
;; We must bypass input method while reading key. When a user type
|
||||
;; printable character, appropriate input method is turned on in
|
||||
;; minibuffer to read multibyte characters.
|
||||
|
|
@ -1155,6 +1376,12 @@ NOPUSH is t and EDIT is t."
|
|||
(setq input-method-function isearch-input-method-function)
|
||||
(kill-local-variable 'input-method-function))
|
||||
|
||||
(if isearch-tool-bar-old-map
|
||||
(progn
|
||||
(setq-local tool-bar-map isearch-tool-bar-old-map)
|
||||
(setq isearch-tool-bar-old-map nil))
|
||||
(kill-local-variable 'tool-bar-map))
|
||||
|
||||
(force-mode-line-update)
|
||||
|
||||
;; If we ended in the middle of some intangible text,
|
||||
|
|
@ -1187,9 +1414,17 @@ NOPUSH is t and EDIT is t."
|
|||
|
||||
(and (not edit) isearch-recursive-edit (exit-recursive-edit)))
|
||||
|
||||
(defvar isearch-mouse-commands '(mouse-minor-mode-menu)
|
||||
"List of mouse commands that are allowed during Isearch.")
|
||||
|
||||
(defun isearch-mouse-leave-buffer ()
|
||||
"Exit Isearch unless the mouse command is allowed in Isearch."
|
||||
(unless (eq (get this-command 'isearch-scroll) t)
|
||||
"Exit Isearch unless the mouse command is allowed in Isearch.
|
||||
|
||||
Mouse commands are allowed in Isearch if they have a non-nil
|
||||
`isearch-scroll' property or if they are listed in
|
||||
`isearch-mouse-commands'."
|
||||
(unless (or (memq this-command isearch-mouse-commands)
|
||||
(eq (get this-command 'isearch-scroll) t))
|
||||
(isearch-done)))
|
||||
|
||||
(defun isearch-update-ring (string &optional regexp)
|
||||
|
|
@ -1457,7 +1692,11 @@ You can update the global isearch variables by setting new values to
|
|||
|
||||
;; Reinvoke the pending search.
|
||||
(isearch-search)
|
||||
(isearch-push-state) ; this pushes the correct state
|
||||
;; If no code has changed the search parameters, then pushing
|
||||
;; a new state of Isearch should not be necessary.
|
||||
(unless (and isearch-cmds
|
||||
(equal (car isearch-cmds) (isearch--get-state)))
|
||||
(isearch-push-state)) ; this pushes the correct state
|
||||
(isearch-update)
|
||||
(if isearch-nonincremental
|
||||
(progn
|
||||
|
|
@ -2581,7 +2820,12 @@ See more for options in `search-exit-option'."
|
|||
;; `set-transient-map' thingy like `universal-argument--mode'.
|
||||
((not (eq overriding-terminal-local-map isearch--saved-overriding-local-map)))
|
||||
;; Don't exit Isearch for isearch key bindings.
|
||||
((commandp (lookup-key isearch-mode-map key nil)))
|
||||
((or (commandp (lookup-key isearch-mode-map key nil))
|
||||
(commandp
|
||||
(lookup-key
|
||||
`(keymap (tool-bar menu-item nil ,isearch-tool-bar-map)) key))))
|
||||
;; Allow key bindings that open a menubar.
|
||||
((memq this-command isearch-menu-bar-commands))
|
||||
;; Optionally edit the search string instead of exiting.
|
||||
((eq search-exit-option 'edit)
|
||||
(setq this-command 'isearch-edit-string))
|
||||
|
|
@ -2645,7 +2889,8 @@ See more for options in `search-exit-option'."
|
|||
(when isearch-forward
|
||||
(goto-char isearch-pre-move-point))
|
||||
(isearch-search-and-update)))
|
||||
(setq isearch-pre-move-point nil))))
|
||||
(setq isearch-pre-move-point nil)))
|
||||
(force-mode-line-update))
|
||||
|
||||
(defun isearch-quote-char (&optional count)
|
||||
"Quote special characters for incremental search.
|
||||
|
|
|
|||
42
lisp/tmm.el
42
lisp/tmm.el
|
|
@ -42,6 +42,23 @@
|
|||
(defvar tmm-next-shortcut-digit)
|
||||
(defvar tmm-table-undef)
|
||||
|
||||
(defun tmm-menubar-keymap ()
|
||||
"Return the current menu-bar keymap.
|
||||
|
||||
The ordering of the return value respects `menu-bar-final-items'."
|
||||
(let ((menu-bar '())
|
||||
(menu-end '()))
|
||||
(map-keymap
|
||||
(lambda (key binding)
|
||||
(push (cons key binding)
|
||||
;; If KEY is the name of an item that we want to put last,
|
||||
;; move it to the end.
|
||||
(if (memq key menu-bar-final-items)
|
||||
menu-end
|
||||
menu-bar)))
|
||||
(tmm-get-keybind [menu-bar]))
|
||||
`(keymap ,@(nreverse menu-bar) ,@(nreverse menu-end))))
|
||||
|
||||
;;;###autoload (define-key global-map "\M-`" 'tmm-menubar)
|
||||
;;;###autoload (define-key global-map [menu-bar mouse-1] 'tmm-menubar-mouse)
|
||||
|
||||
|
|
@ -58,19 +75,8 @@ to invoke `tmm-menubar' instead, customize the variable
|
|||
(interactive)
|
||||
(run-hooks 'menu-bar-update-hook)
|
||||
;; Obey menu-bar-final-items; put those items last.
|
||||
(let ((menu-bar '())
|
||||
(menu-end '())
|
||||
(let ((menu-bar (tmm-menubar-keymap))
|
||||
menu-bar-item)
|
||||
(map-keymap
|
||||
(lambda (key binding)
|
||||
(push (cons key binding)
|
||||
;; If KEY is the name of an item that we want to put last,
|
||||
;; move it to the end.
|
||||
(if (memq key menu-bar-final-items)
|
||||
menu-end
|
||||
menu-bar)))
|
||||
(tmm-get-keybind [menu-bar]))
|
||||
(setq menu-bar `(keymap ,@(nreverse menu-bar) ,@(nreverse menu-end)))
|
||||
(if x-position
|
||||
(let ((column 0)
|
||||
prev-key)
|
||||
|
|
@ -154,7 +160,7 @@ specify nil for this variable."
|
|||
(defvar tmm--history nil)
|
||||
|
||||
;;;###autoload
|
||||
(defun tmm-prompt (menu &optional in-popup default-item)
|
||||
(defun tmm-prompt (menu &optional in-popup default-item no-execute)
|
||||
"Text-mode emulation of calling the bindings in keymap.
|
||||
Creates a text-mode menu of possible choices. You can access the elements
|
||||
in the menu in two ways:
|
||||
|
|
@ -165,7 +171,9 @@ The last alternative is currently a hack, you cannot use mouse reliably.
|
|||
MENU is like the MENU argument to `x-popup-menu': either a
|
||||
keymap or an alist of alists.
|
||||
DEFAULT-ITEM, if non-nil, specifies an initial default choice.
|
||||
Its value should be an event that has a binding in MENU."
|
||||
Its value should be an event that has a binding in MENU.
|
||||
NO-EXECUTE, if non-nil, means to return the command the user selects
|
||||
instead of executing it."
|
||||
;; If the optional argument IN-POPUP is t,
|
||||
;; then MENU is an alist of elements of the form (STRING . VALUE).
|
||||
;; That is used for recursive calls only.
|
||||
|
|
@ -268,7 +276,7 @@ Its value should be an event that has a binding in MENU."
|
|||
;; We just did the inner level of a -popup menu.
|
||||
choice)
|
||||
;; We just did the outer level. Do the inner level now.
|
||||
(not-menu (tmm-prompt choice t))
|
||||
(not-menu (tmm-prompt choice t nil no-execute))
|
||||
;; We just handled a menu keymap and found another keymap.
|
||||
((keymapp choice)
|
||||
(if (symbolp choice)
|
||||
|
|
@ -276,11 +284,11 @@ Its value should be an event that has a binding in MENU."
|
|||
(condition-case nil
|
||||
(require 'mouse)
|
||||
(error nil))
|
||||
(tmm-prompt choice))
|
||||
(tmm-prompt choice nil nil no-execute))
|
||||
;; We just handled a menu keymap and found a command.
|
||||
(choice
|
||||
(if chosen-string
|
||||
(progn
|
||||
(if no-execute choice
|
||||
(setq last-command-event chosen-string)
|
||||
(call-interactively choice))
|
||||
choice)))))
|
||||
|
|
|
|||
Loading…
Reference in a new issue