From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.devel Subject: Re: isearch hooks Date: Fri, 25 Jun 2004 21:07:38 +0300 Organization: JURTA Sender: emacs-devel-bounces+emacs-devel=quimby.gnus.org@gnu.org Message-ID: <87y8mba4us.fsf@mail.jurta.org> References: <20040528.181649.25475113.wl@gnu.org> <200405291737.i4THbPJ06689@raven.dms.auburn.edu> <878yeyczec.fsf@mail.jurta.org> <87n03aa4jk.fsf@mail.jurta.org> <87d63wy6ux.fsf_-_@mail.jurta.org> <87smcro0nx.fsf@mail.jurta.org> <873c4o60ef.fsf@mail.jurta.org> NNTP-Posting-Host: deer.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1088187538 10437 80.91.224.253 (25 Jun 2004 18:18:58 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Fri, 25 Jun 2004 18:18:58 +0000 (UTC) Cc: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+emacs-devel=quimby.gnus.org@gnu.org Fri Jun 25 20:18:49 2004 Return-path: Original-Received: from quimby.gnus.org ([80.91.224.244]) by deer.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 1BdvHl-0000N2-00 for ; Fri, 25 Jun 2004 20:18:49 +0200 Original-Received: from lists.gnu.org ([199.232.76.165]) by quimby.gnus.org with esmtp (Exim 3.35 #1 (Debian)) id 1BdvHj-0003MJ-00 for ; Fri, 25 Jun 2004 20:18:48 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.33) id 1BdvJB-0007Sr-Rj for emacs-devel@quimby.gnus.org; Fri, 25 Jun 2004 14:20:17 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.33) id 1BdvIm-0007HS-QI for emacs-devel@gnu.org; Fri, 25 Jun 2004 14:19:52 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.33) id 1BdvIj-0007GE-Vl for emacs-devel@gnu.org; Fri, 25 Jun 2004 14:19:51 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.33) id 1BdvIj-0007Fn-Nn for emacs-devel@gnu.org; Fri, 25 Jun 2004 14:19:49 -0400 Original-Received: from [66.33.205.9] (helo=spatula.dreamhost.com) by monty-python.gnu.org with esmtp (Exim 4.34) id 1BdvH7-0006gZ-II; Fri, 25 Jun 2004 14:18:10 -0400 Original-Received: from mail.jurta.org (80-235-42-124-dsl.mus.estpak.ee [80.235.42.124]) by spatula.dreamhost.com (Postfix) with ESMTP id BE56617D02A; Fri, 25 Jun 2004 11:17:54 -0700 (PDT) Original-To: rms@gnu.org In-Reply-To: (Richard Stallman's message of "Tue, 22 Jun 2004 19:17:47 -0400") User-Agent: Gnus/5.110002 (No Gnus v0.2) Emacs/21.3.50 (gnu/linux) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.4 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+emacs-devel=quimby.gnus.org@gnu.org Xref: main.gmane.org gmane.emacs.devel:25256 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:25256 Richard Stallman writes: > There were some problems with this approach: lazy highlighting uses > the same function `isearch-search-fun' to highlight other matches. > > It could well be that the existing hook isearch-search-fun is not adequate. > An additional hook for searching other places, before "failing" but > not used by lazy highlighting, could be useful. The existing hook `isearch-search-fun-function' seems adequate for lazy highlighting because the same search function should be used to highlight other possible matches which will be visited by the same search function (and in case of `Info-search' its matches are different from matches found by the default `isearch-search-fun' because `Info-search' ignores whitespace chars). The search function should be responsible for interpreting the `bound' argument (which is set by lazy highlighting to window boundaries) and restricting the search to these boundaries. > There are some inconveniences: the user can't delete the last input > by DEL and can't return the point to the search beginning by cancelling > the search with C-g. > > Can you design the hooks to fix all these problems? I added two new hooks: `isearch-push-state-function' and `isearch-pop-state-function' to save/restore the current Info file and node names in the search status stack. With changes in `isearch-cancel', `isearch-abort', `isearch-top-state' and `isearch-push-state' search locations are restored on typing `DEL', `C-g', `ESC ESC ESC'. The patch below for info.el sets four isearch functions in Info-mode by default, and `Info-isearch-search-function' uses `Info-search' only for regexp search. This makes sense because Info search is a regexp search already. So to search only within a Info node users can use C-s (non-regexp), and to search across the whole Info manual C-M-s. I think this is a good default behavior since the cases when users might want to restrict a regexp search only to the current Info node are very rare. Index: lisp/isearch.el =================================================================== RCS file: /cvsroot/emacs/emacs/lisp/isearch.el,v retrieving revision 1.229 diff -u -r1.229 isearch.el --- lisp/isearch.el 21 Jun 2004 03:15:43 -0000 1.229 +++ lisp/isearch.el 25 Jun 2004 17:26:12 -0000 @@ -199,6 +157,17 @@ (defvar isearch-mode-end-hook nil "Function(s) to call after terminating an incremental search.") +(defvar isearch-wrap-function nil + "Function to call to wrap the search when search is failed. +If nil, move point to the beginning of the buffer for a forward search, +or to the end of the buffer for a backward search.") + +(defvar isearch-push-state-function nil + "Function to save additional information to the search status stack.") + +(defvar isearch-pop-state-function nil + "Function to restore additional information from the search status stack.") + ;; Search ring. (defvar search-ring nil @@ -946,10 +926,12 @@ (defun isearch-cancel () "Terminate the search and go back to the starting point." (interactive) - (goto-char isearch-opoint) - (isearch-done t) + (if isearch-pop-state-function + (funcall isearch-pop-state-function (car (last isearch-cmds))) + (goto-char isearch-opoint)) + (isearch-done t) ; exit isearch (isearch-clean-overlays) - (signal 'quit nil)) ; and pass on quit signal + (signal 'quit nil)) ; and pass on quit signal (defun isearch-abort () "Abort incremental search mode if searching is successful, signaling quit. @@ -961,11 +943,9 @@ (if isearch-success ;; If search is successful, move back to starting point ;; and really do quit. - (progn (goto-char isearch-opoint) - (setq isearch-success nil) - (isearch-done t) ; exit isearch - (isearch-clean-overlays) - (signal 'quit nil)) ; and pass on quit signal + (progn + (setq isearch-success nil) + (isearch-cancel)) ;; If search is failing, or has an incomplete regexp, ;; rub out until it is once more successful. (while (or (not isearch-success) isearch-invalid-regexp) @@ -990,7 +970,9 @@ ;; If already have what to search for, repeat it. (or isearch-success (progn - (goto-char (if isearch-forward (point-min) (point-max))) + (if isearch-wrap-function + (funcall isearch-wrap-function) + (goto-char (if isearch-forward (point-min) (point-max)))) (setq isearch-wrapped t)))) ;; C-s in reverse or C-r in forward, change direction. (setq isearch-forward (not isearch-forward))) @@ -1742,7 +1762,9 @@ isearch-barrier (nth 9 cmd) isearch-within-brackets (nth 10 cmd) isearch-case-fold-search (nth 11 cmd)) - (goto-char (car (cdr (cdr cmd)))))) + (if isearch-pop-state-function + (funcall isearch-pop-state-function cmd) + (goto-char (car (cdr (cdr cmd))))))) (defun isearch-pop-state () (setq isearch-cmds (cdr isearch-cmds)) @@ -1750,11 +1772,14 @@ (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) + (cons (append + (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) + (if isearch-push-state-function + (list (funcall isearch-push-state-function)))) isearch-cmds))) @@ -1793,6 +1818,7 @@ (or isearch-success (setq ellipsis nil)) (let ((m (concat (if isearch-success "" "failing ") (if (and isearch-wrapped + (not isearch-wrap-function) (if isearch-forward (> (point) isearch-opoint) (< (point) isearch-opoint))) Index: lisp/info.el =================================================================== RCS file: /cvsroot/emacs/emacs/lisp/info.el,v retrieving revision 1.398 diff -u -r1.398 info.el --- lisp/info.el 12 Jun 2004 05:54:43 -0000 1.398 +++ lisp/info.el 25 Jun 2004 17:33:41 -0000 @@ -1442,8 +1442,9 @@ (defvar Info-search-case-fold nil "The value of `case-fold-search' from previous `Info-search' command.") -(defun Info-search (regexp) - "Search for REGEXP, starting from point, and select node it's found in." +(defun Info-search (regexp &optional bound noerror count direction) + "Search for REGEXP, starting from point, and select node it's found in. +If DIRECTION is `backward', search in the reverse direction." (interactive (list (read-string (if Info-search-history (format "Regexp search%s (default `%s'): " @@ -1458,31 +1459,42 @@ (setq regexp (car Info-search-history))) (when regexp (let (found beg-found give-up + (backward (eq direction 'backward)) (onode Info-current-node) (ofile Info-current-file) (opoint (point)) + (opoint-min (point-min)) + (opoint-max (point-max)) (ostart (window-start)) (osubfile Info-current-subfile)) (when Info-search-whitespace-regexp (setq regexp (replace-regexp-in-string "[ \t\n]+" Info-search-whitespace-regexp regexp))) (setq Info-search-case-fold case-fold-search) (save-excursion (save-restriction (widen) (while (and (not give-up) (or (null found) - (isearch-range-invisible beg-found found))) - (if (re-search-forward regexp nil t) - (setq found (point) beg-found (match-beginning 0)) + (if backward + (isearch-range-invisible found beg-found) + (isearch-range-invisible beg-found found)))) + (if (if backward + (re-search-backward regexp bound t) + (re-search-forward regexp bound t)) + (setq found (point) beg-found (if backward (match-end 0) + (match-beginning 0))) (setq give-up t))))) ;; If no subfiles, give error now. (if give-up (if (null Info-current-subfile) - (re-search-forward regexp) + (if backward + (re-search-backward regexp) + (re-search-forward regexp)) (setq found nil))) - (unless found + (unless (or found bound) (unwind-protect ;; Try other subfiles. (let ((list ())) @@ -1498,29 +1510,39 @@ ;; Find the subfile we just searched. (search-forward (concat "\n" osubfile ": ")) ;; Skip that one. - (forward-line 1) + (forward-line (if backward 0 1)) ;; Make a list of all following subfiles. ;; Each elt has the form (VIRT-POSITION . SUBFILENAME). - (while (not (eobp)) - (re-search-forward "\\(^.*\\): [0-9]+$") + (while (not (if backward (bobp) (eobp))) + (if backward + (re-search-backward "\\(^.*\\): [0-9]+$") + (re-search-forward "\\(^.*\\): [0-9]+$")) (goto-char (+ (match-end 1) 2)) (setq list (cons (cons (+ (point-min) (read (current-buffer))) (match-string-no-properties 1)) list)) - (goto-char (1+ (match-end 0)))) + (goto-char (if backward + (1- (match-beginning 0)) + (1+ (match-end 0))))) ;; Put in forward order (setq list (nreverse list)))) (while list (message "Searching subfile %s..." (cdr (car list))) (Info-read-subfile (car (car list))) + (if backward (goto-char (point-max))) (setq list (cdr list)) (setq give-up nil found nil) (while (and (not give-up) (or (null found) - (isearch-range-invisible beg-found found))) - (if (re-search-forward regexp nil t) - (setq found (point) beg-found (match-beginning 0)) + (if backward + (isearch-range-invisible found beg-found) + (isearch-range-invisible beg-found found)))) + (if (if backward + (re-search-backward regexp nil t) + (re-search-forward regexp nil t)) + (setq found (point) beg-found (if backward (match-end 0) + (match-beginning 0))) (setq give-up t))) (if give-up (setq found nil)) @@ -1534,9 +1556,15 @@ (goto-char opoint) (Info-select-node) (set-window-start (selected-window) ostart))))) - (widen) - (goto-char found) - (Info-select-node) + (if (and (string= ofile Info-current-file) + (string= onode Info-current-node) + (> found opoint-min) + (< found opoint-max)) + (goto-char found) + (widen) + (goto-char found) + (save-match-data (Info-select-node))) + ;; Use string-equal, not equal, to ignore text props. (or (and (string-equal onode Info-current-node) (equal ofile Info-current-file)) @@ -1556,6 +1584,50 @@ (if Info-search-history (Info-search (car Info-search-history)) (call-interactively 'Info-search)))) + +(defun Info-search-backward (regexp &optional bound noerror count) + "Search for REGEXP in the reverse direction." + (interactive (list (read-string + (if Info-search-history + (format "Regexp search%s backward (default `%s'): " + (if case-fold-search "" " case-sensitively") + (car Info-search-history)) + (format "Regexp search%s backward: " + (if case-fold-search "" " case-sensitively"))) + nil 'Info-search-history))) + (Info-search regexp bound noerror count 'backward)) + +(defun Info-isearch-search-function () + (cond + (isearch-word + (if isearch-forward 'word-search-forward 'word-search-backward)) + (isearch-regexp + (lambda (regexp bound noerror) + (condition-case nil + (progn + (Info-search regexp bound noerror nil + (unless isearch-forward 'backward)) + (point)) + (error nil)))) + (t + (if isearch-forward 'search-forward 'search-backward)))) + +(defun Info-isearch-wrap-function () + (if isearch-regexp + (if isearch-forward (Info-top-node) (Info-final-node)) + (goto-char (if isearch-forward (point-min) (point-max))))) + +(defun Info-isearch-push-state-function () + (list Info-current-file Info-current-node)) + +(defun Info-isearch-pop-state-function (cmd) + (let ((file (car (nth 12 cmd))) + (node (cadr (nth 12 cmd)))) + (or (and (string= Info-current-file file) + (string= Info-current-node node)) + (Info-find-node file node))) + (goto-char (car (cdr (cdr cmd))))) + (defun Info-extract-pointer (name &optional errorname) "Extract the value of the node-pointer named NAME. @@ -3064,6 +3136,16 @@ (setq desktop-save-buffer 'Info-desktop-buffer-misc-data) (add-hook 'clone-buffer-hook 'Info-clone-buffer-hook nil t) (add-hook 'change-major-mode-hook 'font-lock-defontify nil t) + (set (make-local-variable 'isearch-search-fun-function) + 'Info-isearch-search-function) + (set (make-local-variable 'isearch-wrap-function) + 'Info-isearch-wrap-function) + (set (make-local-variable 'isearch-push-state-function) + 'Info-isearch-push-state-function) + (set (make-local-variable 'isearch-pop-state-function) + 'Info-isearch-pop-state-function) (Info-set-mode-line) (run-hooks 'Info-mode-hook)) -- Juri Linkov http://www.jurta.org/emacs/