home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / vm / vm-5.33beta / vm-search.el < prev    next >
Encoding:
Text File  |  1991-04-21  |  14.8 KB  |  417 lines

  1. ;; Incremental search through a mail folder
  2. ;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
  3.  
  4. ;; This file is part of GNU Emacs.
  5.  
  6. ;; GNU Emacs is distributed in the hope that it will be useful,
  7. ;; but WITHOUT ANY WARRANTY.  No author or distributor
  8. ;; accepts responsibility to anyone for the consequences of using it
  9. ;; or for whether it serves any particular purpose or works at all,
  10. ;; unless he says so in writing.  Refer to the GNU Emacs General Public
  11. ;; License for full details.
  12.  
  13. ;; Everyone is granted permission to copy, modify and redistribute
  14. ;; GNU Emacs, but only under the conditions described in the
  15. ;; GNU Emacs General Public License.   A copy of this license is
  16. ;; supposed to have been given to you along with GNU Emacs so you
  17. ;; can know your rights and responsibilities.  It should be in a
  18. ;; file named COPYING.  Among other things, the copyright notice
  19. ;; and this notice must be preserved on all copies.
  20.  
  21.  
  22. ;; Adapted for the VM mail reader, Kyle Jones, May 1989
  23.  
  24.  
  25. ;; This function does all the work of incremental search.
  26. ;; The functions attached to ^R and ^S are trivial,
  27. ;; merely calling this one, but they are always loaded by default
  28. ;; whereas this file can optionally be autoloadable.
  29. ;; This is the only entry point in this file.
  30.  
  31. (defun vm-isearch (forward &optional regexp)
  32.   (let ((search-string "")
  33.     (search-message "")
  34.     (cmds nil)
  35.     (success t)
  36.     (wrapped nil)
  37.     (barrier (point))
  38.     adjusted
  39.     (invalid-regexp nil)
  40.     (slow-terminal-mode (and (<= (baud-rate) search-slow-speed)
  41.                  (> (window-height)
  42.                     (* 4 search-slow-window-lines))))
  43.     (other-end nil)    ;Start of last match if fwd, end if backwd.
  44.     (small-window nil)        ;if t, using a small window
  45.     (found-point nil)        ;to restore point from a small window
  46.     ;; This is the window-start value found by the search.
  47.     (found-start nil)
  48.     (opoint (point))
  49.     (vm-ml-attributes-string vm-ml-attributes-string)
  50.     (vm-ml-message-number vm-ml-message-number)
  51.     (vm-message-pointer vm-message-pointer)
  52.     (inhibit-quit t))  ;Prevent ^G from quitting immediately.
  53.     (vm-isearch-push-state)
  54.     (save-window-excursion
  55.      (catch 'search-done
  56.        (while t
  57.      (or (>= unread-command-char 0)
  58.          (progn
  59.            (or (input-pending-p)
  60.            (vm-isearch-message))
  61.            (if (and slow-terminal-mode
  62.             (not (or small-window (pos-visible-in-window-p))))
  63.            (progn
  64.              (setq small-window t)
  65.              (setq found-point (point))
  66.              (move-to-window-line 0)
  67.              (let ((window-min-height 1))
  68.                (split-window nil (if (< search-slow-window-lines 0)
  69.                          (1+ (- search-slow-window-lines))
  70.                        (- (window-height)
  71.                           (1+ search-slow-window-lines)))))
  72.              (if (< search-slow-window-lines 0)
  73.              (progn (vertical-motion (- 1 search-slow-window-lines))
  74.                 (set-window-start (next-window) (point))
  75.                 (set-window-hscroll (next-window)
  76.                             (window-hscroll))
  77.                 (set-window-hscroll (selected-window) 0))
  78.                (other-window 1))
  79.              (goto-char found-point)))))
  80.      (let ((char (if quit-flag
  81.              ?\C-g
  82.                (read-char))))
  83.        (setq quit-flag nil adjusted nil)
  84.        ;; Meta character means exit search.
  85.        (cond ((and (>= char 128)
  86.                search-exit-option)
  87.           (setq unread-command-char char)
  88.           (throw 'search-done t))
  89.          ((eq char search-exit-char)
  90.           ;; Esc means exit search normally.
  91.           ;; Except, if first thing typed, it means do nonincremental
  92.           (if (= 0 (length search-string))
  93.               (vm-nonincremental-search forward regexp))
  94.           (throw 'search-done t))
  95.          ((= char ?\C-g)
  96.           ;; ^G means the user tried to quit.
  97.           (ding)
  98.           (discard-input)
  99.           (if success
  100.               ;; If search is successful, move back to starting point
  101.               ;; and really do quit.
  102.               (progn (goto-char opoint)
  103.                  (vm-update-search-position)
  104.                  (signal 'quit nil))
  105.             ;; If search is failing, rub out until it is once more
  106.             ;;  successful.
  107.             (while (not success) (vm-isearch-pop))))
  108.          ((or (eq char search-repeat-char)
  109.               (eq char search-reverse-char))
  110.           (if (eq forward (eq char search-repeat-char))
  111.               ;; C-s in forward or C-r in reverse.
  112.               (if (equal search-string "")
  113.               ;; If search string is empty, use last one.
  114.               (setq search-string
  115.                 (if regexp
  116.                     search-last-regexp search-last-string)
  117.                 search-message
  118.                 (mapconcat 'text-char-description
  119.                        search-string ""))
  120.             ;; If already have what to search for, repeat it.
  121.             (or success
  122.                 (progn (goto-char (if forward (point-min) (point-max)))
  123.                    (setq wrapped t))))
  124.             ;; C-s in reverse or C-r in forward, change direction.
  125.             (setq forward (not forward)))
  126.           (setq barrier (point)) ; For subsequent \| if regexp.
  127.           (setq success t)
  128.           (or (equal search-string "")
  129.               (vm-isearch-search))
  130.           (vm-isearch-push-state))
  131.          ((= char search-delete-char)
  132.           ;; Rubout means discard last input item and move point
  133.           ;; back.  If buffer is empty, just beep.
  134.           (if (null (cdr cmds))
  135.               (ding)
  136.             (vm-isearch-pop)))
  137.          (t
  138.           (cond ((or (eq char search-yank-word-char)
  139.                  (eq char search-yank-line-char))
  140.              ;; ^W means gobble next word from buffer.
  141.              ;; ^Y means gobble rest of line from buffer.
  142.              (let ((word (save-excursion
  143.                        (and (not forward) other-end
  144.                         (goto-char other-end))
  145.                        (buffer-substring
  146.                     (point)
  147.                     (save-excursion
  148.                       (if (eq char search-yank-line-char)
  149.                           (end-of-line)
  150.                         (forward-word 1))
  151.                       (point))))))
  152.                (setq search-string (concat search-string word)
  153.                  search-message
  154.                    (concat search-message
  155.                        (mapconcat 'text-char-description
  156.                               word "")))))
  157.              ;; Any other control char =>
  158.              ;;  unread it and exit the search normally.
  159.              ((and search-exit-option
  160.                    (/= char search-quote-char)
  161.                    (or (= char ?\177)
  162.                    (and (< char ? ) (/= char ?\t) (/= char ?\r))))
  163.               (setq unread-command-char char)
  164.               (throw 'search-done t))
  165.              (t
  166.               ;; Any other character => add it to the
  167.               ;;  search string and search.
  168.               (cond ((= char search-quote-char)
  169.                  (setq char (read-quoted-char
  170.                          (vm-isearch-message t))))
  171.                 ((= char ?\r)
  172.                  ;; unix braindeath
  173.                  (setq char ?\n)))
  174.               (setq search-string (concat search-string
  175.                               (char-to-string char))
  176.                 search-message (concat search-message
  177.                                (text-char-description char)))))
  178.           (if (and (not success)
  179.                ;; unsuccessful regexp search may become
  180.                ;;  successful by addition of characters which
  181.                ;;  make search-string valid
  182.                (not regexp))
  183.               nil
  184.             ;; If a regexp search may have been made more
  185.             ;; liberal, retreat the search start.
  186.             ;; Go back to place last successful search started
  187.             ;; or to the last ^S/^R (barrier), whichever is nearer.
  188.             (and regexp success cmds
  189.              (cond ((memq char '(?* ??))
  190.                 (setq adjusted t)
  191.                 (let ((cs (nth (if forward
  192.                            5 ; other-end
  193.                          2) ; saved (point)
  194.                            (car (cdr cmds)))))
  195.                   ;; (car cmds) is after last search;
  196.                   ;; (car (cdr cmds)) is from before it.
  197.                   (setq cs (or cs barrier))
  198.                   (goto-char
  199.                    (if forward
  200.                        (max cs barrier)
  201.                      (min cs barrier)))))
  202.                    ((eq char ?\|)
  203.                 (setq adjusted t)
  204.                 (goto-char barrier))))
  205.             ;; In reverse regexp search, adding a character at
  206.             ;; the end may cause zero or many more chars to be
  207.             ;; matched, in the string following point.
  208.             ;; Allow all those possibiities without moving point as
  209.             ;; long as the match does not extend past search origin.
  210.             (if (and regexp (not forward) (not adjusted)
  211.                  (condition-case ()
  212.                  (looking-at search-string)
  213.                    (error nil))
  214.                  (<= (match-end 0) (min opoint barrier)))
  215.             (setq success t invalid-regexp nil
  216.                   other-end (match-end 0))
  217.               ;; Not regexp, not reverse, or no match at point.
  218.               (if (and other-end (not adjusted))
  219.               (goto-char (if forward other-end
  220.                        (min opoint barrier (1+ other-end)))))
  221.               (vm-isearch-search)))
  222.           (vm-isearch-push-state))))))
  223.      (setq found-start (window-start (selected-window)))
  224.      (setq found-point (point)))
  225.     (if (> (length search-string) 0)
  226.     (if regexp
  227.         (setq search-last-regexp search-string)
  228.         (setq search-last-string search-string)))
  229.     (message "")
  230.     (if small-window
  231.     (goto-char found-point)
  232.       ;; Exiting the save-window-excursion clobbers this; restore it.
  233.       (set-window-start (selected-window) found-start t))))
  234.  
  235. (defun vm-isearch-message (&optional c-q-hack ellipsis)
  236.   ;; If about to search, and previous search regexp was invalid,
  237.   ;; check that it still is.  If it is valid now,
  238.   ;; let the message we display while searching say that it is valid.
  239.   (and invalid-regexp ellipsis
  240.        (condition-case ()
  241.        (progn (re-search-forward search-string (point) t)
  242.           (setq invalid-regexp nil))
  243.      (error nil)))
  244.   ;; If currently failing, display no ellipsis.
  245.   (or success (setq ellipsis nil))
  246.   (let ((m (concat (if success "" "failing ")
  247.            (if wrapped "wrapped ")
  248.            (if regexp "regexp " "")
  249.            "VM I-search"
  250.            (if forward ": " " backward: ")
  251.            search-message
  252.            (if c-q-hack "^Q" "")
  253.            (if invalid-regexp
  254.                (concat " [" invalid-regexp "]")
  255.              ""))))
  256.     (aset m 0 (upcase (aref m 0)))
  257.     (let ((cursor-in-echo-area ellipsis))
  258.       (if c-q-hack m (message "%s" m)))))
  259.  
  260. (defun vm-isearch-pop ()
  261.   (setq cmds (cdr cmds))
  262.   (let ((cmd (car cmds)))
  263.     (setq search-string (car cmd)
  264.       search-message (car (cdr cmd))
  265.       success (nth 3 cmd)
  266.       forward (nth 4 cmd)
  267.       other-end (nth 5 cmd)
  268.       invalid-regexp (nth 6 cmd)
  269.       wrapped (nth 7 cmd)
  270.       barrier (nth 8 cmd)
  271.       vm-ml-attributes-string (nth 9 cmd)
  272.       vm-ml-message-number (nth 10 cmd)
  273.       vm-message-pointer (nth 11 cmd))
  274.     (if vm-summary-buffer
  275.     (save-excursion
  276.       (set-buffer vm-summary-buffer)
  277.       (setq vm-ml-attributes-string (nth 9 cmd)
  278.         vm-ml-message-number (nth 10 cmd))))
  279.     (goto-char (car (cdr (cdr cmd))))
  280.     (vm-set-summary-pointer (car vm-message-pointer))))
  281.  
  282. (defun vm-isearch-push-state ()
  283.   (setq cmds (cons (list search-string search-message (point)
  284.              success forward other-end invalid-regexp
  285.              wrapped barrier
  286.              vm-ml-attributes-string vm-ml-message-number
  287.              vm-message-pointer)
  288.            cmds)))
  289.  
  290. (defun vm-isearch-search ()
  291.   (vm-isearch-message nil t)
  292.   (condition-case lossage
  293.       (let ((inhibit-quit nil))
  294.     (if regexp (setq invalid-regexp nil))
  295.     (setq success
  296.           (funcall
  297.            (if regexp
  298.            (if forward 're-search-forward 're-search-backward)
  299.          (if forward 'search-forward 'search-backward))
  300.            search-string nil t))
  301.     (if success
  302.         (setq other-end
  303.           (if forward (match-beginning 0) (match-end 0)))))
  304.     (quit (setq unread-command-char ?\C-g)
  305.       (setq success nil))
  306.     (invalid-regexp (setq invalid-regexp (car (cdr lossage)))
  307.             (if (string-match "\\`Premature \\|\\`Unmatched \\|\\`Invalid "
  308.                       invalid-regexp)
  309.             (setq invalid-regexp "incomplete input"))))
  310.   (if success
  311.       (vm-update-search-position)
  312.     ;; Ding if failed this time after succeeding last time.
  313.     (and (nth 3 (car cmds))
  314.      (ding))
  315.     (goto-char (nth 2 (car cmds)))))
  316.  
  317. ;; This is called from incremental-search
  318. ;; if the first input character is the exit character.
  319. ;; The interactive-arg-reader uses free variables `forward' and `regexp'
  320. ;; which are bound by `incremental-search'.
  321.  
  322. ;; We store the search string in `search-string'
  323. ;; which has been bound already by `incremental-search'
  324. ;; so that, when we exit, it is copied into `search-last-string'.
  325.  
  326. (defun vm-nonincremental-search (forward regexp)
  327.   (let (message char function string inhibit-quit
  328.         (cursor-in-echo-area t))
  329.     ;; Prompt assuming not word search,
  330.     (setq message (if regexp 
  331.               (if forward "VM Regexp search: "
  332.             "VM Regexp search backward: ")
  333.             (if forward "VM Search: " "VM Search backward: ")))
  334.     (message "%s" message)
  335.     ;; Read 1 char and switch to word search if it is ^W.
  336.     (setq char (read-char))
  337.     (if (eq char search-yank-word-char)
  338.     (setq message (if forward "VM Word search: " "VM Word search backward: "))
  339.       ;; Otherwise let that 1 char be part of the search string.
  340.       (setq unread-command-char char))
  341.     (setq function
  342.       (if (eq char search-yank-word-char)
  343.           (if forward 'word-search-forward 'word-search-backward)
  344.         (if regexp
  345.         (if forward 're-search-forward 're-search-backward)
  346.           (if forward 'search-forward 'search-backward))))
  347.     ;; Read the search string with corrected prompt.
  348.     (setq string (read-string message))
  349.     ;; Empty means use default.
  350.     (if (= 0 (length string))
  351.     (setq string search-last-string)
  352.       ;; Set last search string now so it is set even if we fail.
  353.       (setq search-last-string string))
  354.     ;; Since we used the minibuffer, we should be available for redo.
  355.     (setq command-history (cons (list function string) command-history))
  356.     ;; Go ahead and search.
  357.     (funcall function string)))
  358.  
  359. (defun vm-update-search-position (&optional record-change)
  360.   (if (and (>= (point) (vm-start-of (car vm-message-pointer)))
  361.        (<= (point) (vm-end-of (car vm-message-pointer))))
  362.       nil
  363.     (let ((mp vm-message-list)
  364.       (point (point)))
  365.       (while mp
  366.     (if (and (>= point (vm-start-of (car mp)))
  367.          (<= point (vm-end-of (car mp))))
  368.         (if record-change
  369.         (progn
  370.           (vm-record-and-change-message-pointer vm-message-pointer mp)
  371.           (setq mp nil))
  372.           (setq vm-message-pointer mp mp nil))
  373.       (setq mp (cdr mp))))
  374.       (setq vm-need-summary-pointer-update t)
  375.       (vm-update-summary-and-mode-line))))
  376.  
  377. (defun vm-isearch-forward ()
  378.   "Incrementally search forward through the current folder's messages.
  379. Usage is identical to the standard Emacs incremental search.
  380. When the search terminates the message containing point will be selected.
  381.  
  382. If the variable vm-search-using-regexps is non-nil, regular expressions
  383. are understood; nil means the search will be for the input string taken
  384. literally."
  385.   (interactive)
  386.   (vm-follow-summary-cursor)
  387.   (vm-select-folder-buffer)
  388.   (vm-check-for-killed-summary)
  389.   (vm-error-if-folder-empty)
  390.   (vm-set-window-configuration 'searching-folder)
  391.   (if (null (get-buffer-window (current-buffer)))
  392.       (vm-display-current-message-buffer))
  393.   (let ((clip-head (point-min))
  394.     (clip-tail (point-max))
  395.     (old-w (selected-window)))
  396.     (unwind-protect
  397.     (progn (select-window (get-buffer-window (current-buffer)))
  398.            (widen)
  399.            (vm-isearch t vm-search-using-regexps)
  400.            (vm-update-search-position t)
  401.            ;; vm-show-current-message only adjusts (point-max),
  402.            ;; it doesn't change (point-min).
  403.            (narrow-to-region
  404.         (if (< (point) (vm-vheaders-of (car vm-message-pointer)))
  405.             (vm-start-of (car vm-message-pointer))
  406.           (vm-vheaders-of (car vm-message-pointer)))
  407.         (point-max))
  408.            (vm-highlight-headers (car vm-message-pointer)
  409.                      (get-buffer-window (current-buffer)))
  410.            (vm-show-current-message)
  411.            (setq vm-system-state 'reading)
  412.            ;; turn the clipping unwind into a noop
  413.            (setq clip-head (point-min))
  414.            (setq clip-tail (point-max)))
  415.       (narrow-to-region clip-head clip-tail)
  416.       (select-window old-w))))
  417.