[Top][All Lists]

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

Re: isearch hooks

From: Juri Linkov
Subject: Re: isearch hooks
Date: Sat, 19 Jun 2004 21:36:18 +0300
User-agent: Gnus/5.110002 (No Gnus v0.2) Emacs/21.3.50 (gnu/linux)

Richard Stallman <address@hidden> writes:
>     The patch below adds two hooks `isearch-wrapped-hook' and
>     `isearch-failed-hook'.
> Thanks for working on it.
> However, I have a feeling that `isearch-failed-hook' is not
> implemented properly for the intended use.  If isearch should move
> between info nodes, the natural way is that a failing search should
> switch nodes and then try again.  To do that, this hook should run
> shortly after the actual search primitive, and it should be run with
> run-hook-with-args-until-success, and if it succeeds then
> isearch-success should be t--as if the search primitive had succeeded.
> So it won't put "Failed " in the echo area, for instance.

This seems to be the right place to call the hook.

> I just looked at isearch.el and came across isearch-search-fun-function.
> I have a feeling that the right way to make isearch search through
> multiple nodes or buffers is to define a new low-level search function
> and interface it through isearch-search-fun-function.
> Does that look right to you?

It doesn't look right since `isearch-search-fun' is used to specify
the function to call for the search different from the default
`search-forward' or `re-search-forward'.  But in the intended cases
default functions are suitable to search the text in the buffer.
What is needed is to switch locations on the search when the search
in the current buffers is failed.

In the newest version I added a new variable `isearch-wrap-failed'.
If it is set to non-nil the search will not pause for displaying the
message "Failing I-search..." but will immediately wrap the search
to the location found by `isearch-wrap-functions'.

If `isearch-wrap-failed' is nil and `isearch-wrap-functions' are
specified, these hooks are called in another place, where currently
the point is moved to the beginning/end of the buffer.

And below is the hook which works for moving between Info nodes.
It sets isearch-cmds to nil, because it's impossible to restore
previous positions in visited Info nodes by typing DEL in isearch mode.

If it is ok, it could be added to info.el to be activated by some option
or minor mode.

(add-hook 'isearch-wrap-functions
          (lambda ()
            (Info-search isearch-string (unless isearch-forward 'backward))
            (goto-char (if isearch-forward (point-min) (point-max)))
            (setq isearch-cmds nil)
          nil t)

(set (make-local-variable 'isearch-wrap-failed) t)

There is also the patch to info.el below after isearch.el
which implements a backward search in Info mode.

Index: lisp/isearch.el
RCS file: /cvsroot/emacs/emacs/lisp/isearch.el,v
retrieving revision 1.228
diff -u -r1.228 isearch.el
--- lisp/isearch.el     6 Jun 2004 13:57:39 -0000       1.228
+++ lisp/isearch.el     19 Jun 2004 18:02:39 -0000
@@ -199,6 +157,14 @@
 (defvar isearch-mode-end-hook nil
   "Function(s) to call after terminating an incremental search.")
+(defvar isearch-wrap-functions nil
+  "Function(s) 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-wrap-failed nil
+  "If non-nil, search is wrapped immediately after failing.")
 ;; Search ring.
 (defvar search-ring nil
@@ -990,8 +967,12 @@
        ;; If already have what to search for, repeat it.
        (or isearch-success
-             (goto-char (if isearch-forward (point-min) (point-max)))
-             (setq isearch-wrapped t))))
+             ;; `isearch-search' takes care of the following condition
+             (when (not (and isearch-wrap-functions isearch-wrap-failed))
+                (if isearch-wrap-functions
+                    (run-hook-with-args-until-success 'isearch-wrap-functions)
+                  (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)))
@@ -1786,6 +1885,7 @@
   (or isearch-success (setq ellipsis nil))
   (let ((m (concat (if isearch-success "" "failing ")
                   (if (and isearch-wrapped
+                           (not isearch-wrap-functions)
                            (if isearch-forward
                                (> (point) isearch-opoint)
                              (< (point) isearch-opoint)))
@@ -1836,7 +1939,8 @@
       (let ((inhibit-point-motion-hooks search-invisible)
            (inhibit-quit nil)
            (case-fold-search isearch-case-fold-search)
-           (retry t))
+           (retry t)
+           (m nil))
        (if isearch-regexp (setq isearch-invalid-regexp nil))
        (setq isearch-within-brackets nil)
        (while retry
@@ -1852,7 +1956,15 @@
                  (= (match-beginning 0) (match-end 0))
                  (not (isearch-range-invisible
                        (match-beginning 0) (match-end 0))))
-             (setq retry nil)))
+             (setq retry nil))
+          (if (and isearch-wrap-failed isearch-wrap-functions
+                  (not isearch-success)
+                  (not (and (markerp m)
+                            (eq (marker-buffer m) (current-buffer))
+                            (eq (marker-position m) (point))))
+                  (run-hook-with-args-until-success
+                   'isearch-wrap-functions))
+             (setq retry t m (point-marker) isearch-wrapped t)))
        (setq isearch-just-started nil)
        (if isearch-success
            (setq isearch-other-end
@@ -1878,7 +1990,8 @@
     ;; Ding if failed this time after succeeding last time.
     (and (nth 3 (car isearch-cmds))
-    (goto-char (nth 2 (car isearch-cmds)))))
+    (and (nth 2 (car isearch-cmds))
+        (goto-char (nth 2 (car isearch-cmds))))))
 ;; Called when opening an overlay, and we are still in isearch.

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        19 Jun 2004 18:31:05 -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 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,6 +1459,7 @@
     (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))
@@ -1472,14 +1474,21 @@
          (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 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
@@ -1498,29 +1507,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))
-                   (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))
@@ -1556,6 +1575,19 @@
     (if Info-search-history
         (Info-search (car Info-search-history))
       (call-interactively 'Info-search))))
+(defun Info-search-backward (regexp)
+  "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 'backward))
 (defun Info-extract-pointer (name &optional errorname)
   "Extract the value of the node-pointer named NAME.

Juri Linkov

reply via email to

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