[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Interpretation of a space in regexp isearch?

From: Juri Linkov
Subject: Re: Interpretation of a space in regexp isearch?
Date: Fri, 31 Aug 2012 12:31:04 +0300
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.2.50 (x86_64-pc-linux-gnu)

> - search-whitespace should not be a defcustom, since it is altered by
>   commands like isearch-toggle-whitespace.  Users can customize whether
>   to enable the feature by default setting search-whitespace-regexp to
>   either nil or a regexp.  I think search-whitespace should be renamed
>   to something more accurate like isearch-lax-space-match, and made into
>   a defvar.

Like there are two existing variables with similar functionality
`compare-windows-whitespace' and `compare-ignore-whitespace',
maybe it would be better to have similar names in isearch:
the already existing `search-whitespace-regexp'
and a new defvar `isearch-ignore-whitespace'.

> - Don't call the functions whitespace-search-forward; the whitespace-
>   prefix should be reserved for whitespace.el.  Call it something like
>   isearch-forward-lax-space-match.

The prefix `isearch-' is not quite right because these functions
can be used in other packages like replace.el being bound to
`replace-search-function'.  `search-' seems more right.

And when using the suffix `-ignore-whitespace' we could have functions:
`search-forward-ignore-whitespace' and `search-backward-ignore-whitespace'.

Or do you think `-ignore-whitespace' implies a more general functionality?
For instance, instead of the current limited implementation that just
turns every space character into a whitespace regexp like in:

(defun search-forward-ignore-whitespace (string &optional bound noerror count)
  (let ((search-spaces-regexp search-whitespace-regexp))
    (re-search-forward (regexp-quote string) bound noerror count)))

it would be also useful to completely ignore all whitespace differences
between the search string and the buffer text with the following

(defun search-whitespace-regexp (string)
   string nil t))

(defun search-forward-ignore-whitespace (string &optional bound noerror count)
  (re-search-forward (search-whitespace-regexp (regexp-quote string))
                     bound noerror count))

This is truly whitespace ignoring function that is very useful
when yanking and searching lines containing a mix of spaces, tabs
and newlines.  This implementation ignores whitespace in the same way
as `word-search-regexp' ignores punctuation.

I don't want to complicate this feature, but this possibility
for future development could be taken into account when thinking
about suitable names for new functions and variables.

> Also, I guess it won't be difficult to make M-s SPC work for regexp
> search too, by making it change search-spaces-regexp.  This can be left
> for later.

When users bind `isearch-forward-regexp' to C-s and use regexp search
as simple search, they will miss this feature.  So when leaving it,
a separate variable is needed to disable whitespace mode in regexp mode,
but to enable it in non-regexp simple mode by default.  This requires
a new variable `isearch-regexp-ignore-whitespace' but it complicates the
functionality, so maybe it should be removed from the next version of the patch?

=== modified file 'lisp/isearch.el'
--- lisp/isearch.el     2012-08-27 04:08:32 +0000
+++ lisp/isearch.el     2012-08-31 09:30:33 +0000
@@ -120,20 +120,10 @@ (defcustom search-whitespace-regexp (pur
 incremental search.  If the value is nil, each space you type
 matches literally, against one space.
-The value can also be a cons cell (REGEXP-1 . REGEXP-2).  In that
-case, REGEXP-1 is used as the value for ordinary incremental
-search, and REGEXP-2 is used for regexp 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 `]+'."
   :type '(choice (const :tag "Treat Spaces Literally" nil)
-                (cons (choice :tag "For Ordinary Isearch"
-                              regexp
-                              (const :tag "Treat Spaces Literally" nil))
-                      (choice :tag "For Regexp Isearch"
-                              regexp
-                              (const :tag "Treat Spaces Literally" nil)))
   :group 'isearch
   :version "24.3")
@@ -510,6 +512,7 @@ (defvar isearch-mode-map
     (define-key map "\M-r" 'isearch-toggle-regexp)
     (define-key map "\M-e" 'isearch-edit-string)
+    (define-key map "\M-s " 'isearch-toggle-whitespace)
     (define-key map "\M-sc" 'isearch-toggle-case-fold)
     (define-key map "\M-sr" 'isearch-toggle-regexp)
     (define-key map "\M-sw" 'isearch-toggle-word)
@@ -556,6 +564,17 @@ (defvar isearch-word nil
 The property `isearch-message-prefix' put on this function specifies the
 prefix string displayed in the search message.")
+(defvar isearch-ignore-whitespace t
+  "If non-nil, a space will match a sequence of whitespace chars.
+When you enter a space or spaces in the incremental search, it
+will match any sequence matched by the regexp in the variable
+If the value is nil, each space you type matches literally,
+against one space.")
+(defvar isearch-regexp-ignore-whitespace nil
+  "Like `isearch-ignore-whitespace' but for regexp mode.")
 (defvar isearch-cmds nil
   "Stack of search status sets.
 Each set is a vector of the form:
@@ -1409,6 +1434,24 @@ (defun isearch-toggle-case-fold ()
   (sit-for 1)
+(defun isearch-toggle-whitespace ()
+  "Toggle whitespace matching in searching on or off."
+  (interactive)
+  (if isearch-regexp
+      (setq isearch-regexp-ignore-whitespace (not 
+    (setq isearch-ignore-whitespace (not isearch-ignore-whitespace)))
+  (let ((message-log-max nil))
+    (message "%s%s [%s]"
+            (isearch-message-prefix nil isearch-nonincremental)
+            isearch-message
+            (if (if isearch-regexp
+                    isearch-regexp-ignore-whitespace
+                  isearch-ignore-whitespace)
+                "ignore whitespace"
+              "treat spaces literally")))
+  (setq isearch-success t isearch-adjusted t)
+  (sit-for 1)
+  (isearch-update))
 ;; Word search
@@ -1507,6 +1561,25 @@ (defun isearch-symbol-regexp (string &op
 (put 'isearch-symbol-regexp 'isearch-message-prefix "symbol ")
+;; Search ignoring whitespace
+(defun search-forward-ignore-whitespace (string &optional bound noerror count)
+  (let ((search-spaces-regexp search-whitespace-regexp))
+    (re-search-forward (regexp-quote string) bound noerror count)))
+(defun search-backward-ignore-whitespace (string &optional bound noerror count)
+  (let ((search-spaces-regexp search-whitespace-regexp))
+    (re-search-backward (regexp-quote string) bound noerror count)))
+(defun re-search-forward-ignore-whitespace (string &optional bound noerror 
+  (let ((search-spaces-regexp search-whitespace-regexp))
+    (re-search-forward string bound noerror count)))
+(defun re-search-backward-ignore-whitespace (string &optional bound noerror 
+  (let ((search-spaces-regexp search-whitespace-regexp))
+    (re-search-backward string bound noerror count)))
 (defun isearch-query-replace (&optional delimited regexp-flag)
   "Start `query-replace' with string to replace from last search string.
 The arg DELIMITED (prefix arg if interactive), if non-nil, means replace
@@ -1522,6 +1595,14 @@ (defun isearch-query-replace (&optional
        ;; set `search-upper-case' to nil to not call
        ;; `isearch-no-upper-case-p' in `perform-replace'
        (search-upper-case nil)
+       (replace-search-function
+        (if (and isearch-ignore-whitespace (not regexp-flag))
+            #'search-forward-ignore-whitespace
+          replace-search-function))
+       (replace-re-search-function
+        (if (and isearch-regexp-ignore-whitespace regexp-flag)
+            #'re-search-forward-ignore-whitespace
+          replace-re-search-function))
        ;; Set `isearch-recursive-edit' to nil to prevent calling
        ;; `exit-recursive-edit' in `isearch-done' that terminates
        ;; the execution of this command when it is non-nil.
@@ -1558,15 +1639,6 @@ (defun isearch-query-replace-regexp (&op
    (list current-prefix-arg))
   (isearch-query-replace delimited t))
-(defun isearch-whitespace-regexp ()
-  "Return the value of `search-whitespace-regexp' for the current search."
-  (cond ((not (consp search-whitespace-regexp))
-        search-whitespace-regexp)
-       (isearch-regexp
-        (cdr search-whitespace-regexp))
-       (t
-        (car search-whitespace-regexp))))
 (defun isearch-occur (regexp &optional nlines)
   "Run `occur' using the last search string as the regexp.
 Interactively, REGEXP is constructed using the search string from the
@@ -1606,7 +1678,11 @@ (defun isearch-occur (regexp &optional n
        ;; Set `search-upper-case' to nil to not call
        ;; `isearch-no-upper-case-p' in `occur-1'.
        (search-upper-case nil)
-       (search-spaces-regexp (isearch-whitespace-regexp)))
+       (search-spaces-regexp
+        (if (if isearch-regexp
+                isearch-regexp-ignore-whitespace
+              isearch-ignore-whitespace)
+            search-whitespace-regexp)))
     (occur regexp nlines)))
 (declare-function hi-lock-read-face-name "hi-lock" ())
@@ -2203,7 +2286,7 @@ (defun isearch-quote-char ()
     ;; Assume character codes 0200 - 0377 stand for characters in some
     ;; single-byte character set, and convert them to Emacs
     ;; characters.
-    (if (and isearch-regexp (= char ?\s))
+    (if (and isearch-regexp isearch-regexp-ignore-whitespace (= char ?\s))
        (if (subregexp-context-p isearch-string (length isearch-string))
            (isearch-process-search-string "[ ]" " ")
          (isearch-process-search-char char))
@@ -2443,16 +2534,19 @@ (defun isearch-search-fun-default ()
             (funcall isearch-word string lax)
           (word-search-regexp string lax))
         bound noerror count))))
+   ((and isearch-regexp isearch-regexp-ignore-whitespace
+        search-whitespace-regexp)
+    (if isearch-forward
+       're-search-forward-ignore-whitespace
+      're-search-backward-ignore-whitespace))
     (if isearch-forward 're-search-forward 're-search-backward))
+   ((and isearch-ignore-whitespace search-whitespace-regexp)
+    (if isearch-forward
+       'search-forward-ignore-whitespace
+      'search-backward-ignore-whitespace))
-    (if isearch-forward 'isearch-search-forward 'isearch-search-backward))))
-(defun isearch-search-forward (string &optional bound noerror count)
-  (re-search-forward (regexp-quote string) bound noerror count))
-(defun isearch-search-backward (string &optional bound noerror count)
-  (re-search-backward (regexp-quote string) bound noerror count))
+    (if isearch-forward 'search-forward 'search-backward))))
 (defun isearch-search-string (string bound noerror)
   "Search for the first occurrence of STRING or its translation.
@@ -2503,17 +2597,13 @@ (defun isearch-search ()
            (inhibit-quit nil)
            (case-fold-search isearch-case-fold-search)
-           (search-spaces-regexp (isearch-whitespace-regexp))
            (retry t))
        (setq isearch-error nil)
        (while retry
@@ -2805,7 +2942,8 @@ (defvar isearch-lazy-highlight-window-st
 (defvar isearch-lazy-highlight-window-end nil)
 (defvar isearch-lazy-highlight-case-fold-search nil)
 (defvar isearch-lazy-highlight-regexp nil)
-(defvar isearch-lazy-highlight-space-regexp nil)
+(defvar isearch-lazy-highlight-whitespace nil)
+(defvar isearch-lazy-highlight-whitespace-regexp nil)
 (defvar isearch-lazy-highlight-word nil)
 (defvar isearch-lazy-highlight-forward nil)
 (defvar isearch-lazy-highlight-error nil)
@@ -2847,6 +2985,10 @@ (defun isearch-lazy-highlight-new-loop (
                 (not (eq isearch-lazy-highlight-word
+                (not (eq isearch-lazy-highlight-whitespace
+                         isearch-ignore-whitespace))
+                (not (eq isearch-lazy-highlight-whitespace-regexp
+                         search-whitespace-regexp))
                  (not (= (window-start)
                  (not (= (window-end)   ; Window may have been split/joined.
@@ -2873,7 +3015,8 @@ (defun isearch-lazy-highlight-new-loop (
          isearch-lazy-highlight-last-string  isearch-string
          isearch-lazy-highlight-case-fold-search isearch-case-fold-search
          isearch-lazy-highlight-regexp       isearch-regexp
-         isearch-lazy-highlight-space-regexp (isearch-whitespace-regexp)
+         isearch-lazy-highlight-whitespace   isearch-ignore-whitespace
+         isearch-lazy-highlight-whitespace-regexp search-whitespace-regexp
          isearch-lazy-highlight-word         isearch-word
          isearch-lazy-highlight-forward      isearch-forward)
       (unless (equal isearch-string "")
@@ -2887,7 +3030,8 @@ (defun isearch-lazy-highlight-search ()
   (condition-case nil
       (let ((case-fold-search isearch-lazy-highlight-case-fold-search)
            (isearch-regexp isearch-lazy-highlight-regexp)
-           (search-spaces-regexp isearch-lazy-highlight-space-regexp)
+           (search-spaces-regexp (if isearch-lazy-highlight-whitespace
+                                     isearch-lazy-highlight-whitespace-regexp))
            (isearch-word isearch-lazy-highlight-word)
            (search-invisible nil)      ; don't match invisible text
            (retry t)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]