New user options to move between isearch matches

* lisp/isearch.el (isearch-allow-motion,
isearch-motion-changes-direction): New user options.
(isearch-pre-command-hook): Handle the new options.

* etc/NEWS: Mention the new user options.

* doc/emacs/search.texi: Document the new user options.
This commit is contained in:
Gregory Heytings 2021-09-10 12:43:45 +02:00 committed by Lars Ingebrigtsen
parent 150ff9c157
commit f3cfd47898
3 changed files with 81 additions and 1 deletions

View file

@ -593,6 +593,19 @@ or the selected window and frame. The command must not itself attempt
an incremental search. This feature is disabled if
@code{isearch-allow-scroll} is @code{nil} (which it is by default).
@vindex isearch-allow-motion
@vindex isearch-motion-changes-direction
Likewise, if you change the variable @code{isearch-allow-motion}
to a non-@code{nil} value, this enables the use of the keyboard motion
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. The search direction
does not change when these motion commands are used, unless you change
the variable @code{isearch-motion-changes-direction} to a non-@code{nil}
value, in which case the search direction is forward after @kbd{M-<} and
@kbd{C-v}, and backward after @kbd{M->} and @kbd{M-v}.
@item Motion Commands
@cindex motion commands, during incremental search
When @code{isearch-yank-on-move} is customized to @code{shift},

View file

@ -1132,6 +1132,18 @@ keys, add the following to your init file:
Using it instead of 'read-char-choice' allows using 'C-x o'
to switch to the help window displayed after typing 'C-h'.
+++
** New user option 'isearch-allow-motion'.
When 'isearch-allow-motion' is set, the commands 'beginning-of-buffer',
'end-of-buffer', 'scroll-up-command' and 'scroll-down-command', when
invoked during I-search, 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 I-search by using their 'isearch-motion' property. The
option 'isearch-motion-changes-direction' controls whether the
direction of the search changes after a motion command.
** Outline
+++

View file

@ -2927,12 +2927,49 @@ If non-nil, scrolling commands can be used in Isearch mode.
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-motion'."
: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-motion
'((lambda () (goto-char (point-min))) . forward))
(put 'end-of-buffer 'isearch-motion
'((lambda () (goto-char (point-max))) . backward))
(put 'scroll-up-command 'isearch-motion
'((lambda () (goto-char (window-end)) (recenter 1 t)) . forward))
(put 'scroll-down-command 'isearch-motion
'((lambda () (goto-char (window-start)) (recenter -1 t)) . backward))
(defcustom isearch-allow-motion nil
"Whether to allow movement between isearch matches by cursor motion commands.
If non-nil, the four motion commands \\[beginning-of-buffer], \\[end-of-buffer], \
\\[scroll-up-command] and \\[scroll-down-command], when invoked during
Isearch, 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.
If nil, these motion commands normally exit Isearch and are executed.
See also the related options `isearch-motion-changes-direction' and
`isearch-allow-scroll'."
:type '(choice (const :tag "Off" nil)
(const :tag "On" t))
:group 'isearch
:version "28.1")
(defcustom isearch-motion-changes-direction nil
"Whether motion commands during incremental search change search direction.
If nil, the search direction (forward or backward) does not change when
motion commands are used during incremental search, except when wrapping.
If non-nil, the search direction is forward after \\[beginning-of-buffer] and \
\\[scroll-up-command], and
backward after \\[end-of-buffer] and \\[scroll-down-command]."
:type '(choice (const :tag "Off" nil)
(const :tag "On" t))
:group 'isearch
:version "28.1")
(defcustom isearch-allow-prefix t
"Whether prefix arguments are allowed during incremental search.
If non-nil, entering a prefix argument will not terminate the
@ -3034,6 +3071,24 @@ See more for options in `search-exit-option'."
;; Optionally edit the search string instead of exiting.
((eq search-exit-option 'edit)
(setq this-command 'isearch-edit-string))
;; Handle motion command functions.
((and isearch-allow-motion
(symbolp this-command)
(get this-command 'isearch-motion))
(let* ((property (get this-command 'isearch-motion))
(function (car property))
(current-direction (if isearch-forward 'forward 'backward))
(direction (or (cdr property)
(if isearch-forward 'forward 'backward))))
(funcall function)
(setq isearch-just-started t)
(let ((isearch-repeat-on-direction-change nil))
(isearch-repeat direction))
(when (and isearch-success (not isearch-motion-changes-direction))
(unless (eq direction current-direction)
(let ((isearch-repeat-on-direction-change nil))
(isearch-repeat current-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