Subject: Yank and delete characters in word and symbol isearch
From: Juri Linkov <[email-masked]>
To: [email-masked]
Date: Wed, 12 Jun 2013 23:57:04 +0300
List-Id: <debbugs-submit.debbugs.gnu.org>

As found in http://lists.gnu.org/archive/html/emacs-devel/2013-06/msg00390.html
the currently existing commands `isearch-yank-char' and `isearch-del-char'
fail to yank and delete characters in a word/symbol search.

The test case is typing `M-s w C-M-y C-M-y ... C-M-w C-M-w ...'
in the middle of a word/symbol or at the beginning/end of a word/symbol.

To remove the failure to yank a character in the middle of a word/symbol
it helps to lax the regexp at both ends of the word/symbol.

And to remove the failure to yank a character at the beginning/end
of a word/symbol it helps to match leading/trailing whitespace
at the word/symbol boundaries as well.

Then both `word-search-regexp' and `isearch-symbol-regexp' could share
the same body with the difference where the former uses word-based regexps
with \\<, \\> and \\W, and the latter uses symbol-based regexps with
\\_< and \\_>.

The remaining problem is how to translate \\W to the symbol-based regexp that
will match a non-word non-symbol character.  The only solution that I found is
to list all possible syntaxes except word and symbol syntax.

I tested this and it successfully passes all tests.

=== modified file 'lisp/isearch.el'
--- lisp/isearch.el	2013-06-06 06:23:19 +0000
+++ lisp/isearch.el	2013-06-12 20:48:17 +0000
@@ -1545,12 +1649,15 @@ (defun word-search-regexp (string &optio
 
 Used in `word-search-forward', `word-search-backward',
 `word-search-forward-lax', `word-search-backward-lax'."
-  (if (string-match-p "^\\W*$" string)
-      ""
-    (concat
-     "\\b"
-     (mapconcat 'identity (split-string string "\\W+" t) "\\W+")
-     (if (or (not lax) (string-match-p "\\W$" string)) "\\b"))))
+  (cond
+   ((equal string "") "")
+   ((string-match-p "\\`\\W+\\'" string) "\\W+")
+   (t (concat
+       (if (string-match-p "\\`\\W" string) "\\W+"
+	 (unless lax "\\<"))
+       (mapconcat 'regexp-quote (split-string string "\\W+" t) "\\W+")
+       (if (string-match-p "\\W\\'" string) "\\W+"
+	 (unless lax "\\>"))))))
 
 (defun word-search-backward (string &optional bound noerror count)
   "Search backward from point for STRING, ignoring differences in punctuation.
@@ -1627,7 +1733,17 @@ (defun isearch-symbol-regexp (string &op
   "Return a regexp which matches STRING as a symbol.
 Creates a regexp where STRING is surrounded by symbol delimiters \\_< and \\_>.
 If LAX is non-nil, the end of the string need not match a symbol boundary."
-  (concat "\\_<" (regexp-quote string) (unless lax "\\_>")))
+  (let ((not-word-symbol-re
+	 "\\(?:\\s-\\|\\s.\\|\\s(\\|\\s)\\|\\s\"\\|\\s\\\\|\\s/\\|\\s$\\|\\s'\\|\\s<\\|\\s>\\|\\s@\\|\\s!\\|\\s|\\)+"))
+    (cond
+     ((equal string "") "")
+     ((string-match-p (format "\\`%s\\'" not-word-symbol-re) string) not-word-symbol-re)
+     (t (concat
+	 (if (string-match-p (format "\\`%s" not-word-symbol-re) string) not-word-symbol-re
+	   (unless lax "\\_<"))
+	 (mapconcat 'regexp-quote (split-string string not-word-symbol-re t) not-word-symbol-re)
+	 (if (string-match-p (format "%s\\'" not-word-symbol-re) string) not-word-symbol-re
+	   (unless lax "\\_>")))))))
 
 (put 'isearch-symbol-regexp 'isearch-message-prefix "symbol ")