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