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

From: Ergus <[email-masked]>
Date: Mon, 10 Aug 2020 03:19:54 +0200

On Mon, Aug 10, 2020 at 02:23:59AM +0300, Juri Linkov wrote:
>>> Thanks for creating a new feature request that unlike these discussions
>>> on emacs-devel won't fall into oblivion.
>>
>> This was in February, though, and the patch still hasn't been applied.  :-/
>>
>> I think this addition makes sense...  was there any particular reason
>> it's not applied?
>
>I really don't see a need for adding isearch-yank-region.  I think that
>isearch-forward-region proposed by Ergus should be sufficient because
>typing 'M-s M-.' (bound globally to isearch-forward-region) even when
>isearch mode is active, will exit Isearch and restart Isearch with the
>contents of the still active region added to the search string.
>This will cover all cases requested here with just one new command:
>
>  (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))))
>
>  (define-key search-map "\M-." 'isearch-forward-region)

Hi Juri:

I didn't add this command to vanilla at the end because there were many
arguments about the bindings to use. And I consider that without a
default binding it is pretty much useless for the general user.

Now I am using swiper which has an improved version for thing-at-point
(something like `thing-at-point-or-region` called `ivy-thing-at-point`)
which actually is much more useful and avoids an extra binding.

https://github.com/abo-abo/swiper/blob/c6b60d34ac37bf4d91a25f16d22e528f85e06938/ivy.el#L426

Implementing something like that in vanilla is (in my opinion) the best
default behaviors for isearch-forward-symbol-at-point. But I don't want
to go in that discussion in the mailing list because it is difficult to
get an agreement what touching old commands. But you are free to do it
if you want.

Something more or less like this should work:

(defcustom isearch-thing-at-point-use-region nil
   "isearch-forward-symbol-at-point use region when active."
   :type 'boolean)

(defun bounds-thing-at-pt-or-region ()
   "Return current 'thing-at-point' or region bounds"
   (and (not (nth 3 (syntax-ppss)))  ;; global skip
        (cond
	((and isearch-thing-at-point-use-region
	      (region-active-p))
	 (let* ((beg (region-beginning))
		(end (region-end))
		(eol (save-excursion (goto-char beg) (line-end-position))))
	   (and (< beg end)      ;; no empty region
		(<= end eol)     ;; no multiline region
		(cons beg end))))
	((find-tag-default-bounds)))))

(defun isearch-forward-symbol-at-point (&optional arg)
   "Do incremental search forward for a symbol found near point.
Like ordinary incremental search except that the symbol found at point
is added to the search string initially as a regexp surrounded
by symbol boundary constructs \\_< and \\_>.
See the command `isearch-forward-symbol' for more information.
With a prefix argument, search for ARGth symbol forward if ARG is
positive, or search for ARGth symbol backward if ARG is negative."
   (interactive "P")
   (isearch-forward-symbol nil 1)
   (let ((bounds (bounds-thing-at-pt-or-region))
         (count (and arg (prefix-numeric-value arg))))
     (cond
      (bounds
       (when (< (car bounds) (point))
	(goto-char (car bounds)))
       (isearch-yank-string
        (buffer-substring-no-properties (car bounds) (cdr bounds)))
       (when count
         (isearch-repeat-forward count)))
      (t
       (if isearch-thing-at-point-use-region
           (setq isearch-error "No symbol at point or active region.")
         (setq isearch-error "No symbol at point"))
       (isearch-push-state)
       (isearch-update)))))

Best,
Ergus