Mercurial > emacs
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 |