summaryrefslogtreecommitdiff
path: root/lisp/isearch.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/isearch.el')
-rw-r--r--lisp/isearch.el162
1 files changed, 122 insertions, 40 deletions
diff --git a/lisp/isearch.el b/lisp/isearch.el
index 57b13a38d67..4fba4370d98 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -54,7 +54,6 @@
;;; Code:
(eval-when-compile (require 'cl-lib))
-(declare-function tmm-menubar-keymap "tmm.el")
;; Some additional options and constants.
@@ -269,6 +268,17 @@ are `word-search-regexp' \(`\\[isearch-toggle-word]'), `isearch-symbol-regexp'
"Non-nil means incremental search highlights the current match."
:type 'boolean)
+(defcustom search-highlight-submatches t
+ "Whether to highlight regexp subexpressions of the current regexp match.
+The faces used to do the highlights are named `isearch-group-1',
+`isearch-group-2', etc. (By default, only these 2 are defined.)
+When there are more matches than faces, then faces are reused from the
+beginning, in a cyclical manner, so the `isearch-group-1' face is
+isreused for the third match. If you want to use more distinctive colors,
+you can define more of these faces using the same numbering scheme."
+ :type 'boolean
+ :version "28.1")
+
(defface isearch
'((((class color) (min-colors 88) (background light))
;; The background must not be too dark, for that means
@@ -494,7 +504,7 @@ This is like `describe-bindings', but displays only Isearch keys."
(require 'tmm)
(run-hooks 'menu-bar-update-hook)
(let ((command nil))
- (let ((menu-bar (tmm-menubar-keymap)))
+ (let ((menu-bar (menu-bar-keymap)))
(with-isearch-suspended
(setq command (let ((isearch-mode t)) ; Show bindings from
; `isearch-mode-map' in
@@ -555,6 +565,10 @@ This is like `describe-bindings', but displays only Isearch keys."
:help "Highlight all matches for current search string"))
(define-key map [isearch-search-replace-separator]
'(menu-item "--"))
+ (define-key map [isearch-transient-input-method]
+ '(menu-item "Turn on transient input method"
+ isearch-transient-input-method
+ :help "Turn on transient input method for search"))
(define-key map [isearch-toggle-specified-input-method]
'(menu-item "Turn on specific input method"
isearch-toggle-specified-input-method
@@ -737,6 +751,7 @@ This is like `describe-bindings', but displays only Isearch keys."
;; For searching multilingual text.
(define-key map "\C-\\" 'isearch-toggle-input-method)
(define-key map "\C-^" 'isearch-toggle-specified-input-method)
+ (define-key map "\C-x\\" 'isearch-transient-input-method)
;; People expect to be able to paste with the mouse.
(define-key map [mouse-2] #'isearch-mouse-2)
@@ -880,7 +895,7 @@ variable by the command `isearch-toggle-lax-whitespace'.")
"Stack of search status elements.
Each element is an `isearch--state' struct where the slots are
[STRING MESSAGE POINT SUCCESS FORWARD OTHER-END WORD/REGEXP-FUNCTION
- ERROR WRAPPED BARRIER CASE-FOLD-SEARCH POP-FUN]")
+ ERROR WRAPPED BARRIER CASE-FOLD-SEARCH POP-FUN MATCH-DATA]")
(defvar isearch-string "") ; The current search string.
(defvar isearch-message "") ; text-char-description version of isearch-string
@@ -896,6 +911,7 @@ Each element is an `isearch--state' struct where the slots are
"Recorded minimum/maximal point for the current search.")
(defvar isearch-just-started nil)
(defvar isearch-start-hscroll 0) ; hscroll when starting the search.
+(defvar isearch-match-data nil) ; match-data of regexp-based search
;; case-fold-search while searching.
;; either nil, t, or 'yes. 'yes means the same as t except that mixed
@@ -1067,6 +1083,8 @@ To use a different input method for searching, type \
\\[isearch-toggle-specified-input-method],
and specify an input method you want to use.
+To activate a transient input method, type \\[isearch-transient-input-method].
+
The above keys, bound in `isearch-mode-map', are often controlled by
options; do \\[apropos] on search-.* to find them.
Other control and meta characters terminate the search
@@ -1214,6 +1232,7 @@ used to set the value of `isearch-regexp-function'."
isearch-small-window nil
isearch-just-started t
isearch-start-hscroll (window-hscroll)
+ isearch-match-data nil
isearch-opoint (point)
search-ring-yank-pointer nil
@@ -1342,8 +1361,8 @@ The last thing is to trigger a new round of lazy highlighting."
(set-window-hscroll (selected-window) current-scroll))))
(if isearch-other-end
(if (< isearch-other-end (point)) ; isearch-forward?
- (isearch-highlight isearch-other-end (point))
- (isearch-highlight (point) isearch-other-end))
+ (isearch-highlight isearch-other-end (point) isearch-match-data)
+ (isearch-highlight (point) isearch-other-end isearch-match-data))
(isearch-dehighlight))))
(setq ;; quit-flag nil not for isearch-mode
isearch-adjusted nil
@@ -1501,7 +1520,8 @@ REGEXP if non-nil says use the regexp search ring."
(barrier isearch-barrier)
(case-fold-search isearch-case-fold-search)
(pop-fun (if isearch-push-state-function
- (funcall isearch-push-state-function))))))
+ (funcall isearch-push-state-function)))
+ (match-data isearch-match-data))))
(string nil :read-only t)
(message nil :read-only t)
(point nil :read-only t)
@@ -1513,7 +1533,8 @@ REGEXP if non-nil says use the regexp search ring."
(wrapped nil :read-only t)
(barrier nil :read-only t)
(case-fold-search nil :read-only t)
- (pop-fun nil :read-only t))
+ (pop-fun nil :read-only t)
+ (match-data nil :read-only t))
(defun isearch--set-state (cmd)
(setq isearch-string (isearch--state-string cmd)
@@ -1525,7 +1546,8 @@ REGEXP if non-nil says use the regexp search ring."
isearch-error (isearch--state-error cmd)
isearch-wrapped (isearch--state-wrapped cmd)
isearch-barrier (isearch--state-barrier cmd)
- isearch-case-fold-search (isearch--state-case-fold-search cmd))
+ isearch-case-fold-search (isearch--state-case-fold-search cmd)
+ isearch-match-data (isearch--state-match-data cmd))
(if (functionp (isearch--state-pop-fun cmd))
(funcall (isearch--state-pop-fun cmd) cmd))
(goto-char (isearch--state-point cmd)))
@@ -1617,6 +1639,7 @@ You can update the global isearch variables by setting new values to
(isearch-adjusted isearch-adjusted)
(isearch-yank-flag isearch-yank-flag)
(isearch-error isearch-error)
+ (isearch-match-data isearch-match-data)
(multi-isearch-file-list-new multi-isearch-file-list)
(multi-isearch-buffer-list-new multi-isearch-buffer-list)
@@ -2011,15 +2034,16 @@ Turning on character-folding turns off regexp mode.")
(defvar isearch-message-properties minibuffer-prompt-properties
"Text properties that are added to the isearch prompt.")
-(defun isearch--momentary-message (string)
- "Print STRING at the end of the isearch prompt for 1 second."
+(defun isearch--momentary-message (string &optional seconds)
+ "Print STRING at the end of the isearch prompt for 1 second.
+The optional argument SECONDS overrides the number of seconds."
(let ((message-log-max nil))
(message "%s%s%s"
(isearch-message-prefix nil isearch-nonincremental)
isearch-message
(apply #'propertize (format " [%s]" string)
isearch-message-properties)))
- (sit-for 1))
+ (sit-for (or seconds 1)))
(isearch-define-mode-toggle lax-whitespace " " nil
"In ordinary search, toggles the value of the variable
@@ -2336,7 +2360,7 @@ characters in that string."
(with-isearch-suspended
(setq regexp-collect
(read-regexp
- (format "Regexp to collect (default %s): " default)
+ (format-prompt "Regexp to collect" default)
default 'occur-collect-regexp-history)))
regexp-collect))
;; Otherwise normal occur takes numerical prefix argument.
@@ -2381,22 +2405,17 @@ respectively)."
(funcall isearch-regexp-function isearch-string))
(isearch-regexp-function (word-search-regexp isearch-string))
(isearch-regexp isearch-string)
- ((if (and (eq isearch-case-fold-search t)
- search-upper-case)
- (isearch-no-upper-case-p
- isearch-string isearch-regexp)
- isearch-case-fold-search)
- ;; Turn isearch-string into a case-insensitive
- ;; regexp.
- (mapconcat
- (lambda (c)
- (let ((s (string c)))
- (if (string-match "[[:alpha:]]" s)
- (format "[%s%s]" (upcase s) (downcase s))
- (regexp-quote s))))
- isearch-string ""))
(t (regexp-quote isearch-string)))))
- (funcall hi-lock-func regexp (hi-lock-read-face-name)))
+ (let ((case-fold-search isearch-case-fold-search)
+ ;; Set `search-upper-case' to nil to not call
+ ;; `isearch-no-upper-case-p' in `hi-lock'.
+ (search-upper-case nil)
+ (search-spaces-regexp
+ (if (if isearch-regexp
+ isearch-regexp-lax-whitespace
+ isearch-lax-whitespace)
+ search-whitespace-regexp)))
+ (funcall hi-lock-func regexp (hi-lock-read-face-name) isearch-string)))
(and isearch-recursive-edit (exit-recursive-edit)))
(defun isearch-highlight-regexp ()
@@ -2404,14 +2423,18 @@ respectively)."
The arguments passed to `highlight-regexp' are the regexp from
the last search and the face from `hi-lock-read-face-name'."
(interactive)
- (isearch--highlight-regexp-or-lines 'highlight-regexp))
+ (isearch--highlight-regexp-or-lines
+ #'(lambda (regexp face lighter)
+ (highlight-regexp regexp face nil lighter))))
(defun isearch-highlight-lines-matching-regexp ()
"Exit Isearch mode and call `highlight-lines-matching-regexp'.
The arguments passed to `highlight-lines-matching-regexp' are the
regexp from the last search and the face from `hi-lock-read-face-name'."
(interactive)
- (isearch--highlight-regexp-or-lines 'highlight-lines-matching-regexp))
+ (isearch--highlight-regexp-or-lines
+ #'(lambda (regexp face _lighter)
+ (highlight-lines-matching-regexp regexp face))))
(defun isearch-delete-char ()
@@ -2518,6 +2541,8 @@ is bound to outside of Isearch."
(let ((pasted-text (nth 1 event)))
(isearch-yank-string pasted-text))))
+(defvar isearch--yank-prev-point nil)
+
(defun isearch-yank-internal (jumpform)
"Pull the text from point to the point reached by JUMPFORM.
JUMPFORM is a lambda expression that takes no arguments and returns
@@ -2528,7 +2553,14 @@ or it might return the position of the end of the line."
(save-excursion
(and (not isearch-forward) isearch-other-end
(goto-char isearch-other-end))
- (buffer-substring-no-properties (point) (funcall jumpform)))))
+ (and (not isearch-success) isearch--yank-prev-point
+ (goto-char isearch--yank-prev-point))
+ (buffer-substring-no-properties
+ (point)
+ (prog1
+ (setq isearch--yank-prev-point (funcall jumpform))
+ (when isearch-success
+ (setq isearch--yank-prev-point nil)))))))
(defun isearch-yank-char-in-minibuffer (&optional arg)
"Pull next character from buffer into end of search string in minibuffer."
@@ -3237,6 +3269,8 @@ the word mode."
(< (point) isearch-opoint)))
"over")
(if isearch-wrapped "wrapped ")
+ (if (and (not isearch-success) (buffer-narrowed-p) widen-automatically)
+ "narrowed " "")
(if (and (not isearch-success) (not isearch-case-fold-search))
"case-sensitive ")
(let ((prefix ""))
@@ -3425,9 +3459,10 @@ Optional third argument, if t, means if fail just return nil (no error).
(match-beginning 0) (match-end 0)))
(setq retry nil)))
(setq isearch-just-started nil)
- (if isearch-success
- (setq isearch-other-end
- (if isearch-forward (match-beginning 0) (match-end 0)))))
+ (when isearch-success
+ (setq isearch-other-end
+ (if isearch-forward (match-beginning 0) (match-end 0)))
+ (setq isearch-match-data (match-data t))))
(quit (isearch-unread ?\C-g)
(setq isearch-success nil))
@@ -3443,7 +3478,10 @@ Optional third argument, if t, means if fail just return nil (no error).
(string-match "\\`Regular expression too big" isearch-error))
(cond
(isearch-regexp-function
- (setq isearch-error "Too many words"))
+ (setq isearch-error nil)
+ (setq isearch-regexp-function nil)
+ (isearch-search-and-update)
+ (isearch--momentary-message "Too many words; switched to literal mode" 2))
((and isearch-lax-whitespace search-whitespace-regexp)
(setq isearch-error "Too many spaces for whitespace matching"))))))
@@ -3651,8 +3689,29 @@ since they have special meaning in a regexp."
;; Highlighting
(defvar isearch-overlay nil)
+(defvar isearch-submatches-overlays nil)
-(defun isearch-highlight (beg end)
+(defface isearch-group-1
+ '((((class color) (min-colors 88) (background light))
+ (:background "#f000f0" :foreground "lightskyblue1"))
+ (((class color) (min-colors 88) (background dark))
+ (:background "palevioletred1" :foreground "brown4"))
+ (t (:inherit isearch)))
+ "Face for highlighting Isearch the odd group matches."
+ :group 'isearch
+ :version "28.1")
+
+(defface isearch-group-2
+ '((((class color) (min-colors 88) (background light))
+ (:background "#a000a0" :foreground "lightskyblue1"))
+ (((class color) (min-colors 88) (background dark))
+ (:background "palevioletred3" :foreground "brown4"))
+ (t (:inherit isearch)))
+ "Face for highlighting Isearch the even group matches."
+ :group 'isearch
+ :version "28.1")
+
+(defun isearch-highlight (beg end &optional match-data)
(if search-highlight
(if isearch-overlay
;; Overlay already exists, just move it.
@@ -3661,11 +3720,33 @@ since they have special meaning in a regexp."
(setq isearch-overlay (make-overlay beg end))
;; 1001 is higher than lazy's 1000 and ediff's 100+
(overlay-put isearch-overlay 'priority 1001)
- (overlay-put isearch-overlay 'face isearch-face))))
+ (overlay-put isearch-overlay 'face isearch-face)))
+
+ (when (and search-highlight-submatches
+ isearch-regexp)
+ (mapc 'delete-overlay isearch-submatches-overlays)
+ (setq isearch-submatches-overlays nil)
+ (let ((submatch-data (cddr (butlast match-data)))
+ (group 0)
+ ov face)
+ (while submatch-data
+ (setq group (1+ group))
+ (setq ov (make-overlay (pop submatch-data) (pop submatch-data))
+ face (intern-soft (format "isearch-group-%d" group)))
+ ;; Recycle faces from beginning.
+ (unless (facep face)
+ (setq group 1 face 'isearch-group-1))
+ (overlay-put ov 'face face)
+ (overlay-put ov 'priority 1002)
+ (push ov isearch-submatches-overlays)))))
(defun isearch-dehighlight ()
(when isearch-overlay
- (delete-overlay isearch-overlay)))
+ (delete-overlay isearch-overlay))
+ (when search-highlight-submatches
+ (mapc 'delete-overlay isearch-submatches-overlays)
+ (setq isearch-submatches-overlays nil)))
+
;; isearch-lazy-highlight feature
;; by Bob Glickstein <http://www.zanshin.com/~bobg/>
@@ -3866,9 +3947,10 @@ Attempt to do the search exactly the way the pending Isearch would."
(isearch-regexp-lax-whitespace
isearch-lazy-highlight-regexp-lax-whitespace)
(isearch-forward isearch-lazy-highlight-forward)
- ;; Match invisible text only when counting matches
- ;; and user can visit invisible matches
- (search-invisible (and isearch-lazy-count search-invisible t))
+ ;; Don't match invisible text unless it can be opened
+ ;; or when counting matches and user can visit hidden matches
+ (search-invisible (or (eq search-invisible 'open)
+ (and isearch-lazy-count search-invisible)))
(retry t)
(success nil))
;; Use a loop like in `isearch-search'.