From 166f6274b4118344612e60fba831e223728f3e89 Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Wed, 21 Nov 2018 01:43:21 +0200 Subject: [PATCH] Add prefix arg to isearch-repeat-forward/backward (bug#14563, bug#29321) * lisp/isearch.el (isearch-repeat): Add optional arg COUNT. Add a while-loop that calls `isearch-search' COUNT times. (isearch-repeat-forward, isearch-repeat-backward): Add optional prefix ARG passed down to `isearch-repeat'. Handle reversed directions. --- etc/NEWS | 5 +++ lisp/isearch.el | 81 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 1382b4d81e5..4ed312c7216 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -640,6 +640,11 @@ can now be searched via 'C-s'. ** Search and Replace +*** Isearch supports a prefix argument for 'C-s' ('isearch-repeat-forward') +and 'C-r' ('isearch-repeat-backward'). With a prefix argument, these +commands repeat the search for the specified occurrence of the search string. +A negative argument repeats the search in the opposite direction. + *** 'isearch-lazy-count' shows the current match number and total number of matches in the Isearch prompt. Customizable variables 'lazy-count-prefix-format' and 'lazy-count-suffix-format' define the diff --git a/lisp/isearch.el b/lisp/isearch.el index 87f4d495f4e..6d94ef66931 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -1555,8 +1555,8 @@ Use `isearch-exit' to quit without signaling." (isearch-pop-state)) (isearch-update))) -(defun isearch-repeat (direction) - ;; Utility for isearch-repeat-forward and -backward. +(defun isearch-repeat (direction &optional count) + ;; Utility for isearch-repeat-forward and isearch-repeat-backward. (if (eq isearch-forward (eq direction 'forward)) ;; C-s in forward or C-r in reverse. (if (equal isearch-string "") @@ -1587,32 +1587,67 @@ Use `isearch-exit' to quit without signaling." (if (equal isearch-string "") (setq isearch-success t) - (if (and isearch-success - (equal (point) isearch-other-end) - (not isearch-just-started)) - ;; If repeating a search that found - ;; an empty string, ensure we advance. - (if (if isearch-forward (eobp) (bobp)) - ;; If there's nowhere to advance to, fail (and wrap next time). - (progn - (setq isearch-success nil) - (ding)) - (forward-char (if isearch-forward 1 -1)) + ;; For the case when count > 1, don't keep intermediate states + ;; added to isearch-cmds by isearch-push-state in this loop. + (let ((isearch-cmds isearch-cmds)) + (while (<= 0 (setq count (1- (or count 1)))) + (if (and isearch-success + (equal (point) isearch-other-end) + (not isearch-just-started)) + ;; If repeating a search that found + ;; an empty string, ensure we advance. + (if (if isearch-forward (eobp) (bobp)) + ;; If there's nowhere to advance to, fail (and wrap next time). + (progn + (setq isearch-success nil) + (ding)) + (forward-char (if isearch-forward 1 -1)) + (isearch-search)) (isearch-search)) - (isearch-search))) + (when (> count 0) + ;; Update isearch-cmds, so if isearch-search fails later, + ;; it can restore old successful state from isearch-cmds. + (isearch-push-state)) + ;; Stop looping on failure. + (when (or (not isearch-success) isearch-error) + (setq count 0))))) (isearch-push-state) (isearch-update)) -(defun isearch-repeat-forward () - "Repeat incremental search forwards." - (interactive) - (isearch-repeat 'forward)) - -(defun isearch-repeat-backward () - "Repeat incremental search backwards." - (interactive) - (isearch-repeat 'backward)) +(defun isearch-repeat-forward (&optional arg) + "Repeat incremental search forwards. +With a prefix argument, repeat the search ARG times. +A negative argument searches backwards." + (interactive "P") + (if arg + (let ((count (prefix-numeric-value arg))) + (cond ((< count 0) + (isearch-repeat-backward (abs count)) + ;; Reverse the direction back + (isearch-repeat 'forward)) + (t + ;; Take into account one iteration to reverse direction + (when (not isearch-forward) (setq count (1+ count))) + (isearch-repeat 'forward count)))) + (isearch-repeat 'forward))) + +(defun isearch-repeat-backward (&optional arg) + "Repeat incremental search backwards. +With a prefix argument, repeat the search ARG times. +A negative argument searches forwards." + (interactive "P") + (if arg + (let ((count (prefix-numeric-value arg))) + (cond ((< count 0) + (isearch-repeat-forward (abs count)) + ;; Reverse the direction back + (isearch-repeat 'backward)) + (t + ;; Take into account one iteration to reverse direction + (when isearch-forward (setq count (1+ count))) + (isearch-repeat 'backward count)))) + (isearch-repeat 'backward))) ;;; Toggles for `isearch-regexp-function' and `search-default-mode'. -- 2.39.2