changeset 56668:99e8e40ec202

Remove accidental changes of March 4. Fix backing up when a regexp isearch is made more general. Use symbolic accessor functions for isearch stack frames to make usage clearer. (search-whitespace-regexp): Made groups in documentation shy (as is the group in the default value). (isearch-fallback): New function, addresses problems with regexps liberalized by `\|', adds support for liberalization by `\}' (the general repetition construct), and incorporates behavior for `*'/`?'. (isearch-}-char): New command, calls `isearch-fallback' with arguments appropriate to a typed `}'. (isearch-*-char, isearch-|-char): Now just call `isearch-fallback' appropriately. (isearch-mode-map): Bind `}' to `isearch-}-char'. (isearch-string, isearch-message,string, isearch-point, isearch-success, isearch-forward-flag, isearch-other-end, isearch-word, isearch-invalid-regexp, isearch-wrapped, isearch-barrier, isearch-within-brackets, isearch-case-fold-search): New inline functions to read fields of a stack frame.
author Eli Zaretskii <eliz@gnu.org>
date Sat, 14 Aug 2004 12:48:39 +0000
parents 00e5170987b5
children 126be634e20a
files lisp/isearch.el
diffstat 1 files changed, 157 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/isearch.el	Sat Aug 14 12:47:42 2004 +0000
+++ b/lisp/isearch.el	Sat Aug 14 12:48:39 2004 +0000
@@ -153,9 +153,9 @@
 (defcustom search-whitespace-regexp "\\(?:\\s-+\\)"
   "*If non-nil, regular expression to match a sequence of whitespace chars.
 This applies to regular expression incremental search.
-You might want to use something like \"[ \\t\\r\\n]+\" instead.
-In the Customization buffer, that is `[' followed by a space,
-a tab, a carriage return (control-M), a newline, and `]+'."
+You might want to use something like \"\\\\(?:[ \\t\\r\\n]+\\\\)\" instead.
+In the Customization buffer, that is `\\(?:[' followed by a space,
+a tab, a carriage return (control-M), a newline, and `]+\\)'."
   :type 'regexp
   :group 'isearch)
 
