Synch up with main trunk, and prepare the release 2.12.0.
[elisp/wanderlust.git] / wl / wl-summary.el
index a2e1069..8cee114 100644 (file)
 (defvar wl-summary-buffer-mode-line-formatter nil)
 (defvar wl-summary-buffer-mode-line nil)
 (defvar wl-summary-buffer-display-mime-mode 'mime)
-(defvar wl-summary-buffer-display-all-header nil)
+(defvar wl-summary-buffer-display-header-mode 'partial)
+(defvar wl-summary-buffer-event-handler nil)
 
 (defvar wl-thread-indent-level-internal nil)
 (defvar wl-thread-have-younger-brother-str-internal nil)
 (make-variable-buffer-local 'wl-summary-buffer-mode-line-formatter)
 (make-variable-buffer-local 'wl-summary-buffer-mode-line)
 (make-variable-buffer-local 'wl-summary-buffer-display-mime-mode)
-(make-variable-buffer-local 'wl-summary-buffer-display-all-header)
+(make-variable-buffer-local 'wl-summary-buffer-display-header-mode)
+(make-variable-buffer-local 'wl-summary-buffer-event-handler)
 
 (defvar wl-datevec)
 (defvar wl-thr-indent-string)
@@ -396,6 +398,11 @@ See also variable `wl-use-petname'."
     ()
   (setq wl-summary-mode-map (make-keymap))
   (suppress-keymap wl-summary-mode-map)
+  (substitute-key-definition 'kill-buffer
+                            'wl-summary-mimic-kill-buffer
+                            wl-summary-mode-map
+                            global-map)
+  ;; basic commands
   (define-key wl-summary-mode-map " "    'wl-summary-read)
   (define-key wl-summary-mode-map "."    'wl-summary-redisplay)
   (define-key wl-summary-mode-map "<"    'wl-summary-display-top)
@@ -578,6 +585,15 @@ See also variable `wl-use-petname'."
    "Menu used in Summary mode."
    wl-summary-mode-menu-spec))
 
+(defun wl-summary-mimic-kill-buffer (buffer)
+  "Kill the current (Summary) buffer with query."
+  (interactive "bKill buffer: ")
+  (if (or (not buffer)
+         (string-equal buffer "")
+         (string-equal buffer (buffer-name)))
+      (wl-summary-exit 'force-exit)
+    (kill-buffer buffer)))
+
 (defsubst wl-summary-message-visible-p (number)
   "Return non-nil if the message with NUMBER is visible."
   (or (eq wl-summary-buffer-view 'sequence)
@@ -618,6 +634,42 @@ See also variable `wl-use-petname'."
        (wl-summary-lazy-update-mark
         (list 'wl-summary-update-mark-window))))
 
+(defun wl-summary-after-resize-function (frame)
+  "Called from `window-size-change-functions'."
+  (save-excursion
+    (save-selected-window
+      (select-frame frame)
+      (walk-windows
+       (lambda (window)
+        (set-buffer (window-buffer window))
+        (when (eq major-mode 'wl-summary-mode)
+          (run-hook-with-args 'wl-summary-buffer-window-scroll-functions
+                              window)))
+       'nomini frame))))
+
+;; Handler of event from elmo-folder
+(eval-and-compile
+  (luna-define-class wl-summary-event-handler (elmo-event-handler)
+                    (buffer))
+  (luna-define-internal-accessors 'wl-summary-event-handler))
+
+(luna-define-method elmo-event-handler-flag-changed ((handler
+                                                     wl-summary-event-handler)
+                                                    numbers)
+  (save-excursion
+    (set-buffer (wl-summary-event-handler-buffer-internal handler))
+    (dolist (number numbers)
+      (when (and (wl-summary-message-visible-p number)
+                (wl-summary-jump-to-msg number))
+       (wl-summary-update-persistent-mark number)))))
+
+(defun wl-summary-buffer-detach ()
+  (when (and (eq major-mode 'wl-summary-mode)
+            wl-summary-buffer-elmo-folder
+            wl-summary-buffer-event-handler)
+    (elmo-folder-remove-handler wl-summary-buffer-elmo-folder
+                               wl-summary-buffer-event-handler)))
+
 (defun wl-status-update ()
   (interactive)
   (wl-address-init))
@@ -765,6 +817,7 @@ you."
          wl-summary-buffer-persistent-mark-column persistent)))
 
 (defun wl-summary-buffer-set-folder (folder)
+  (wl-summary-buffer-detach)
   (if (stringp folder)
       (setq folder (wl-folder-get-elmo-folder folder)))
   (setq wl-summary-buffer-elmo-folder folder)
@@ -801,6 +854,11 @@ you."
   (setq wl-summary-buffer-persistent
        (wl-folder-persistent-p (elmo-folder-name-internal folder)))
   (elmo-folder-set-persistent-internal folder wl-summary-buffer-persistent)
+  (elmo-folder-add-handler folder
+                          (setq wl-summary-buffer-event-handler
+                                (luna-make-entity
+                                 'wl-summary-event-handler
+                                 :buffer (current-buffer))))
   ;; process duplicates.
   (elmo-folder-set-process-duplicates-internal
    folder (cdr (elmo-string-matched-assoc
@@ -843,6 +901,8 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
 ;;;(setq default-directory (or wl-tmp-dir (expand-file-name "~/")))
   (setq buffer-read-only t)
   (setq truncate-lines t)
+  (when (boundp 'show-trailing-whitespace)
+    (setq show-trailing-whitespace nil))
 ;;;(make-local-variable 'tab-width)
 ;;;(setq tab-width 1)
   (buffer-disable-undo (current-buffer))
@@ -856,7 +916,12 @@ Entering Folder mode calls the value of `wl-summary-mode-hook'."
     (let ((hook (if wl-on-xemacs 'pre-idle-hook 'window-scroll-functions)))
       (make-local-hook hook)
       (dolist (function wl-summary-buffer-window-scroll-functions)
-       (add-hook hook function nil t))))
+       (add-hook hook function nil t)))
+    (add-hook 'window-size-change-functions
+             #'wl-summary-after-resize-function))
+  (dolist (hook '(change-major-mode-hook kill-buffer-hook))
+    (make-local-hook hook)
+    (add-hook hook #'wl-summary-buffer-detach nil t))
   ;; This hook may contain the function `wl-setup-summary' for reasons
   ;; of system internal to accord facilities for the Emacs variants.
   (run-hooks 'wl-summary-mode-hook))
@@ -1662,11 +1727,6 @@ If ARG is non-nil, checking is omitted."
         folder
         (elmo-folder-list-flagged folder 'unread 'in-msgdb)
         'unread)
-       (save-excursion
-         (goto-char (point-min))
-         (while (not (eobp))
-           (wl-summary-update-persistent-mark)
-           (forward-line 1)))
        (wl-folder-update-unread (wl-summary-buffer-folder-name) 0)
        (setq wl-summary-buffer-unread-count 0)
        (setq wl-summary-buffer-new-count    0)
@@ -2515,7 +2575,7 @@ If ARG, without confirm."
 (defun wl-summary-default-subject-filter (subject)
   (setq subject (elmo-replace-in-string subject "[ \t]*\\(re\\|was\\)[:>]" ""))
   (setq subject (elmo-replace-in-string subject "[ \t]" ""))
-  (elmo-replace-in-string subject "^\\[.*\\]" ""))
+  (elmo-replace-in-string subject "^\\[[^]]*\\]" ""))
 
 (defun wl-summary-subject-equal (subject1 subject2)
   (string= (funcall wl-summary-subject-filter-function subject1)
@@ -3014,7 +3074,7 @@ Return non-nil if the mark is updated"
   (save-excursion
     (let ((folder wl-summary-buffer-elmo-folder)
          unread-message number
-         number-list visible)
+         number-list)
       (setq number-list (cond ((numberp number-or-numbers)
                               (setq unread-message
                                     (elmo-message-flagged-p
@@ -3038,14 +3098,11 @@ Return non-nil if the mark is updated"
        (if inverse
            (elmo-folder-set-flag folder number-list 'unread no-folder-mark)
          (elmo-folder-unset-flag folder number-list 'unread no-folder-mark))
-       (dolist (number number-list)
-         (setq visible (wl-summary-jump-to-msg number))
-         (unless inverse
-           (when unread-message
-             (run-hooks 'wl-summary-unread-message-hook)))
-         ;; set mark on buffer
-         (when visible
-           (wl-summary-update-persistent-mark)))
+       (when (and unread-message
+                  (not inverse))
+         (dolist (number number-list)
+           (wl-summary-jump-to-msg number)
+           (run-hooks 'wl-summary-unread-message-hook)))
        (unless no-modeline-update
          ;; Update unread numbers.
          (wl-summary-count-unread)
@@ -3081,7 +3138,7 @@ Return non-nil if the mark is updated"
   "Set persistent mark."
   (save-excursion
     (let ((folder wl-summary-buffer-elmo-folder)
-         number number-list visible)
+         number number-list)
       (setq number-list (cond ((numberp number-or-numbers)
                               (list number-or-numbers))
                              ((and (not (null number-or-numbers))
@@ -3098,10 +3155,6 @@ Return non-nil if the mark is updated"
              (if inverse
                  (elmo-folder-unset-flag folder number-list flag no-server)
                (elmo-folder-set-flag folder number-list flag no-server))
-             (dolist (number number-list)
-               ;; set mark on buffer
-               (when (wl-summary-jump-to-msg number)
-                 (wl-summary-update-persistent-mark)))
              (unless no-modeline-update
                ;; Update unread numbers.
                ;; should elmo-flag-mark-as-read return unread numbers?
@@ -3240,7 +3293,7 @@ Return non-nil if the mark is updated"
                                        remove-all)
   (save-excursion
     (let ((folder wl-summary-buffer-elmo-folder)
-         number number-list visible)
+         number number-list)
       (setq number-list (cond ((numberp number-or-numbers)
                               (list number-or-numbers))
                              ((and (not (null number-or-numbers))
@@ -3256,11 +3309,7 @@ Return non-nil if the mark is updated"
       (if (null number-list)
          (message "No message.")
        (dolist (number number-list)
-         (elmo-message-set-global-flags folder number flags local)
-         (setq visible (wl-summary-jump-to-msg number))
-         ;; set mark on buffer
-         (when visible
-           (wl-summary-update-persistent-mark))))
+         (elmo-message-set-global-flags folder number flags local)))
       flags)))
 
 (defun wl-summary-set-flags (&optional remove)
@@ -4096,9 +4145,7 @@ Reply to author if invoked with ARG."
     (when number
       (save-excursion
        (wl-summary-set-message-buffer-or-redisplay))
-      (setq mes-buf wl-message-buffer)
       (wl-message-select-buffer wl-message-buffer)
-      (set-buffer mes-buf)
       (condition-case err
          (when (setq mes-buf (wl-message-get-original-buffer))
            (wl-draft-reply mes-buf arg summary-buf number)
@@ -4161,7 +4208,6 @@ Use function list is `wl-summary-write-current-folder-functions'."
        (number (wl-summary-message-number))
        (summary-buf (current-buffer))
        (wl-draft-forward t)
-       mes-buf
        entity subject num)
     (if (null number)
        (message "No message.")
@@ -4173,17 +4219,10 @@ Use function list is `wl-summary-write-current-folder-functions'."
          ;; Reload.
          (wl-summary-redisplay-internal nil nil 'force-reload)
        (wl-summary-redisplay-internal folder number))
-      (setq mes-buf wl-message-buffer)
-      (wl-message-select-buffer mes-buf)
-      ;; get original subject.
-      (if summary-buf
-         (save-excursion
-           (set-buffer summary-buf)
-           (setq subject
-                 (or (elmo-message-entity-field
-                      (elmo-message-entity folder number) 'subject 'decode)
-                     ""))))
-      (set-buffer mes-buf)
+      (wl-message-select-buffer wl-message-buffer)
+      (setq subject (with-current-buffer
+                       wl-message-buffer-original-buffer
+                     (std11-field-body "Subject")))
       (wl-draft-forward subject summary-buf number)
       (with-current-buffer summary-buf (run-hooks 'wl-summary-forward-hook))
       (unless without-setup-hook
@@ -4356,6 +4395,24 @@ Use function list is `wl-summary-write-current-folder-functions'."
            (wl-summary-redisplay)))
     (message "No last message.")))
 
+(defun wl-summary-message-display-type ()
+  (when (and wl-summary-buffer-disp-msg
+            (buffer-live-p wl-message-buffer)
+            wl-summary-buffer-current-msg
+            (wl-summary-message-number)
+            (= (wl-summary-message-number) wl-summary-buffer-current-msg))
+    (wl-message-buffer-display-type wl-message-buffer)))
+
+(defun wl-summary-buffer-display-mime-mode ()
+  (or (wl-message-display-type-property (wl-summary-message-display-type)
+                                       :mime)
+      wl-summary-buffer-display-mime-mode))
+
+(defun wl-summary-buffer-display-header-mode ()
+  (or (wl-message-display-type-property (wl-summary-message-display-type)
+                                       :header)
+      wl-summary-buffer-display-header-mode))
+
 (defun wl-summary-toggle-mime (&optional arg)
   "Toggle MIME decoding.
 If ARG is non-nil, ask coding-system to display the message in the current
@@ -4366,37 +4423,39 @@ If ARG is numeric number, decode message as following:
 2: Enable MIME analysis only for headers.
 3: Disable MIME analysis."
   (interactive "P")
-  (let ((rest (memq wl-summary-buffer-display-mime-mode
-                   wl-summary-display-mime-mode-list))
+  (let ((mime-mode (wl-summary-buffer-display-mime-mode))
        (elmo-mime-display-as-is-coding-system
         elmo-mime-display-as-is-coding-system))
-    (if (numberp arg)
-       (setq wl-summary-buffer-display-mime-mode
-             (case arg
-               (1 'mime)
-               (2 'header-only)
-               (3 'as-is)))
-      (if arg
-         ;; Specify coding-system (doesn't change the MIME mode).
-         (setq elmo-mime-display-as-is-coding-system
-               (if (and arg (not (eq wl-summary-buffer-display-mime-mode
-                                     'mime)))
-                   (or (read-coding-system "Coding system: ")
-                       elmo-mime-display-as-is-coding-system)
-                 elmo-mime-display-as-is-coding-system))
+    (if (and (consp arg) (> (prefix-numeric-value arg) 4))
+       (progn
+         (setq wl-summary-buffer-display-mime-mode mime-mode)
+         (wl-summary-update-modeline))
+      (cond
+       ((numberp arg)
+       (setq mime-mode (case arg
+                         (1 'mime)
+                         (2 'header-only)
+                         (3 'as-is))))
+       (arg
+       ;; Specify coding-system (doesn't change the MIME mode).
+       (setq elmo-mime-display-as-is-coding-system
+             (if (and arg
+                      (not (wl-message-mime-analysis-p
+                            (wl-summary-message-display-type))))
+                 (or (read-coding-system "Coding system: ")
+                     elmo-mime-display-as-is-coding-system)
+               elmo-mime-display-as-is-coding-system)))
+       (t
        ;; Change the MIME mode.
-       (if (cadr rest)
-           (setq wl-summary-buffer-display-mime-mode (cadr rest))
-         (setq wl-summary-buffer-display-mime-mode
-               (car wl-summary-display-mime-mode-list)))))
-    (wl-summary-redisplay arg)
-    (wl-summary-update-modeline)
+       (setq mime-mode (or (cadr (memq mime-mode
+                                       wl-summary-display-mime-mode-list))
+                           (car wl-summary-display-mime-mode-list)))))
+      (wl-summary-redisplay-internal nil nil arg mime-mode))
     (message "MIME decoding: %s%s"
-            (upcase (symbol-name wl-summary-buffer-display-mime-mode))
-            (if (and arg
-                     (not (numberp arg))
-                     (not (eq wl-summary-buffer-display-mime-mode
-                              'mime)))
+            (upcase (symbol-name mime-mode))
+            (if (and (not (eq mime-mode 'mime))
+                     (not (eq elmo-mime-display-as-is-coding-system
+                              wl-cs-autoconv)))
                 (concat " ("
                         (symbol-name elmo-mime-display-as-is-coding-system)
                         ")")
@@ -4405,20 +4464,24 @@ If ARG is numeric number, decode message as following:
 (defun wl-summary-redisplay (&optional arg)
   "Redisplay message."
   (interactive "P")
-  (wl-summary-redisplay-internal nil nil arg))
+  (apply #'wl-summary-redisplay-internal nil nil arg
+        (unless (and (consp arg) (> (prefix-numeric-value arg) 4))
+          (list wl-summary-buffer-display-mime-mode
+                wl-summary-buffer-display-header-mode))))
 
 (defun wl-summary-toggle-all-header (&optional arg)
   "Toggle displaying message with all header."
   (interactive "P")
-  (setq wl-summary-buffer-display-all-header
-       (not wl-summary-buffer-display-all-header))
-  (wl-summary-redisplay-internal nil nil arg))
+  (let ((header-mode (wl-summary-buffer-display-header-mode)))
+    (if (and (consp arg) (> (prefix-numeric-value arg) 4))
+       (setq wl-summary-buffer-display-header-mode header-mode)
+      (wl-summary-redisplay-internal
+       nil nil arg nil
+       (if (eq header-mode 'all) 'partial 'all)))))
 
 (defun wl-summary-redisplay-internal (&optional folder number force-reload
-                                               mode all-header)
+                                               mime-mode header-mode)
   (let* ((folder (or folder wl-summary-buffer-elmo-folder))
-        (mode (or mode wl-summary-buffer-display-mime-mode))
-        (all-header (or all-header wl-summary-buffer-display-all-header))
         (num (or number (wl-summary-message-number)))
         (wl-mime-charset      wl-summary-buffer-mime-charset)
         (default-mime-charset wl-summary-buffer-mime-charset)
@@ -4446,13 +4509,16 @@ If ARG is numeric number, decode message as following:
          (setq wl-current-summary-buffer (current-buffer))
          (setq no-folder-mark
                ;; If cache is used, change folder-mark.
-               (if (wl-message-redisplay folder num
-                                         mode all-header
-                                         (or
-                                          force-reload
-                                          (string= (elmo-folder-name-internal
-                                                    folder)
-                                                   wl-draft-folder)))
+               (if (wl-message-redisplay
+                    folder num
+                    (wl-message-make-display-type
+                     (or mime-mode
+                         (wl-summary-buffer-display-mime-mode))
+                     (or header-mode
+                         (wl-summary-buffer-display-header-mode)))
+                    (or force-reload
+                        (string= (elmo-folder-name-internal folder)
+                                 wl-draft-folder)))
                    nil
                  ;; plugged, then leave folder-mark.
                  (if (and (not (elmo-folder-local-p