changeset 5855:0bddb59072b6

Look for cased character classes when deciding on case-fold-search, #'isearch lisp/ChangeLog addition: 2015-03-11 Aidan Kehoe <kehoea@parhasard.net> * isearch-mode.el: * isearch-mode.el (isearch-fix-case): Use the new #'no-case-regexp-p function if treating ISEARCH-STRING as a regular expression; otherwise, use the [[:upper:]] character class. * isearch-mode.el (isearch-no-upper-case-p): Removed. * isearch-mode.el (with-caps-disable-folding): Removed. These two haven't been used since 1998. * occur.el (occur-1): Use #'no-case-regexp-p here. * replace.el (perform-replace): Don't use #'no-upper-case-p, use #'no-case-regexp-p or (string-match "[[:upper:]]" ...) as appropriate. * simple.el: * simple.el (no-upper-case-p): Removed. This did two different things, and its secondary function (examining regular expressions) just became much more complicated; move the regular expression functionality to its own function, use character classes when examining non-regular-expressions instead. The code to look for character classes, and the design decision that this should be done, are from GNU, thank you Stefan Monnier. * simple.el (no-case-regexp-p): New. Given a REGEXP, return non-nil if it has nothing to suggest an interactive user wants a case-sensitive search. * simple.el (with-search-caps-disable-folding): * simple.el (with-interactive-search-caps-disable-folding): Update both these macros to use #'no-case-regexp-p.
author Aidan Kehoe <kehoea@parhasard.net>
date Wed, 11 Mar 2015 18:06:15 +0000
parents ccb0cff115d2
children 27876789edc5
files lisp/ChangeLog lisp/isearch-mode.el lisp/occur.el lisp/replace.el lisp/simple.el
diffstat 5 files changed, 89 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/ChangeLog	Wed Mar 11 15:06:05 2015 +0000
+++ b/lisp/ChangeLog	Wed Mar 11 18:06:15 2015 +0000
@@ -1,3 +1,33 @@
+2015-03-11  Aidan Kehoe  <kehoea@parhasard.net>
+
+	* isearch-mode.el:
+	* isearch-mode.el (isearch-fix-case):
+	Use the new #'no-case-regexp-p function if treating ISEARCH-STRING
+	as a regular expression; otherwise, use the [[:upper:]] character
+	class.
+	* isearch-mode.el (isearch-no-upper-case-p): Removed. 
+	* isearch-mode.el (with-caps-disable-folding): Removed.
+	These two haven't been used since 1998.
+	* occur.el (occur-1):
+	Use #'no-case-regexp-p here.
+	* replace.el (perform-replace):
+	Don't use #'no-upper-case-p, use #'no-case-regexp-p or
+	(string-match "[[:upper:]]" ...) as appropriate.
+	* simple.el:
+	* simple.el (no-upper-case-p): Removed. This did two different
+	things, and its secondary function (examining regular expressions)
+	just became much more complicated; move the regular expression
+	functionality to its own function, use character classes when
+	examining non-regular-expressions instead.
+	The code to look for character classes, and the design decision
+	that this should be done, are from GNU, thank you Stefan Monnier.
+	* simple.el (no-case-regexp-p): New.
+	Given a REGEXP, return non-nil if it has nothing to suggest an
+	interactive user wants a case-sensitive search.
+	* simple.el (with-search-caps-disable-folding):
+	* simple.el (with-interactive-search-caps-disable-folding):
+	Update both these macros to use #'no-case-regexp-p.
+
 2015-03-11  Aidan Kehoe  <kehoea@parhasard.net>
 
 	Correct #'clear-message and friends so the START and END supplied
