From c5855569efdcd5af20ea37609ece3f0eef9c4f3d Mon Sep 17 00:00:00 2001 From: Gregory Heytings Date: Fri, 8 Apr 2021 22:30:07 +0000 Subject: [PATCH] New user option to scroll isearch matches * lisp/isearch.el (isearch-allow-match-scroll): New user option. (isearch-pre-command-hook): Handle the new option. * etc/NEWS: Mention the new user option. * doc/emacs/search.texi: Document the new user option. --- doc/emacs/search.texi | 22 ++++++++++++++++++++++ etc/NEWS | 10 ++++++++++ lisp/isearch.el | 41 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi index f3c42bcea7..59e2841611 100644 --- a/doc/emacs/search.texi +++ b/doc/emacs/search.texi @@ -587,6 +587,14 @@ Not Exiting Isearch an incremental search. This feature is disabled if @code{isearch-allow-scroll} is @code{nil} (which it is by default). +@vindex isearch-allow-match-scroll + Likewise, if you change the variable @code{isearch-allow-match-scroll} +to a non-@code{nil} value, this enables the use of the keyboard scrolling +commands @kbd{M-<}, @kbd{M->}, @kbd{C-v} and @kbd{M-v}, to move +respectively to the first occurrence of the current search string in +the buffer, the last one, the first one after the current window, +and the last one before the current window. + @item Motion Commands @cindex motion commands, during incremental search When @code{isearch-yank-on-move} is customized to @code{shift}, @@ -598,6 +606,20 @@ Not Exiting Isearch search string without using the shift key for cursor motion commands, but it applies only for certain motion command that have the @code{isearch-move} property on their symbols. + +@cindex motion commands, during incremental search, change + When @code{isearch-allow-match-scroll} is non-@code{nil}, it +is also possible to change the effect of motion commands during +incremental search, by modifying the @code{isearch-match-scroll} +property of their symbols. For example, to make @kbd{C-p} and +@kbd{C-n} move to the previous and next line and restart Isearch +forward and backward respectively, you can put the following +lines in your init file (@pxref{Init File}): + +@example +(put 'next-line 'isearch-match-scroll '(next-line . forward)) +(put 'previous-line 'isearch-match-scroll '(previous-line . backward)) +@end example @end table @node Isearch Minibuffer diff --git a/etc/NEWS b/etc/NEWS index d3a8748ded..4d4b2f48e1 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -367,6 +367,16 @@ trying to be non-destructive. This command opens a new buffer called "*Memory Report*" and gives a summary of where Emacs is using memory currently. ++++ +** New user option 'isearch-allow-match-scroll'. +When this option is set, the commands 'beginning-of-buffer', +'end-of-buffer', 'scroll-up-command' and 'scroll-down-command' move +respectively to the first occurrence of the current search string +in the buffer, the last one, the first one after the current window, +and the last one before the current window. Additionally, users can +change the meaning of other motion commands during Isearch by using +their 'isearch-match-scroll' property. + ** Outline +++ diff --git a/lisp/isearch.el b/lisp/isearch.el index 4b4f44bdff..ca3baf5eee 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -2866,12 +2866,37 @@ isearch-allow-scroll However, you cannot scroll far enough that the current match is no longer visible (is off screen). But if the value is `unlimited' that limitation is removed and you can scroll any distance off screen. -If nil, scrolling commands exit Isearch mode." +If nil, scrolling commands exit Isearch mode. +See also the related option `isearch-allow-match-scroll'." :type '(choice (const :tag "Scrolling exits Isearch" nil) (const :tag "Scrolling with current match on screen" t) (const :tag "Scrolling with current match off screen" unlimited)) :group 'isearch) +(put 'beginning-of-buffer 'isearch-match-scroll + '((lambda () (goto-char (point-min))) . forward)) +(put 'end-of-buffer 'isearch-match-scroll + '((lambda () (goto-char (point-max))) . backward)) +(put 'scroll-up-command 'isearch-match-scroll + '((lambda () (goto-char (window-end))) . forward)) +(put 'scroll-down-command 'isearch-match-scroll + '((lambda () (goto-char (window-start)) (recenter nil t)) . backward)) + +(put 'next-line 'isearch-match-scroll '(next-line . forward)) +(put 'previous-line 'isearch-match-scroll '(previous-line . backward)) + +(defcustom isearch-allow-match-scroll nil + "Whether scrolling to another match is allowed during incremental search. +If non-nil, the four scrolling commands `beginning-of-buffer', +`end-of-buffer', `scroll-up-command' and `scroll-down-command' move +respectively to the first first occurrence of the current search string in +the buffer, the last one, the first one after the current window, and the +last one before the current window. +See also the related option `isearch-allow-scroll'." + :type '(choice (const :tag "Off" nil) + (const :tag "On" t)) + :group 'isearch) + (defcustom isearch-allow-prefix t "Whether prefix arguments are allowed during incremental search. If non-nil, entering a prefix argument will not terminate the @@ -2973,6 +2998,20 @@ isearch-pre-command-hook ;; Optionally edit the search string instead of exiting. ((eq search-exit-option 'edit) (setq this-command 'isearch-edit-string)) + ;; Handle match scrolling functions. + ((and isearch-allow-match-scroll + (symbolp this-command) + (get this-command 'isearch-match-scroll)) + (let* ((property (get this-command 'isearch-match-scroll)) + (function (car property)) + (direction (or (cdr property) + (if isearch-forward 'forward 'backward)))) + (setq isearch-just-started t) + (condition-case nil + (funcall function) + (error nil)) + (isearch-repeat direction) + (setq this-command 'ignore))) ;; Handle a scrolling function or prefix argument. ((or (and isearch-allow-prefix (memq this-command '(universal-argument universal-argument-more -- 2.30.2