Subject: bug#39512: 28.0.50; Add command isearch-yank-region

From: Tino Calancha <[email-masked]>
Date: Sun, 09 Feb 2020 13:38:14 +0100

Juri Linkov <[email-masked]> writes:

>> such a functionality was also missing.  This is consistent with
>> `isearch-yank-kill' (I think we should mention that in its docstring).
>
> Please add this useful feature of `isearch-yank-kill' to the documentation.
> Maybe it should be bound to a special key on the global `M-s' prefix map.
> The most natural key would be `M-s C-y'.
Done.  Added global binding `M-s C-y' for `isearch-yank-kill'.
Updated its docstring and the NEWS.

> (defun isearch-forward-region ()
>   "Do incremental search forward for text from the active region.
> Like ordinary incremental search except that text from the region
> is added to the search string initially if the region is active."
>   (interactive)
>   (isearch-forward nil 1)
>   (cond
>    ((use-region-p)
>     (when (< (mark) (point))
>       (exchange-point-and-mark))
>     (isearch-yank-string
>      (buffer-substring-no-properties (region-beginning) (region-end)))
>     (deactivate-mark))
>    (t
>     (setq isearch-error "No active region")
>     (isearch-push-state)
>     (isearch-update))))
I got inspired by your function; I took you default case in the
`cond' to not exit the interactive search, as I was doing.

I have added global keybinding `M-s M-.' for my `isearch-yank-region'.
This naturally open the following question.

`isearch-yank-kill' and `isearch-yank-region' are good names for the
use case of calling them once we are in an interactive search.

The names are not any good for the use case of calling them directly
(from a global keybinding).  We might want:

1. aliases `isearch-forward-kill', `isearch-forward-region'

2. restrict the use of them for just inside the interactive search, and
   define the new commands (`isearch-forward-kill',`isearch-forward-region')
   as those calling `isearch-mode' at the beginning.

[might case a regression of Bug#21419.]

--8<-----------------------------cut here---------------start------------->8---
commit 9cfe28b2b9661ca5cb11b0a99649faad5d6cf708
Author: Tino Calancha <[email-masked]>
Date:   Sun Feb 9 13:19:51 2020 +0100

    Add command isearch-yank-region
    
    Right after start an interactive search, set the search string
    equal to the active region; this is analogous to other
    'isearch-yank-...' commands.
    
    Calling the command out of an interactive search, then it starts
    an interactive search with the region as the search string.  This
    is consistent with `isearch-yank-kill'.
    
    * lisp/isearch.el (isearch-yank-region): New command; bound to 'M-.'
    in isearch-mode-map.  Bind it globally to 'M-s M-.'.
    (isearch-yank-kill): Update dosctring.  Bind this command globally
    to 'M-s C-y'.
    
    * doc/emacs/search.texi (Isearch Yank): Document these changes.
    * etc/NEWS: Announce these changes.

diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi
index 16916617a2..07a40c18cf 100644
--- a/doc/emacs/search.texi
+++ b/doc/emacs/search.texi
@@ -250,6 +250,16 @@ Isearch Yank
 search string.  The commands described in this subsection let you do
 that conveniently.
 
+@kindex M-. @r{(Incremental search)}
+@kindex M-s M-.
+@findex isearch-yank-region
+  @kbd{M-.} (@code{isearch-yank-region}) sets the search string equal
+to the active region.  This is useful when you have selected a string
+that you now want to search for.  Then you can start the interactive
+search and use @kbd{M-.}.  Alternatively, you can use @kbd{M-s M-.}
+to start directly an interactive search with the region as the
+search string.
+
 @kindex C-w @r{(Incremental search)}
 @findex isearch-yank-word-or-char
   @kbd{C-w} (@code{isearch-yank-word-or-char}) appends the next
@@ -287,6 +297,7 @@ Isearch Yank
 
 @kindex C-y @r{(Incremental search)}
 @kindex M-y @r{(Incremental search)}
+@kindex M-s C-y
 @kindex mouse-2 @r{in the minibuffer (Incremental search)}
 @findex isearch-yank-kill
 @findex isearch-yank-pop
diff --git a/etc/NEWS b/etc/NEWS
index 55c1a47fbf..ecb8048ade 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -91,6 +91,14 @@ shows equivalent key bindings for all commands that have them.
 
 * Changes in Specialized Modes and Packages in Emacs 28.1
 
+** Search and Replace
+
++++
+*** New isearch bindings.
+'M-.' invokes new command 'isearch-yank-region', which yanks the selected
+region into the search string.  It's globally bound to 'M-s M-.'.
+'isearch-yank-kill' now is globally bound to 'M-s C-y'.
+
 ** Help
 
 +++
diff --git a/lisp/isearch.el b/lisp/isearch.el
index ddf9190dc6..c5ae96033d 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -514,6 +514,9 @@ isearch-menu-bar-yank-map
     (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-region]
+      '(menu-item "Active region" isearch-yank-region
+                  :help "Append active region to search string"))
     (define-key map [isearch-yank-until-char]
       '(menu-item "Until char..." isearch-yank-until-char
                   :help "Yank from point to specified character into search string"))