--- a/lisp/isearch-mode.el	Wed Mar 11 15:06:05 2015 +0000
+++ b/lisp/isearch-mode.el	Wed Mar 11 18:06:15 2015 +0000
@@ -1068,7 +1068,11 @@
 	   (not isearch-fixed-case)
 	   search-caps-disable-folding)
       (setq isearch-case-fold-search
-	    (no-upper-case-p isearch-string isearch-regexp)))
+            (if isearch-regexp
+                (no-case-regexp-p isearch-string)
+              (save-match-data
+                (let (case-fold-search)
+                  (not (string-match "[[:upper:]]" isearch-string)))))))
   (setq isearch-mode (if case-fold-search
                          (if isearch-case-fold-search
                              " Isearch"  ;As God Intended Mode
@@ -1856,15 +1860,6 @@
 			 t))
 		     isearch-unhidden-extents)))))
 
-(defun isearch-no-upper-case-p (string)
-  "Return t if there are no upper case chars in string.
-But upper case chars preceded by \\ do not count since they
-have special meaning in a regexp."
-  ;; this incorrectly returns t for "\\\\A"
-  (let ((case-fold-search nil))
-    (not (string-match "\\(^\\|[^\\]\\)[A-Z]" string))))
-(make-obsolete 'isearch-no-upper-case-p 'no-upper-case-p)
-
 ;; Portability functions to support various Emacs versions.
 
 (defun isearch-char-to-string (c)
@@ -1876,20 +1871,6 @@
 ;  (isearch-char-to-string c))
 
 (define-function 'isearch-text-char-description 'text-char-description)