@@ -298,11 +298,11 @@
     (define-key map "\M-\C-y" 'isearch-yank-char)
     (define-key map    "\C-y" 'isearch-yank-line)
 
-    ;; Define keys for regexp chars * ? |.
+    ;; Define keys for regexp chars * ? } |.
     ;; Nothing special for + because it matches at least once.
     (define-key map "*" 'isearch-*-char)
     (define-key map "?" 'isearch-*-char)
-    (define-key map "{" 'isearch-{-char)
+    (define-key map "}" 'isearch-}-char)
     (define-key map "|" 'isearch-|-char)
 
     ;; Turned off because I find I expect to get the global definition--rms.
@@ -372,9 +372,9 @@
 
 (defvar isearch-cmds nil
   "Stack of search status sets.
-Each set is a list of the form:
- (STRING MESSAGE POINT SUCCESS FORWARD OTHER-END WORD
-  INVALID-REGEXP WRAPPED BARRIER WITHIN-BRACKETS CASE-FOLD-SEARCH)")
+Each set is a vector of the form:
+ [STRING MESSAGE POINT SUCCESS FORWARD OTHER-END WORD
+  INVALID-REGEXP WRAPPED BARRIER WITHIN-BRACKETS CASE-FOLD-SEARCH]")
 
 (defvar isearch-string "")  ; The current search string.
 (defvar isearch-message "") ; text-char-description version of isearch-string
@@ -774,6 +774,74 @@
 ;;   (handle-switch-frame (car (cdr last-command-char))))
 
 
+;; The search status structure and stack.
+
+(defsubst isearch-string (frame)
+  "Return the search string in FRAME."
+  (aref 0 frame))
+(defsubst isearch-message-string (frame)
+  "Return the search string to display to the user in FRAME."
+  (aref 1 frame))
+(defsubst isearch-point (frame)
+  "Return the point in FRAME."
+  (aref 2 frame))
+(defsubst isearch-success (frame)
+  "Return the success flag in FRAME."
+  (aref 3 frame))
+(defsubst isearch-forward-flag (frame)
+  "Return the searching-forward flag in FRAME."
+  (aref 4 frame))
+(defsubst isearch-other-end (frame)
+  "Return the other end of the match in FRAME."
+  (aref 5 frame))
+(defsubst isearch-word (frame)
+  "Return the search-by-word flag in FRAME."
+  (aref 6 frame))
+(defsubst isearch-invalid-regexp (frame)
+  "Return the regexp error message in FRAME, or nil if its regexp is valid."
+  (aref 7 frame))
+(defsubst isearch-wrapped (frame)
+  "Return the search-wrapped flag in FRAME."
+  (aref 8 frame))
+(defsubst isearch-barrier (frame)
+  "Return the barrier value in FRAME."
+  (aref 9 frame))
+(defsubst isearch-within-brackets (frame)
+  "Return the in-character-class flag in FRAME."
+  (aref 10 frame))
+(defsubst isearch-case-fold-search (frame)
+  "Return the case-folding flag in FRAME."
+  (aref 11 frame))
+
+(defun isearch-top-state ()
+  (let ((cmd (car isearch-cmds)))
+    (setq isearch-string (isearch-string cmd)
+	  isearch-message (isearch-message-string cmd)
+	  isearch-success (isearch-success cmd)
+	  isearch-forward (isearch-forward-flag cmd)
+	  isearch-other-end (isearch-other-end cmd)
+	  isearch-word (isearch-word cmd)
+	  isearch-invalid-regexp (isearch-invalid-regexp cmd)
+	  isearch-wrapped (isearch-wrapped cmd)
+	  isearch-barrier (isearch-barrier cmd)
+	  isearch-within-brackets (isearch-within-brackets cmd)
+	  isearch-case-fold-search (isearch-case-fold-search cmd))
+    (goto-char (isearch-point cmd))))
+
+(defun isearch-pop-state ()
+  (setq isearch-cmds (cdr isearch-cmds))
+  (isearch-top-state))
+
+(defun isearch-push-state ()
+  (setq isearch-cmds
+	(cons (vector isearch-string isearch-message (point)
+		      isearch-success isearch-forward isearch-other-end
+		      isearch-word
+		      isearch-invalid-regexp isearch-wrapped isearch-barrier
+		      isearch-within-brackets isearch-case-fold-search)
+	      isearch-cmds)))
+
+
 ;; Commands active while inside of the isearch minor mode.
 
 (defun isearch-exit ()
@@ -1249,53 +1317,93 @@
   (isearch-update))
 
 
-(defun isearch-{-char ()
-  "Handle \{ specially in regexps."
-  (interactive)
-  (isearch-*-char t))
-
-;; *, ?, and | chars can make a regexp more liberal.
+;; *, ?, }, and | chars can make a regexp more liberal.
 ;; They can make a regexp match sooner or make it succeed instead of failing.
 ;; So go back to place last successful search started
 ;; or to the last ^S/^R (barrier), whichever is nearer.
 ;; + needs no special handling because the string must match at least once.
 
-(defun isearch-*-char (&optional want-backslash)
-  "Handle * and ? specially in regexps.
-When WANT-BACKSLASH is non-nil, do special handling for \{."
-  (interactive)
-  (if isearch-regexp
-      (let ((idx (length isearch-string)))
-	(while (and (> idx 0)
-		    (eq (aref isearch-string (1- idx)) ?\\))
-	  (setq idx (1- idx)))
-	;; * and ? are special when not preceded by \.
-	;; { is special when it is preceded by \.
-	(when (= (mod (- (length isearch-string) idx) 2)
-		 (if want-backslash 1 0))
-	  (setq isearch-adjusted t)
-	  ;; Get the isearch-other-end from before the last search.
-	  ;; We want to start from there,
-	  ;; so that we don't retreat farther than that.
-	  ;; (car isearch-cmds) is after last search;
-	  ;; (car (cdr isearch-cmds)) is from before it.
-	  (let ((cs (nth 5 (car (cdr isearch-cmds)))))
-	    (setq cs (or cs isearch-barrier))
-	    (goto-char
-	     (if isearch-forward
-		 (max cs isearch-barrier)
-	       (min cs isearch-barrier)))))))
+(defun isearch-backslash (str)
+  "Return t if STR ends in an odd number of backslashes."
+  (= (mod (- (length str) (string-match "\\\\*\\'" str)) 2) 1))
+
+(defun isearch-fallback (want-backslash &optional allow-invalid to-barrier)
+  "Return point to previous successful match to allow regexp liberalization.
+\\<isearch-mode-map>
+Respects \\[isearch-repeat-forward] and \\[isearch-repeat-backward] by
+stopping at `isearch-barrier' as needed.
+
+Do nothing if a backslash is escaping the liberalizing character.  If
+WANT-BACKSLASH is non-nil, invert this behavior (for \\} and \\|).
+
+Do nothing if regexp has recently been invalid unless optional ALLOW-INVALID
+non-nil.
+
+If optional TO-BARRIER non-nil, ignore previous matches and go exactly to the
+barrier."
+  ;; (eq (not a) (not b)) makes all non-nil values equivalent
+  (when (and isearch-regexp (eq (not (isearch-backslash isearch-string))
+				(not want-backslash))
+	     ;; We have to check 2 stack frames because the last might be
+	     ;; invalid just because of a backslash.
+	     (or (not isearch-invalid-regexp)
+		 (not (isearch-invalid-regexp (cadr isearch-cmds)))
+		 allow-invalid))
+    (if to-barrier
+	(progn (goto-char isearch-barrier)
+	       (setq isearch-adjusted t))
+      (let* ((stack isearch-cmds)
+	     (previous (cdr stack))	; lookbelow in the stack
+	     (frame (car stack)))
+	;; Walk down the stack looking for a valid regexp (as of course only
+	;; they can be the previous successful match); this conveniently
+	;; removes all bracket-sets and groups that might be in the way, as
+	;; well as partial \{\} constructs that the code below leaves behind.
+	;; Also skip over postfix operators -- though horrid,
+	;; 'ab?\{5,6\}+\{1,2\}*' is perfectly legal.
+	(while (and previous
+		    (or (isearch-invalid-regexp frame)
+			(let* ((string (isearch-string frame))
+			       (lchar (aref string (1- (length string)))))
+			  ;; The operators aren't always operators; check
+			  ;; backslashes.  This doesn't handle the case of
+			  ;; operators at the beginning of the regexp not
+			  ;; being special, but then we should fall back to
+			  ;; the barrier anyway because it's all optional.
+			  (if (isearch-backslash
+			       (isearch-string (car previous)))
+			      (eq lchar ?\})
+			    (memq lchar '(?* ?? ?+))))))
+	  (setq stack previous previous (cdr previous) frame (car stack)))
+	(when stack
+	  ;; `stack' now refers the most recent valid regexp that is not at
+	  ;; all optional in its last term.  Now dig one level deeper and find
+	  ;; what matched before that.
+	  (let ((last-other-end (or (isearch-other-end (car previous))
+				    isearch-barrier)))
+	    (goto-char (if isearch-forward
+			   (max last-other-end isearch-barrier)
+			 (min last-other-end isearch-barrier)))
+	    (setq isearch-adjusted t))))))
   (isearch-process-search-char last-command-char))
 
-
-(defun isearch-|-char ()
-  "If in regexp search, jump to the barrier."
+;; * and ? are special when not preceded by \.
+(defun isearch-*-char ()
+  "Maybe back up to handle * and ? specially in regexps."
   (interactive)
-  (if isearch-regexp
-      (progn
-	(setq isearch-adjusted t)
-	(goto-char isearch-barrier)))
-  (isearch-process-search-char last-command-char))
+  (isearch-fallback nil))
+
+;; } is special when it is preceded by \.
+(defun isearch-}-char ()
+  "Handle \\} specially in regexps."
+  (interactive)
+  (isearch-fallback t t))
+
+;; | is special when it is preceded by \.
+(defun isearch-|-char ()
+  "If in regexp search, jump to the barrier unless in a group."
+  (interactive)
+  (isearch-fallback t nil t))
 
 (defun isearch-unread-key-sequence (keylist)
   "Unread the given key-sequence KEYLIST.
@@ -1775,38 +1883,6 @@
 	(insert isearch-string))))
 
 
-;; The search status stack (and isearch window-local variables, not used).
-;; Need a structure for this.
-
-(defun isearch-top-state ()
-  (let ((cmd (car isearch-cmds)))
-    (setq isearch-string (car cmd)
-	  isearch-message (car (cdr cmd))
-	  isearch-success (nth 3 cmd)
-	  isearch-forward (nth 4 cmd)
-	  isearch-other-end (nth 5 cmd)
-	  isearch-word (nth 6 cmd)
-	  isearch-invalid-regexp (nth 7 cmd)
-	  isearch-wrapped (nth 8 cmd)
-	  isearch-barrier (nth 9 cmd)
-	  isearch-within-brackets (nth 10 cmd)
-	  isearch-case-fold-search (nth 11 cmd))
-    (goto-char (car (cdr (cdr cmd))))))
-
-(defun isearch-pop-state ()
-  (setq isearch-cmds (cdr isearch-cmds))
-  (isearch-top-state))
-
-(defun isearch-push-state ()
-  (setq isearch-cmds
-	(cons (list isearch-string isearch-message (point)
-		    isearch-success isearch-forward isearch-other-end
-		    isearch-word
-		    isearch-invalid-regexp isearch-wrapped isearch-barrier
-		    isearch-within-brackets isearch-case-fold-search)
-	      isearch-cmds)))
-
-
 ;; Message string
 
 (defun isearch-message (&optional c-q-hack ellipsis)
@@ -1936,9 +2012,9 @@
   (if isearch-success
       nil
     ;; Ding if failed this time after succeeding last time.
-    (and (nth 3 (car isearch-cmds))
+    (and (isearch-success (car isearch-cmds))
 	 (ding))
-    (goto-char (nth 2 (car isearch-cmds)))))
+    (goto-char (isearch-point (car isearch-cmds)))))
 
 
 ;; Called when opening an overlay, and we are still in isearch.