emacs-devel
[Top][All Lists]
Advanced

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

Re: isearch hooks


From: Juri Linkov
Subject: Re: isearch hooks
Date: Fri, 25 Jun 2004 21:07:38 +0300
User-agent: Gnus/5.110002 (No Gnus v0.2) Emacs/21.3.50 (gnu/linux)

Richard Stallman <address@hidden> 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/





reply via email to

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