@@ -708,6 +711,7 @@ isearch-mode-map
     (define-key map "\M-\C-d" 'isearch-del-char)
     (define-key map "\M-\C-y" 'isearch-yank-char)
     (define-key map    "\C-y" 'isearch-yank-kill)
+    (define-key map    "\M-." 'isearch-yank-region)
     (define-key map "\M-\C-z" 'isearch-yank-until-char)
     (define-key map "\M-s\C-e" 'isearch-yank-line)
 
@@ -973,6 +977,8 @@ isearch--saved-overriding-local-map
 (defvar-local isearch-mode nil) ;; Name of the minor mode, if non-nil.
 
 (define-key global-map "\C-s" 'isearch-forward)
+(define-key global-map "\M-s\M-." 'isearch-yank-region)
+(define-key global-map "\M-s\C-y" 'isearch-yank-kill)
 (define-key esc-map "\C-s" 'isearch-forward-regexp)
 (define-key global-map "\C-r" 'isearch-backward)
 (define-key esc-map "\C-r" 'isearch-backward-regexp)
@@ -1007,6 +1013,7 @@ isearch-forward
 Type \\[isearch-yank-line] to yank rest of line onto end of search string\
  and search for it.
 Type \\[isearch-yank-kill] to yank the last string of killed text.
+Type \\[isearch-yank-region] to yank the active region.
 Type \\[isearch-yank-pop] to replace string just yanked into search prompt
  with string killed before it.
 Type \\[isearch-quote-char] to quote control character to search for it.
@@ -2468,11 +2475,28 @@ isearch-yank-string
    string (mapconcat 'isearch-text-char-description string "")))
 
 (defun isearch-yank-kill ()
-  "Pull string from kill ring into search string."
+  "Pull string from kill ring into search string.
+If called out of an incremental search, then start an incremental
+search with the last string of killed text as the search string."
   (interactive)
   (unless isearch-mode (isearch-mode t))
   (isearch-yank-string (current-kill 0)))
 
+(defun isearch-yank-region ()
+  "Pull region into search string.
+If called out of an incremental search, then start an incremental
+search with the region as the search string."
+  (interactive)
+  (unless isearch-mode (isearch-mode t))
+  (cond ((use-region-p)
+         (isearch-yank-string (funcall region-extract-function nil))
+         (deactivate-mark))
+        (t
+         (setq isearch-error "No active region")
+         (isearch-push-state)
+         (isearch-update))))
+
+
 (defun isearch-yank-pop ()
   "Replace just-yanked search string with previously killed string."
   (interactive)

--8<-----------------------------cut here---------------end--------------->8---