comparison lisp/mh-e/mh-seq.el @ 50702:7dd3d5eae9c7

Upgraded to MH-E version 7.3. See etc/MH-E-NEWS and lisp/mh-e/ChangeLog for details.
author Bill Wohler <wohler@newt.com>
date Fri, 25 Apr 2003 05:52:00 +0000
parents b35587af8747
children 695cf19ef79e
comparison
equal deleted inserted replaced
50701:cb5f0a5d5b36 50702:7dd3d5eae9c7
1 ;;; mh-seq.el --- MH-E sequences support 1 ;;; mh-seq.el --- MH-E sequences support
2 2
3 ;; Copyright (C) 1993, 1995, 2001, 2002 Free Software Foundation, Inc. 3 ;; Copyright (C) 1993, 1995, 2001, 02, 2003 Free Software Foundation, Inc.
4 4
5 ;; Author: Bill Wohler <wohler@newt.com> 5 ;; Author: Bill Wohler <wohler@newt.com>
6 ;; Maintainer: Bill Wohler <wohler@newt.com> 6 ;; Maintainer: Bill Wohler <wohler@newt.com>
7 ;; Keywords: mail 7 ;; Keywords: mail
8 ;; See: mh-e.el 8 ;; See: mh-e.el
66 66
67 ;; Internal support for MH-E package. 67 ;; Internal support for MH-E package.
68 68
69 ;;; Change Log: 69 ;;; Change Log:
70 70
71 ;; $Id: mh-seq.el,v 1.101 2003/01/26 00:57:35 jchonig Exp $
72
73 ;;; Code: 71 ;;; Code:
74 72
75 (require 'cl) 73 (require 'cl)
76 (require 'mh-e) 74 (require 'mh-e)
77 75
144 (interactive (list (mh-read-seq-default "Delete" t))) 142 (interactive (list (mh-read-seq-default "Delete" t)))
145 (let ((msg-list (mh-seq-to-msgs sequence))) 143 (let ((msg-list (mh-seq-to-msgs sequence)))
146 (mh-undefine-sequence sequence '("all")) 144 (mh-undefine-sequence sequence '("all"))
147 (mh-delete-seq-locally sequence) 145 (mh-delete-seq-locally sequence)
148 (mh-iterate-on-messages-in-region msg (point-min) (point-max) 146 (mh-iterate-on-messages-in-region msg (point-min) (point-max)
149 (when (and (member msg msg-list) (not (mh-seq-containing-msg msg nil))) 147 (cond ((and mh-tick-seq (eq sequence mh-tick-seq))
150 (mh-notate nil ? (1+ mh-cmd-note)))))) 148 (mh-notate-tick msg ()))
149 ((and (member msg msg-list) (not (mh-seq-containing-msg msg nil)))
150 (mh-notate nil ? (1+ mh-cmd-note)))))))
151 151
152 ;; Avoid compiler warnings 152 ;; Avoid compiler warnings
153 (defvar view-exit-action) 153 (defvar view-exit-action)
154 154
155 ;;;###mh-autoload 155 ;;;###mh-autoload
193 (setq view-exit-action 'kill-buffer) 193 (setq view-exit-action 'kill-buffer)
194 (message "Listing sequences...done"))))) 194 (message "Listing sequences...done")))))
195 195
196 ;;;###mh-autoload 196 ;;;###mh-autoload
197 (defun mh-msg-is-in-seq (message) 197 (defun mh-msg-is-in-seq (message)
198 "Display the sequences that contain MESSAGE (default: current message)." 198 "Display the sequences that contain MESSAGE.
199 Default is the displayed message."
199 (interactive (list (mh-get-msg-num t))) 200 (interactive (list (mh-get-msg-num t)))
200 (let* ((dest-folder (loop for seq in mh-refile-list 201 (let* ((dest-folder (loop for seq in mh-refile-list
201 when (member message (cdr seq)) return (car seq))) 202 until (member message (cdr seq))
203 finally return (car seq)))
202 (deleted-flag (unless dest-folder (member message mh-delete-list)))) 204 (deleted-flag (unless dest-folder (member message mh-delete-list))))
203 (message "Message %d%s is in sequences: %s" 205 (message "Message %d%s is in sequences: %s"
204 message 206 message
205 (cond (dest-folder (format " (to be refiled to %s)" dest-folder)) 207 (cond (dest-folder (format " (to be refiled to %s)" dest-folder))
206 (deleted-flag (format " (to be deleted)")) 208 (deleted-flag (format " (to be deleted)"))
207 (t "")) 209 (t ""))
208 (mapconcat 'concat 210 (mapconcat 'concat
209 (mh-list-to-string (mh-seq-containing-msg message t)) 211 (mh-list-to-string (mh-seq-containing-msg message t))
210 " ")))) 212 " "))))
213
214 ;; Avoid compiler warning
215 (defvar tool-bar-map)
211 216
212 ;;;###mh-autoload 217 ;;;###mh-autoload
213 (defun mh-narrow-to-seq (sequence) 218 (defun mh-narrow-to-seq (sequence)
214 "Restrict display of this folder to just messages in SEQUENCE. 219 "Restrict display of this folder to just messages in SEQUENCE.
215 Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command." 220 Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command."
222 (msg-at-cursor (mh-get-msg-num nil))) 227 (msg-at-cursor (mh-get-msg-num nil)))
223 (setq mh-thread-old-scan-line-map mh-thread-scan-line-map) 228 (setq mh-thread-old-scan-line-map mh-thread-scan-line-map)
224 (setq mh-thread-scan-line-map (make-hash-table :test #'eql)) 229 (setq mh-thread-scan-line-map (make-hash-table :test #'eql))
225 (mh-copy-seq-to-eob sequence) 230 (mh-copy-seq-to-eob sequence)
226 (narrow-to-region eob (point-max)) 231 (narrow-to-region eob (point-max))
232 (setq mh-narrowed-to-seq sequence)
227 (mh-notate-user-sequences) 233 (mh-notate-user-sequences)
228 (mh-notate-deleted-and-refiled) 234 (mh-notate-deleted-and-refiled)
229 (mh-notate-cur) 235 (mh-notate-cur)
230 (when msg-at-cursor (mh-goto-msg msg-at-cursor t t)) 236 (when msg-at-cursor (mh-goto-msg msg-at-cursor t t))
231 (make-variable-buffer-local 'mh-non-seq-mode-line-annotation) 237 (make-variable-buffer-local 'mh-non-seq-mode-line-annotation)
232 (setq mh-non-seq-mode-line-annotation mh-mode-line-annotation) 238 (setq mh-non-seq-mode-line-annotation mh-mode-line-annotation)
233 (setq mh-mode-line-annotation (symbol-name sequence)) 239 (setq mh-mode-line-annotation (symbol-name sequence))
234 (mh-make-folder-mode-line) 240 (mh-make-folder-mode-line)
235 (mh-recenter nil) 241 (mh-recenter nil)
236 (if (and (boundp 'tool-bar-mode) tool-bar-mode) 242 (when (and (boundp 'tool-bar-mode) tool-bar-mode)
237 (set (make-local-variable 'tool-bar-map) 243 (set (make-local-variable 'tool-bar-map)
238 mh-folder-seq-tool-bar-map)) 244 mh-folder-seq-tool-bar-map)
239 (setq mh-narrowed-to-seq sequence) 245 (when (buffer-live-p (get-buffer mh-show-buffer))
246 (save-excursion
247 (set-buffer (get-buffer mh-show-buffer))
248 (set (make-local-variable 'tool-bar-map)
249 mh-show-seq-tool-bar-map))))
240 (push 'widen mh-view-ops))) 250 (push 'widen mh-view-ops)))
241 (t 251 (t
242 (error "No messages in sequence `%s'" (symbol-name sequence)))))) 252 (error "No messages in sequence `%s'" (symbol-name sequence))))))
243 253
244 ;;;###mh-autoload 254 ;;;###mh-autoload
245 (defun mh-put-msg-in-seq (msg-or-seq sequence) 255 (defun mh-put-msg-in-seq (msg-or-seq sequence)
246 "Add MSG-OR-SEQ (default: displayed message) to SEQUENCE. 256 "Add MSG-OR-SEQ to SEQUENCE.
247 If optional prefix argument provided, then prompt for the message sequence. 257 Default is the displayed message.
248 If variable `transient-mark-mode' is non-nil and the mark is active, then 258 If optional prefix argument is provided, then prompt for the message sequence.
249 the selected region is added to the sequence." 259 If variable `transient-mark-mode' is non-nil and the mark is active, then the
250 (interactive (list (cond 260 selected region is added to the sequence.
251 ((mh-mark-active-p t) 261 In a program, MSG-OR-SEQ can be a message number, a list of message numbers, a
252 (cons (region-beginning) (region-end))) 262 region in a cons cell, or a sequence."
253 (current-prefix-arg 263 (interactive (list (mh-interactive-msg-or-seq "Add messages from")
254 (mh-read-seq-default "Add messages from" t))
255 (t
256 (cons (line-beginning-position) (line-end-position))))
257 (mh-read-seq-default "Add to" nil))) 264 (mh-read-seq-default "Add to" nil)))
258 (let ((internal-seq-flag (mh-internal-seq sequence)) 265 (when (and (interactive-p) mh-tick-seq (eq sequence mh-tick-seq))
259 msg-list) 266 (error "Use `mh-toggle-tick' to add messages to %s" mh-tick-seq))
260 (cond ((and (consp msg-or-seq) 267 (let* ((internal-seq-flag (mh-internal-seq sequence))
261 (numberp (car msg-or-seq)) (numberp (cdr msg-or-seq))) 268 (note-seq (if internal-seq-flag nil mh-note-seq))
262 (mh-iterate-on-messages-in-region m (car msg-or-seq) (cdr msg-or-seq) 269 (msg-list ()))
263 (push m msg-list) 270 (mh-iterate-on-msg-or-seq m msg-or-seq
264 (unless internal-seq-flag 271 (push m msg-list)
265 (mh-notate nil mh-note-seq (1+ mh-cmd-note)))) 272 (mh-notate nil note-seq (1+ mh-cmd-note)))
266 (mh-add-msgs-to-seq msg-list sequence internal-seq-flag t)) 273 (mh-add-msgs-to-seq msg-list sequence nil t)
267 ((or (numberp msg-or-seq) (listp msg-or-seq))
268 (when (numberp msg-or-seq)
269 (setq msg-or-seq (list msg-or-seq)))
270 (mh-add-msgs-to-seq msg-or-seq sequence internal-seq-flag))
271 (t (mh-add-msgs-to-seq (mh-seq-to-msgs msg-or-seq) sequence)))
272 (if (not internal-seq-flag) 274 (if (not internal-seq-flag)
273 (setq mh-last-seq-used sequence)))) 275 (setq mh-last-seq-used sequence))
276 (when (and (eq sequence mh-unseen-seq) (mh-speed-flists-active-p))
277 (mh-speed-flists t mh-current-folder))))
274 278
275 (defun mh-valid-view-change-operation-p (op) 279 (defun mh-valid-view-change-operation-p (op)
276 "Check if the view change operation can be performed. 280 "Check if the view change operation can be performed.
277 OP is one of 'widen and 'unthread." 281 OP is one of 'widen and 'unthread."
278 (cond ((eq (car mh-view-ops) op) 282 (cond ((eq (car mh-view-ops) op)
298 (widen) 302 (widen)
299 (setq mh-mode-line-annotation mh-non-seq-mode-line-annotation) 303 (setq mh-mode-line-annotation mh-non-seq-mode-line-annotation)
300 (mh-make-folder-mode-line)) 304 (mh-make-folder-mode-line))
301 (if msg 305 (if msg
302 (mh-goto-msg msg t t)) 306 (mh-goto-msg msg t t))
307 (setq mh-narrowed-to-seq nil)
308 (setq mh-tick-seq-changed-when-narrowed-flag nil)
303 (mh-notate-deleted-and-refiled) 309 (mh-notate-deleted-and-refiled)
304 (mh-notate-user-sequences) 310 (mh-notate-user-sequences)
305 (mh-notate-cur) 311 (mh-notate-cur)
306 (mh-recenter nil))) 312 (mh-recenter nil)))
307 (if (and (boundp 'tool-bar-mode) tool-bar-mode) 313 (when (and (boundp 'tool-bar-mode) tool-bar-mode)
308 (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map)) 314 (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map)
309 (setq mh-narrowed-to-seq nil)) 315 (when (buffer-live-p (get-buffer mh-show-buffer))
316 (save-excursion
317 (set-buffer (get-buffer mh-show-buffer))
318 (set (make-local-variable 'tool-bar-map) mh-show-tool-bar-map)))))
310 319
311 ;; FIXME? We may want to clear all notations and add one for current-message 320 ;; FIXME? We may want to clear all notations and add one for current-message
312 ;; and process user sequences. 321 ;; and process user sequences.
313 (defun mh-notate-deleted-and-refiled () 322 (defun mh-notate-deleted-and-refiled ()
314 "Notate messages marked for deletion or refiling. 323 "Notate messages marked for deletion or refiling.
406 "Mark the MH sequence cur. 415 "Mark the MH sequence cur.
407 In addition to notating the current message with `mh-note-cur' the function 416 In addition to notating the current message with `mh-note-cur' the function
408 uses `overlay-arrow-position' to put a marker in the fringe." 417 uses `overlay-arrow-position' to put a marker in the fringe."
409 (let ((cur (car (mh-seq-to-msgs 'cur)))) 418 (let ((cur (car (mh-seq-to-msgs 'cur))))
410 (when (and cur (mh-goto-msg cur t t)) 419 (when (and cur (mh-goto-msg cur t t))
411 (mh-notate nil mh-note-cur mh-cmd-note)
412 (beginning-of-line) 420 (beginning-of-line)
421 (when (looking-at mh-scan-good-msg-regexp)
422 (mh-notate nil mh-note-cur mh-cmd-note))
413 (setq mh-arrow-marker (set-marker mh-arrow-marker (point))) 423 (setq mh-arrow-marker (set-marker mh-arrow-marker (point)))
414 (setq overlay-arrow-position mh-arrow-marker)))) 424 (setq overlay-arrow-position mh-arrow-marker))))
415 425
416 ;;;###mh-autoload 426 ;;;###mh-autoload
417 (defun mh-add-to-sequence (seq msgs) 427 (defun mh-add-to-sequence (seq msgs)
428 ;; doesn't hold. So we will do this the dumb way. 438 ;; doesn't hold. So we will do this the dumb way.
429 ;(defun mh-copy-seq-to-point (seq location) 439 ;(defun mh-copy-seq-to-point (seq location)
430 ; ;; Copy the scan listing of the messages in SEQUENCE to after the point 440 ; ;; Copy the scan listing of the messages in SEQUENCE to after the point
431 ; ;; LOCATION in the current buffer. 441 ; ;; LOCATION in the current buffer.
432 ; (mh-map-to-seq-msgs 'mh-copy-line-to-point seq location)) 442 ; (mh-map-to-seq-msgs 'mh-copy-line-to-point seq location))
443
444 (defvar mh-thread-last-ancestor)
433 445
434 (defun mh-copy-seq-to-eob (seq) 446 (defun mh-copy-seq-to-eob (seq)
435 "Copy SEQ to the end of the buffer." 447 "Copy SEQ to the end of the buffer."
436 ;; It is quite involved to write something which will work at any place in 448 ;; It is quite involved to write something which will work at any place in
437 ;; the buffer, so we will write something which works only at the end of 449 ;; the buffer, so we will write something which works only at the end of
453 (setf (gethash msg mh-thread-scan-line-map) 465 (setf (gethash msg mh-thread-scan-line-map)
454 (mh-thread-parse-scan-line)))) 466 (mh-thread-parse-scan-line))))
455 (forward-line)) 467 (forward-line))
456 ;; Remove scan lines and read results from pre-computed tree 468 ;; Remove scan lines and read results from pre-computed tree
457 (delete-region (point-min) (point-max)) 469 (delete-region (point-min) (point-max))
458 (let ((thread-tree (mh-thread-generate mh-current-folder ())) 470 (mh-thread-print-scan-lines
459 (mh-thread-body-width 471 (mh-thread-generate mh-current-folder ())))
460 (- (window-width) mh-cmd-note
461 (1- mh-scan-field-subject-start-offset)))
462 (mh-thread-last-ancestor nil))
463 (mh-thread-generate-scan-lines thread-tree -2)))
464 (mh-index-data 472 (mh-index-data
465 (mh-index-insert-folder-headers))))))) 473 (mh-index-insert-folder-headers)))))))
466 474
467 (defun mh-copy-line-to-point (msg location) 475 (defun mh-copy-line-to-point (msg location)
468 "Copy current message line to a specific location. 476 "Copy current message line to a specific location.
489 (unless (symbolp var) 497 (unless (symbolp var)
490 (error "Can not bind the non-symbol %s" var)) 498 (error "Can not bind the non-symbol %s" var))
491 (let ((binding-needed-flag var)) 499 (let ((binding-needed-flag var))
492 `(save-excursion 500 `(save-excursion
493 (goto-char ,begin) 501 (goto-char ,begin)
502 (beginning-of-line)
494 (while (and (<= (point) ,end) (not (eobp))) 503 (while (and (<= (point) ,end) (not (eobp)))
495 (when (looking-at mh-scan-valid-regexp) 504 (when (looking-at mh-scan-valid-regexp)
496 (let ,(if binding-needed-flag `((,var (mh-get-msg-num t))) ()) 505 (let ,(if binding-needed-flag `((,var (mh-get-msg-num t))) ())
497 ,@body)) 506 ,@body))
498 (forward-line 1))))) 507 (forward-line 1)))))
508
509 (put 'mh-iterate-on-messages-in-region 'lisp-indent-hook 'defun)
510
511 ;;;###mh-autoload
512 (defmacro mh-iterate-on-msg-or-seq (var msg-or-seq &rest body)
513 "Iterate an operation over a region or sequence.
514
515 VAR is bound to each message in turn in a loop over MSG-OR-SEQ, which can be a
516 message number, a list of message numbers, a sequence, or a region in a cons
517 cell. In each iteration, BODY is executed.
518
519 The parameter MSG-OR-SEQ is usually created with `mh-interactive-msg-or-seq'
520 in order to provide a uniform interface to MH-E functions."
521 (unless (symbolp var)
522 (error "Can not bind the non-symbol %s" var))
523 (let ((binding-needed-flag var)
524 (msgs (make-symbol "msgs"))
525 (seq-hash-table (make-symbol "seq-hash-table")))
526 `(cond ((numberp ,msg-or-seq)
527 (when (mh-goto-msg ,msg-or-seq t t)
528 (let ,(if binding-needed-flag `((,var ,msg-or-seq)) ())
529 ,@body)))
530 ((and (consp ,msg-or-seq)
531 (numberp (car ,msg-or-seq)) (numberp (cdr ,msg-or-seq)))
532 (mh-iterate-on-messages-in-region ,var
533 (car ,msg-or-seq) (cdr ,msg-or-seq)
534 ,@body))
535 (t (let ((,msgs (if (and ,msg-or-seq (symbolp ,msg-or-seq))
536 (mh-seq-to-msgs ,msg-or-seq)
537 ,msg-or-seq))
538 (,seq-hash-table (make-hash-table)))
539 (dolist (msg ,msgs)
540 (setf (gethash msg ,seq-hash-table) t))
541 (mh-iterate-on-messages-in-region v (point-min) (point-max)
542 (when (gethash v ,seq-hash-table)
543 (let ,(if binding-needed-flag `((,var v)) ())
544 ,@body))))))))
545
546 (put 'mh-iterate-on-msg-or-seq 'lisp-indent-hook 'defun)
547
548 ;;;###mh-autoload
549 (defun mh-msg-or-seq-to-msg-list (msg-or-seq)
550 "Return a list of messages for MSG-OR-SEQ.
551 MSG-OR-SEQ can be a message number, a list of message numbers, a sequence, or
552 a region in a cons cell."
553 (let (msg-list)
554 (mh-iterate-on-msg-or-seq msg msg-or-seq
555 (push msg msg-list))
556 (nreverse msg-list)))
557
558 ;;;###mh-autoload
559 (defun mh-interactive-msg-or-seq (sequence-prompt)
560 "Return interactive specification for message, sequence, or region.
561 By convention, the name of this argument is msg-or-seq.
562
563 If variable `transient-mark-mode' is non-nil and the mark is active, then this
564 function returns a cons-cell of the region.
565 If optional prefix argument provided, then prompt for message sequence with
566 SEQUENCE-PROMPT and return sequence.
567 Otherwise, the message number at point is returned.
568
569 This function is usually used with `mh-iterate-on-msg-or-seq' in order to
570 provide a uniform interface to MH-E functions."
571 (cond
572 ((mh-mark-active-p t)
573 (cons (region-beginning) (region-end)))
574 (current-prefix-arg
575 (mh-read-seq-default sequence-prompt t))
576 (t
577 (mh-get-msg-num t))))
499 578
500 ;;;###mh-autoload 579 ;;;###mh-autoload
501 (defun mh-region-to-msg-list (begin end) 580 (defun mh-region-to-msg-list (begin end)
502 "Return a list of messages within the region between BEGIN and END." 581 "Return a list of messages within the region between BEGIN and END."
503 ;; If end is end of buffer back up one position 582 ;; If end is end of buffer back up one position
1003 (forward-line))) 1082 (forward-line)))
1004 (let ((thread-tree (mh-thread-generate folder msg-list)) 1083 (let ((thread-tree (mh-thread-generate folder msg-list))
1005 (buffer-read-only nil) 1084 (buffer-read-only nil)
1006 (old-buffer-modified-flag (buffer-modified-p))) 1085 (old-buffer-modified-flag (buffer-modified-p)))
1007 (delete-region (point-min) (point-max)) 1086 (delete-region (point-min) (point-max))
1008 (let ((mh-thread-body-width (- (window-width) mh-cmd-note 1087 (mh-thread-print-scan-lines thread-tree)
1009 (1- mh-scan-field-subject-start-offset)))
1010 (mh-thread-last-ancestor nil))
1011 (mh-thread-generate-scan-lines thread-tree -2))
1012 (mh-notate-user-sequences) 1088 (mh-notate-user-sequences)
1013 (mh-notate-deleted-and-refiled) 1089 (mh-notate-deleted-and-refiled)
1014 (mh-notate-cur) 1090 (mh-notate-cur)
1015 (set-buffer-modified-p old-buffer-modified-flag)))) 1091 (set-buffer-modified-p old-buffer-modified-flag))))
1016
1017 (defvar mh-thread-last-ancestor)
1018 1092
1019 (defun mh-thread-generate-scan-lines (tree level) 1093 (defun mh-thread-generate-scan-lines (tree level)
1020 "Generate scan lines. 1094 "Generate scan lines.
1021 TREE is the hierarchical tree of messages, SCAN-LINE-MAP maps message indices 1095 TREE is the hierarchical tree of messages, SCAN-LINE-MAP maps message indices
1022 to the corresponding scan lines and LEVEL used to determine indentation of 1096 to the corresponding scan lines and LEVEL used to determine indentation of
1097 (when (numberp msg-num) 1171 (when (numberp msg-num)
1098 (setf (gethash msg-num mh-thread-scan-line-map) 1172 (setf (gethash msg-num mh-thread-scan-line-map)
1099 (mh-thread-parse-scan-line (format "%s%s" spaces old-line))))) 1173 (mh-thread-parse-scan-line (format "%s%s" spaces old-line)))))
1100 (forward-line 1)))) 1174 (forward-line 1))))
1101 1175
1176 (defun mh-thread-print-scan-lines (thread-tree)
1177 "Print scan lines in THREAD-TREE in threaded mode."
1178 (let ((mh-thread-body-width (- (window-width) mh-cmd-note
1179 (1- mh-scan-field-subject-start-offset)))
1180 (mh-thread-last-ancestor nil))
1181 (if (null mh-index-data)
1182 (mh-thread-generate-scan-lines thread-tree -2)
1183 (loop for x in (mh-index-group-by-folder)
1184 do (let* ((old-map mh-thread-scan-line-map)
1185 (mh-thread-scan-line-map (make-hash-table)))
1186 (setq mh-thread-last-ancestor nil)
1187 (loop for msg in (cdr x)
1188 do (let ((v (gethash msg old-map)))
1189 (when v
1190 (setf (gethash msg mh-thread-scan-line-map) v))))
1191 (when (> (hash-table-count mh-thread-scan-line-map) 0)
1192 (insert (if (bobp) "" "\n") (car x) "\n")
1193 (mh-thread-generate-scan-lines thread-tree -2)))))))
1194
1102 (defun mh-thread-folder () 1195 (defun mh-thread-folder ()
1103 "Generate thread view of folder." 1196 "Generate thread view of folder."
1104 (message "Threading %s..." (buffer-name)) 1197 (message "Threading %s..." (buffer-name))
1105 (mh-thread-initialize) 1198 (mh-thread-initialize)
1106 (goto-char (point-min)) 1199 (goto-char (point-min))
1113 (mh-thread-parse-scan-line)))) 1206 (mh-thread-parse-scan-line))))
1114 (forward-line)) 1207 (forward-line))
1115 (let* ((range (mh-coalesce-msg-list msg-list)) 1208 (let* ((range (mh-coalesce-msg-list msg-list))
1116 (thread-tree (mh-thread-generate (buffer-name) range))) 1209 (thread-tree (mh-thread-generate (buffer-name) range)))
1117 (delete-region (point-min) (point-max)) 1210 (delete-region (point-min) (point-max))
1118 (let ((mh-thread-body-width (- (window-width) mh-cmd-note 1211 (mh-thread-print-scan-lines thread-tree)
1119 (1- mh-scan-field-subject-start-offset)))
1120 (mh-thread-last-ancestor nil))
1121 (mh-thread-generate-scan-lines thread-tree -2))
1122 (mh-notate-user-sequences) 1212 (mh-notate-user-sequences)
1123 (mh-notate-deleted-and-refiled) 1213 (mh-notate-deleted-and-refiled)
1124 (mh-notate-cur) 1214 (mh-notate-cur)
1125 (message "Threading %s...done" (buffer-name))))) 1215 (message "Threading %s...done" (buffer-name)))))
1126 1216
1135 (unless (mh-valid-view-change-operation-p 'unthread) 1225 (unless (mh-valid-view-change-operation-p 'unthread)
1136 (error "Can't unthread folder")) 1226 (error "Can't unthread folder"))
1137 (let ((msg-list ())) 1227 (let ((msg-list ()))
1138 (goto-char (point-min)) 1228 (goto-char (point-min))
1139 (while (not (eobp)) 1229 (while (not (eobp))
1140 (let ((index (mh-get-msg-num t))) 1230 (let ((index (mh-get-msg-num nil)))
1141 (when index 1231 (when index
1142 (push index msg-list))) 1232 (push index msg-list)))
1143 (forward-line)) 1233 (forward-line))
1144 (mh-scan-folder mh-current-folder 1234 (mh-scan-folder mh-current-folder
1145 (mapcar #'(lambda (x) (format "%s" x)) 1235 (mapcar #'(lambda (x) (format "%s" x))
1159 "Forget the message INDEX from the threading tables." 1249 "Forget the message INDEX from the threading tables."
1160 (let* ((id (gethash index mh-thread-index-id-map)) 1250 (let* ((id (gethash index mh-thread-index-id-map))
1161 (id-index (gethash id mh-thread-id-index-map)) 1251 (id-index (gethash id mh-thread-id-index-map))
1162 (duplicates (gethash id mh-thread-duplicates))) 1252 (duplicates (gethash id mh-thread-duplicates)))
1163 (remhash index mh-thread-index-id-map) 1253 (remhash index mh-thread-index-id-map)
1254 (remhash index mh-thread-scan-line-map)
1164 (cond ((and (eql index id-index) (null duplicates)) 1255 (cond ((and (eql index id-index) (null duplicates))
1165 (remhash id mh-thread-id-index-map)) 1256 (remhash id mh-thread-id-index-map))
1166 ((eql index id-index) 1257 ((eql index id-index)
1167 (setf (gethash id mh-thread-id-index-map) (car duplicates)) 1258 (setf (gethash id mh-thread-id-index-map) (car duplicates))
1168 (setf (gethash (car duplicates) mh-thread-index-id-map) id) 1259 (setf (gethash (car duplicates) mh-thread-index-id-map) id)
1306 (t (let ((region (mh-thread-find-children))) 1397 (t (let ((region (mh-thread-find-children)))
1307 (mh-iterate-on-messages-in-region () (car region) (cadr region) 1398 (mh-iterate-on-messages-in-region () (car region) (cadr region)
1308 (mh-refile-a-msg nil folder)) 1399 (mh-refile-a-msg nil folder))
1309 (mh-next-msg))))) 1400 (mh-next-msg)))))
1310 1401
1402
1403
1404 ;; Tick mark handling
1405
1406 ;; Functions to highlight and unhighlight ticked messages.
1407 (defun mh-tick-add-overlay ()
1408 "Add tick overlay to current line."
1409 (with-mh-folder-updating (t)
1410 (let ((overlay
1411 (or (mh-funcall-if-exists make-overlay (point) (line-end-position))
1412 (mh-funcall-if-exists make-extent (point) (line-end-position)))))
1413 (or (mh-funcall-if-exists overlay-put overlay 'face 'mh-folder-tick-face)
1414 (mh-funcall-if-exists set-extent-face overlay 'mh-folder-tick-face))
1415 (mh-funcall-if-exists set-extent-priority overlay 10)
1416 (add-text-properties (point) (line-end-position) `(mh-tick ,overlay)))))
1417
1418 (defun mh-tick-remove-overlay ()
1419 "Remove tick overlay from current line."
1420 (let ((overlay (get-text-property (point) 'mh-tick)))
1421 (when overlay
1422 (with-mh-folder-updating (t)
1423 (or (mh-funcall-if-exists delete-overlay overlay)
1424 (mh-funcall-if-exists delete-extent overlay))
1425 (remove-text-properties (point) (line-end-position) `(mh-tick nil))))))
1426
1427 ;;;###mh-autoload
1428 (defun mh-notate-tick (msg ticked-msgs &optional ignore-narrowing)
1429 "Highlight current line if MSG is in TICKED-MSGS.
1430 If optional argument IGNORE-NARROWING is non-nil then highlighting is carried
1431 out even if folder is narrowed to `mh-tick-seq'."
1432 (when mh-tick-seq
1433 (let ((narrowed-to-tick (and (not ignore-narrowing)
1434 (eq mh-narrowed-to-seq mh-tick-seq)))
1435 (overlay (get-text-property (point) 'mh-tick))
1436 (in-tick (member msg ticked-msgs)))
1437 (cond (narrowed-to-tick (mh-tick-remove-overlay))
1438 ((and (not overlay) in-tick) (mh-tick-add-overlay))
1439 ((and overlay (not in-tick)) (mh-tick-remove-overlay))))))
1440
1441 ;; Interactive function to toggle tick.
1442 ;;;###mh-autoload
1443 (defun mh-toggle-tick (begin end)
1444 "Toggle tick mark of all messages in region BEGIN to END."
1445 (interactive (cond ((mh-mark-active-p t)
1446 (list (region-beginning) (region-end)))
1447 (t (list (line-beginning-position) (line-end-position)))))
1448 (unless mh-tick-seq
1449 (error "Enable ticking by customizing `mh-tick-seq'"))
1450 (let* ((tick-seq (mh-find-seq mh-tick-seq))
1451 (tick-seq-msgs (mh-seq-msgs tick-seq)))
1452 (mh-iterate-on-messages-in-region msg begin end
1453 (cond ((member msg tick-seq-msgs)
1454 (mh-undefine-sequence mh-tick-seq (list msg))
1455 (setcdr tick-seq (delq msg (cdr tick-seq)))
1456 (when (null (cdr tick-seq)) (setq mh-last-seq-used nil))
1457 (mh-tick-remove-overlay))
1458 (t
1459 (mh-add-msgs-to-seq (list msg) mh-tick-seq nil t)
1460 (setq mh-last-seq-used mh-tick-seq)
1461 (mh-tick-add-overlay))))
1462 (when (and (eq mh-tick-seq mh-narrowed-to-seq)
1463 (not mh-tick-seq-changed-when-narrowed-flag))
1464 (setq mh-tick-seq-changed-when-narrowed-flag t)
1465 (let ((ticked-msgs (mh-seq-msgs (mh-find-seq mh-tick-seq))))
1466 (mh-iterate-on-messages-in-region msg (point-min) (point-max)
1467 (mh-notate-tick msg ticked-msgs t))))))
1468
1469 ;;;###mh-autoload
1470 (defun mh-narrow-to-tick ()
1471 "Restrict display of this folder to just messages in `mh-tick-seq'.
1472 Use \\<mh-folder-mode-map>\\[mh-widen] to undo this command."
1473 (interactive)
1474 (cond ((not mh-tick-seq)
1475 (error "Enable ticking by customizing `mh-tick-seq'"))
1476 ((null (mh-seq-msgs (mh-find-seq mh-tick-seq)))
1477 (message "No messages in tick sequence"))
1478 (t (mh-narrow-to-seq mh-tick-seq))))
1479
1480
1311 (provide 'mh-seq) 1481 (provide 'mh-seq)
1312 1482
1313 ;;; Local Variables: 1483 ;;; Local Variables:
1314 ;;; indent-tabs-mode: nil 1484 ;;; indent-tabs-mode: nil
1315 ;;; sentence-end-double-space: nil 1485 ;;; sentence-end-double-space: nil