bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#32990: 26.1.50; isearch-forward + t-m-m/mark-active doc


From: Charles A. Roelli
Subject: bug#32990: 26.1.50; isearch-forward + t-m-m/mark-active doc
Date: Thu, 22 Nov 2018 21:29:25 +0100

> From: Juri Linkov <juri@linkov.net>
> Date: Thu, 22 Nov 2018 00:31:45 +0200
>
> Thanks, I tested your new version and have a few suggestions:
> 
> 1. There are two menu items with the same action word "Cancel":
> "Cancel search"
> "Cancel last input item"
> 
> This is confusing terminology.  I suggest to rename the latter to
> "Undo last input item"

Done, thanks.

> 2. Hard-coding command symbols with '(memq this-command ...' is
> not a good style.  

I've consolidated the list of commands into
'isearch-menu-bar-commands' (list of commands that can open a menu bar
during Isearch).  I also updated 'isearch-mouse-leave-buffer' to allow
commands listed in new var 'isearch-mouse-commands' (list of mouse
commands allowed during Isearch).

>                    Isearch provides a special feature to put the
> property 'isearch-scroll' (a misnomer, unfortunately) for the purpose
> to not hard-code command symbols.

'isearch-scroll' does not work on 'isearch-tmm-menubar' since
'isearch-tmm-menubar' runs arbitrary Isearch commands and can
therefore move point, which violates 'isearch-scroll's main
requirement.
 
> 3. Please add a comment to with-isearch-suspended stating that pushing
> a new state is not necessary for cases that don't change search
> parameters.  So that such commands that use with-isearch-suspended
> don't need special code to restore an old value of isearch-cmds.

Done, thanks.  I'm attaching the latest change again.



----
* 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'.

* 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.

----
diff --git a/lisp/isearch.el b/lisp/isearch.el
index b05805c..15f66ee 100644
--- a/lisp/isearch.el
+++ b/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 @@ 'isearch-mode-help
 
 ;; 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)))
@@ -595,9 +754,59 @@ isearch-mode-map
     ;; 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)
@@ -728,11 +937,19 @@ isearch--saved-overriding-local-map
 
 ;; 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)
@@ -986,6 +1203,10 @@ isearch-mode
        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.
@@ -1152,6 +1373,12 @@ isearch-done
       (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,
@@ -1184,9 +1411,17 @@ isearch-done
 
   (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)
@@ -1454,7 +1689,11 @@ with-isearch-suspended
 
        ;; 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
@@ -2540,7 +2779,12 @@ isearch-pre-command-hook
      ;; `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))
@@ -2604,7 +2848,8 @@ isearch-post-command-hook
         (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.
diff --git a/lisp/tmm.el b/lisp/tmm.el
index ff62774..4e3f254 100644
--- a/lisp/tmm.el
+++ b/lisp/tmm.el
@@ -42,6 +42,23 @@ tmm-km-list
 (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 @@ tmm-menubar
   (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 @@ tmm--completion-table
 (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 @@ tmm-prompt
 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 @@ tmm-prompt
           ;; 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 @@ tmm-prompt
           (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)))))





reply via email to

[Prev in Thread] Current Thread [Next in Thread]