-
-;; Used by etags.el and info.el
-(defmacro with-caps-disable-folding (string &rest body) "\
-Eval BODY with `case-fold-search' let to nil if STRING contains
-uppercase letters and `search-caps-disable-folding' is t."
-  `(let ((case-fold-search
-          (if (and case-fold-search search-caps-disable-folding)
-              (isearch-no-upper-case-p ,string)
-            case-fold-search)))
-     ,@body))
-(make-obsolete 'with-caps-disable-folding 'with-search-caps-disable-folding)
-(put 'with-caps-disable-folding 'lisp-indent-function 1)
-(put 'with-caps-disable-folding 'edebug-form-spec '(form body))
-
 
 ;;;========================================================
 ;;; Advanced highlighting
--- a/lisp/occur.el	Wed Mar 11 15:06:05 2015 +0000
+++ b/lisp/occur.el	Wed Mar 11 18:06:15 2015 +0000
@@ -394,8 +394,7 @@
 	(let ((count (occur-engine
 		      regexp active-bufs occur-buf
 		      (or nlines list-matching-lines-default-context-lines)
-		      (and case-fold-search
-			   (no-upper-case-p regexp t))
+		      (and case-fold-search (no-case-regexp-p regexp))
 		      list-matching-lines-buffer-name-face
 		      nil list-matching-lines-face t)))
 	  (let* ((bufcount (length active-bufs))
--- a/lisp/replace.el	Wed Mar 11 15:06:05 2015 +0000
+++ b/lisp/replace.el	Wed Mar 11 18:06:15 2015 +0000
@@ -563,7 +563,11 @@
 	 ;; XEmacs addition
 	 (qr-case-fold-search
 	  (if (and case-fold-search search-caps-disable-folding)
-	      (no-upper-case-p search-string regexp-flag)
+              (if regexp-flag
+                  (no-case-regexp-p search-string)
+                (save-match-data
+                  (let (case-fold-search)
+                    (not (string-match "[[:upper:]]" search-string)))))
 	    case-fold-search))
 	 (message
 	  (if query-flag
--- a/lisp/simple.el	Wed Mar 11 15:06:05 2015 +0000
+++ b/lisp/simple.el	Wed Mar 11 18:06:15 2015 +0000
@@ -94,47 +94,70 @@
   "Warnings customizations."
   :group 'minibuffer)
 
-
 (defcustom search-caps-disable-folding t
   "*If non-nil, upper case chars disable case fold searching.
 This does not apply to \"yanked\" strings."
   :type 'boolean
   :group 'editing-basics)
 
-;; This is stolen (and slightly modified) from FSF emacs's
-;; `isearch-no-upper-case-p'.
-(defun no-upper-case-p (string &optional regexp-flag)
-  "Return t if there are no upper case chars in STRING.
-If REGEXP-FLAG is non-nil, disregard letters preceded by `\\' (but not `\\\\')
-since they have special meaning in a regexp."
+(defun no-case-regexp-p (regexp)
+  "Return t if there are no case-specific constructs in REGEXP.
+
+Lower case characters are regarded as not case-specific.  Upper case
+characters are usually regarded as case-specific, but upper case characters
+used in special regexp constructs, where they do not match upper case
+characters specifically, are regarded as not case-specific.  In contrast, the
+character classes [:lower:] and [:upper:] are viewed as case-specific.
+
+This is intended to be used by interactive searching code to decide, in a
+do-what-I-mean fashion, whether a given search should be case-sensitive."
   (let ((case-fold-search nil))
-    (not (string-match (if regexp-flag
-			   "\\(^\\|\\\\\\\\\\|[^\\]\\)[A-Z]"
-			 "[A-Z]")
-		       string))
-    ))
-
-(defmacro with-search-caps-disable-folding (string regexp-flag &rest body) "\
-Eval BODY with `case-fold-search' let to nil if `search-caps-disable-folding'
-is non-nil, and if STRING (either a string or a regular expression according
-to REGEXP-FLAG) contains uppercase letters."
+    (save-match-data
+      (not (or (string-match "\\(^\\|\\\\\\\\\\|[^\\]\\)[[:upper:]]" regexp)
+               (and (string-match "\\[:\\(upp\\|low\\)er:]" regexp)
+                    (condition-case err
+                        (progn
+                          (string-match (substring regexp 0
+                                                   (match-beginning 0)) "")
+                          nil)
+                      (invalid-regexp
+                       (equal "Unmatched [ or [^" (cadr err))))))))))
+
+(defmacro* with-search-caps-disable-folding (string regexp-p &body body)
+  "Execute the forms in BODY, respecting `search-caps-disable-folding'.
+
+Within BODY, bind `case-fold-search' to nil if `search-caps-disable-folding'
+is non-nil, REGEXP-P is nil, and if STRING contains any uppercase characters.
+
+If REGEXP-P is non-nil, treat STRING as a regular expression, and bind
+`case-fold-search' to nil if it contains uppercase characters that are
+not special regular expression constructs, or if it contains
+case-specific character classes such as `[[:upper:]]' or
+`[[:lower:]]'.  See `no-case-regexp-p'."
   `(let ((case-fold-search
           (if (and case-fold-search search-caps-disable-folding)
-              (no-upper-case-p ,string ,regexp-flag)
+              (if ,regexp-p
+                  (no-case-regexp-p ,string)
+                (save-match-data
+                  (let (case-fold-search)
+                    (not (string-match "[[:upper:]]" ,string)))))
             case-fold-search)))
      ,@body))
 (put 'with-search-caps-disable-folding 'lisp-indent-function 2)
 (put 'with-search-caps-disable-folding 'edebug-form-spec
      '(sexp sexp &rest form))
 
-(defmacro with-interactive-search-caps-disable-folding (string regexp-flag
-							       &rest body)
-  "Same as `with-search-caps-disable-folding', but only in the case of a
-function called interactively."
+(defmacro* with-interactive-search-caps-disable-folding (string regexp-p
+                                                                &body body)
+  "Like `with-search-caps-disable-folding', but only when interactive."
   `(let ((case-fold-search
-	  (if (and (interactive-p)
-		   case-fold-search search-caps-disable-folding)
-              (no-upper-case-p ,string ,regexp-flag)
+	  (if (and (interactive-p) case-fold-search
+                   search-caps-disable-folding)
+              (if ,regexp-p
+                  (no-case-regexp-p ,string)
+                (save-match-data
+                  (let (case-fold-search)
+                    (not (string-match "[[:upper:]]" ,string)))))
             case-fold-search)))
      ,@body))
 (put 'with-interactive-search-caps-disable-folding 'lisp-indent-function 2)