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