From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.bugs Subject: bug#10145: 24.0.91; Word Isearch backward Date: Thu, 01 Dec 2011 09:27:14 +0200 Organization: JURTA Message-ID: <878vmwu55q.fsf@mail.jurta.org> References: <87k46jyd79.fsf@mail.jurta.org> <8739d6j62p.fsf@mail.jurta.org> <87aa7dd48q.fsf@mail.jurta.org> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: dough.gmane.org 1322724787 21988 80.91.229.12 (1 Dec 2011 07:33:07 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Thu, 1 Dec 2011 07:33:07 +0000 (UTC) Cc: 10145@debbugs.gnu.org To: Stefan Monnier Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Thu Dec 01 08:33:00 2011 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([140.186.70.17]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1RW18d-0001dv-GQ for geb-bug-gnu-emacs@m.gmane.org; Thu, 01 Dec 2011 08:32:59 +0100 Original-Received: from localhost ([::1]:46246 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RW18d-0004ws-46 for geb-bug-gnu-emacs@m.gmane.org; Thu, 01 Dec 2011 02:32:59 -0500 Original-Received: from eggs.gnu.org ([140.186.70.92]:45493) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RW18a-0004wl-82 for bug-gnu-emacs@gnu.org; Thu, 01 Dec 2011 02:32:57 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RW18Y-0001Iu-OK for bug-gnu-emacs@gnu.org; Thu, 01 Dec 2011 02:32:56 -0500 Original-Received: from debbugs.gnu.org ([140.186.70.43]:46650) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RW18Y-0001Iq-Ka for bug-gnu-emacs@gnu.org; Thu, 01 Dec 2011 02:32:54 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.69) (envelope-from ) id 1RW18f-0007jZ-N5 for bug-gnu-emacs@gnu.org; Thu, 01 Dec 2011 02:33:01 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Juri Linkov Original-Sender: debbugs-submit-bounces@debbugs.gnu.org Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 01 Dec 2011 07:33:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 10145 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 10145-submit@debbugs.gnu.org id=B10145.132272473729672 (code B ref 10145); Thu, 01 Dec 2011 07:33:01 +0000 Original-Received: (at 10145) by debbugs.gnu.org; 1 Dec 2011 07:32:17 +0000 Original-Received: from localhost ([127.0.0.1] helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1RW17x-0007iX-GH for submit@debbugs.gnu.org; Thu, 01 Dec 2011 02:32:17 -0500 Original-Received: from smarty.dreamhost.com ([208.113.175.8]) by debbugs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1RW17v-0007iP-0i for 10145@debbugs.gnu.org; Thu, 01 Dec 2011 02:32:16 -0500 Original-Received: from ps18281.dreamhostps.com (ps18281.dreamhost.com [69.163.218.105]) by smarty.dreamhost.com (Postfix) with ESMTP id 91270684062; Wed, 30 Nov 2011 23:32:06 -0800 (PST) Original-Received: from localhost (ps18281.dreamhostps.com [69.163.218.105]) by ps18281.dreamhostps.com (Postfix) with ESMTP id 40BA0451C5C7; Wed, 30 Nov 2011 23:31:53 -0800 (PST) In-Reply-To: (Stefan Monnier's message of "Wed, 30 Nov 2011 14:11:18 -0500") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.0.91 (x86_64-pc-linux-gnu) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.11 Precedence: list Resent-Date: Thu, 01 Dec 2011 02:33:01 -0500 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 140.186.70.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:54527 Archived-At: > `word-search-regexp' is good, thank you. > >> I'll provide an Elisp version once the function name is agreed upon. > > Thanks. Of course, that would/will have to wait for 24.2. This is intended to fix a bug reported by Dani for 24.1. Below is a complete patch. Please decide what to do. The Elisp version passes all regression tests and its output is identical to the output of the C version: (word-search-regexp "") "" (word-search-regexp " ") "" (word-search-regexp "w") "\\bw\\b" (word-search-regexp " w") "\\bw\\b" (word-search-regexp "w ") "\\bw\\b" (word-search-regexp " w ") "\\bw\\b" (word-search-regexp "w w") "\\bw\\W\\W*w\\b" (word-search-regexp " w w") "\\bw\\W\\W*w\\b" (word-search-regexp "w w ") "\\bw\\W\\W*w\\b" (word-search-regexp " w w ") "\\bw\\W\\W*w\\b" (word-search-regexp "" t) "" (word-search-regexp " " t) "" (word-search-regexp "w" t) "\\bw" (word-search-regexp " w" t) "\\bw" (word-search-regexp "w " t) "\\bw\\b" (word-search-regexp " w " t) "\\bw\\b" (word-search-regexp "w w" t) "\\bw\\W\\W*w" (word-search-regexp " w w" t) "\\bw\\W\\W*w" (word-search-regexp "w w " t) "\\bw\\W\\W*w\\b" (word-search-regexp " w w " t) "\\bw\\W\\W*w\\b" === modified file 'lisp/isearch.el' --- lisp/isearch.el 2011-11-29 18:39:16 +0000 +++ lisp/isearch.el 2011-12-01 07:27:07 +0000 @@ -1380,6 +1389,20 @@ (defun isearch-toggle-case-fold () (sit-for 1) (isearch-update)) +(defun word-search-regexp (string &optional lax) + "Return a regexp which matches words, ignoring punctuation. +Given STRING, a string of words separated by word delimiters, +compute a regexp that matches those exact words separated by +arbitrary punctuation. If LAX is non-nil, the end of the string +need not match a word boundary unless it ends in whitespace. +Used in `word-search-forward' and `word-search-backward'." + (if (string-match-p "^\\W*$" string) + "" + (concat + "\\b" + (mapconcat 'identity (split-string string "\\W\\W*" t) "\\W\\W*") + (if (or (not lax) (string-match-p "\\W$" string)) "\\b")))) + (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 @@ -1642,8 +1660,10 @@ (defun isearch-search-and-update () (if (and (eq case-fold-search t) search-upper-case) (setq case-fold-search (isearch-no-upper-case-p isearch-string isearch-regexp))) - (looking-at (if isearch-regexp isearch-string - (regexp-quote isearch-string)))) + (looking-at (cond + (isearch-regexp isearch-string) + (isearch-word (word-search-regexp isearch-string t)) + (t (regexp-quote isearch-string))))) (error nil)) (or isearch-yank-flag (<= (match-end 0) === modified file 'src/search.c' --- src/search.c 2011-11-27 18:17:40 +0000 +++ src/search.c 2011-12-01 07:27:07 +0000 @@ -2078,99 +2077,6 @@ (at your option) any later version. XSETBUFFER (last_thing_searched, current_buffer); } -/* Given STRING, a string of words separated by word delimiters, - compute a regexp that matches those exact words separated by - arbitrary punctuation. If LAX is nonzero, the end of the string - need not match a word boundary unless it ends in whitespace. */ - -static Lisp_Object -wordify (Lisp_Object string, int lax) -{ - register unsigned char *o; - register EMACS_INT i, i_byte, len, punct_count = 0, word_count = 0; - Lisp_Object val; - int prev_c = 0; - EMACS_INT adjust; - int whitespace_at_end; - - CHECK_STRING (string); - len = SCHARS (string); - - for (i = 0, i_byte = 0; i < len; ) - { - int c; - - FETCH_STRING_CHAR_AS_MULTIBYTE_ADVANCE (c, string, i, i_byte); - - if (SYNTAX (c) != Sword) - { - punct_count++; - if (SYNTAX (prev_c) == Sword) - word_count++; - } - - prev_c = c; - } - - if (SYNTAX (prev_c) == Sword) - { - word_count++; - whitespace_at_end = 0; - } - else - { - whitespace_at_end = 1; - if (!word_count) - return empty_unibyte_string; - } - - adjust = - punct_count + 5 * (word_count - 1) - + ((lax && !whitespace_at_end) ? 2 : 4); - if (STRING_MULTIBYTE (string)) - val = make_uninit_multibyte_string (len + adjust, - SBYTES (string) - + adjust); - else - val = make_uninit_string (len + adjust); - - o = SDATA (val); - *o++ = '\\'; - *o++ = 'b'; - prev_c = 0; - - for (i = 0, i_byte = 0; i < len; ) - { - int c; - EMACS_INT i_byte_orig = i_byte; - - FETCH_STRING_CHAR_AS_MULTIBYTE_ADVANCE (c, string, i, i_byte); - - if (SYNTAX (c) == Sword) - { - memcpy (o, SDATA (string) + i_byte_orig, i_byte - i_byte_orig); - o += i_byte - i_byte_orig; - } - else if (SYNTAX (prev_c) == Sword && --word_count) - { - *o++ = '\\'; - *o++ = 'W'; - *o++ = '\\'; - *o++ = 'W'; - *o++ = '*'; - } - - prev_c = c; - } - - if (!lax || whitespace_at_end) - { - *o++ = '\\'; - *o++ = 'b'; - } - - return val; -} - DEFUN ("search-backward", Fsearch_backward, Ssearch_backward, 1, 4, "MSearch backward: ", doc: /* Search backward from point for STRING. @@ -2209,6 +2115,9 @@ (at your option) any later version. return search_command (string, bound, noerror, count, 1, 0, 0); } +/* Function that returns a regexp which matches words, ignoring punctuation. */ +static Lisp_Object Qword_search_regexp; + DEFUN ("word-search-backward", Fword_search_backward, Sword_search_backward, 1, 4, "sWord search backward: ", doc: /* Search backward from point for STRING, ignoring differences in punctuation. @@ -2217,10 +2126,15 @@ (at your option) any later version. The match found must not extend before that position. Optional third argument, if t, means if fail just return nil (no error). If not nil and not t, move to limit of search and return nil. -Optional fourth argument is repeat count--search for successive occurrences. */) +Optional fourth argument is repeat count--search for successive occurrences. + +Relies on the function `word-search-regexp' to convert a sequence +of words in STRING to a regexp used to search words without regard +to punctuation. */) (Lisp_Object string, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count) { - return search_command (wordify (string, 0), bound, noerror, count, -1, 1, 0); + return search_command (call2 (Qword_search_regexp, string, Qnil), + bound, noerror, count, -1, 1, 0); } DEFUN ("word-search-forward", Fword_search_forward, Sword_search_forward, 1, 4, @@ -2231,10 +2145,15 @@ (at your option) any later version. The match found must not extend after that position. Optional third argument, if t, means if fail just return nil (no error). If not nil and not t, move to limit of search and return nil. -Optional fourth argument is repeat count--search for successive occurrences. */) +Optional fourth argument is repeat count--search for successive occurrences. + +Relies on the function `word-search-regexp' to convert a sequence +of words in STRING to a regexp used to search words without regard +to punctuation. */) (Lisp_Object string, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count) { - return search_command (wordify (string, 0), bound, noerror, count, 1, 1, 0); + return search_command (call2 (Qword_search_regexp, string, Qnil), + bound, noerror, count, 1, 1, 0); } DEFUN ("word-search-backward-lax", Fword_search_backward_lax, Sword_search_backward_lax, 1, 4, @@ -2249,10 +2168,15 @@ (at your option) any later version. The match found must not extend before that position. Optional third argument, if t, means if fail just return nil (no error). If not nil and not t, move to limit of search and return nil. -Optional fourth argument is repeat count--search for successive occurrences. */) +Optional fourth argument is repeat count--search for successive occurrences. + +Relies on the function `word-search-regexp' to convert a sequence +of words in STRING to a regexp used to search words without regard +to punctuation. */) (Lisp_Object string, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count) { - return search_command (wordify (string, 1), bound, noerror, count, -1, 1, 0); + return search_command (call2 (Qword_search_regexp, string, Qt), + bound, noerror, count, -1, 1, 0); } DEFUN ("word-search-forward-lax", Fword_search_forward_lax, Sword_search_forward_lax, 1, 4, @@ -2267,10 +2191,15 @@ (at your option) any later version. The match found must not extend after that position. Optional third argument, if t, means if fail just return nil (no error). If not nil and not t, move to limit of search and return nil. -Optional fourth argument is repeat count--search for successive occurrences. */) +Optional fourth argument is repeat count--search for successive occurrences. + +Relies on the function `word-search-regexp' to convert a sequence +of words in STRING to a regexp used to search words without regard +to punctuation. */) (Lisp_Object string, Lisp_Object bound, Lisp_Object noerror, Lisp_Object count) { - return search_command (wordify (string, 1), bound, noerror, count, 1, 1, 0); + return search_command (call2 (Qword_search_regexp, string, Qt), + bound, noerror, count, 1, 1, 0); } DEFUN ("re-search-backward", Fre_search_backward, Sre_search_backward, 1, 4, @@ -3243,4 +3172,5 @@ (at your option) any later version. defsubr (&Smatch_data); defsubr (&Sset_match_data); defsubr (&Sregexp_quote); + DEFSYM (Qword_search_regexp, "word-search-regexp"); }