+ (let ((start (point)))
+ (notmuch-show-move-to-current-message-summary-line)
+ (if (not (< (point) start))
+ ; Go backward twice to skip the current message's marker
+ (progn
+ (re-search-backward notmuch-show-message-begin-regexp nil t)
+ (re-search-backward notmuch-show-message-begin-regexp nil t)
+ (notmuch-show-move-to-current-message-summary-line)
+ ))
+ (recenter 0)))
+
+(defun notmuch-show-find-previous-message ()
+ "Returns the position of the previous message in the buffer.
+
+Or the position of the beginning of the current message if point
+is originally within the message rather than at the beginning of
+it."
+ ; save-excursion doesn't save our window position
+ ; save-window-excursion doesn't save point
+ ; Looks like we have to use both.
+ (save-excursion
+ (save-window-excursion
+ (notmuch-show-previous-message)
+ (point))))
+
+(defun notmuch-show-mark-read-then-next-open-message ()
+ "Remove unread tag from current message, then advance to next unread message."
+ (interactive)
+ (notmuch-show-remove-tag "unread")
+ (notmuch-show-next-open-message))
+
+(defun notmuch-show-rewind ()
+ "Do reverse scrolling compared to `notmuch-show-advance-marking-read-and-archiving'
+
+Specifically, if the beginning of the previous email is fewer
+than `window-height' lines from the current point, move to it
+just like `notmuch-show-previous-message'.
+
+Otherwise, just scroll down a screenful of the current message.
+
+This command does not modify any message tags, (it does not undo
+any effects from previous calls to
+`notmuch-show-advance-marking-read-and-archiving'."
+ (interactive)
+ (let ((previous (notmuch-show-find-previous-message)))
+ (if (> (count-lines previous (point)) (- (window-height) next-screen-context-lines))
+ (progn
+ (condition-case nil
+ (scroll-down nil)
+ ((beginning-of-buffer) nil))
+ (goto-char (window-start)))
+ (notmuch-show-previous-message))))
+
+(defun notmuch-show-advance-marking-read-and-archiving ()
+ "Advance through buffer, marking read and archiving.
+
+This command is intended to be one of the simplest ways to
+process a thread of email. It does the following:
+
+If the current message in the thread is not yet fully visible,
+scroll by a near screenful to read more of the message.
+
+Otherwise, (the end of the current message is already within the
+current window), remove the \"unread\" tag (if present) from the
+current message and advance to the next open message.
+
+Finally, if there is no further message to advance to, and this
+last message is already read, then archive the entire current
+thread, (remove the \"inbox\" tag from each message). Also kill
+this buffer, and display the next thread from the search from
+which this thread was originally shown."
+ (interactive)
+ (let ((next (notmuch-show-find-next-message))
+ (unread (notmuch-show-message-unread-p)))
+ (if (> next (window-end))
+ (scroll-up nil)
+ (let ((last (notmuch-show-last-message-p)))
+ (notmuch-show-mark-read-then-next-open-message)
+ (if last
+ (notmuch-show-archive-thread))))))
+
+(defun notmuch-show-next-button ()
+ "Advance point to the next button in the buffer."
+ (interactive)
+ (goto-char (button-start (next-button (point)))))
+
+(defun notmuch-show-previous-button ()
+ "Move point back to the previous button in the buffer."
+ (interactive)
+ (goto-char (button-start (previous-button (point)))))
+
+(defun notmuch-toggle-invisible-action (cite-button)
+ (let ((invis-spec (button-get button 'invisibility-spec)))
+ (if (invisible-p invis-spec)
+ (remove-from-invisibility-spec invis-spec)
+ (add-to-invisibility-spec invis-spec)
+ ))
+ (force-window-update)
+ (redisplay t))
+
+(define-button-type 'notmuch-button-invisibility-toggle-type 'action 'notmuch-toggle-invisible-action 'follow-link t)
+(define-button-type 'notmuch-button-citation-toggle-type 'help-echo "mouse-1, RET: Show citation"
+ :supertype 'notmuch-button-invisibility-toggle-type)
+(define-button-type 'notmuch-button-signature-toggle-type 'help-echo "mouse-1, RET: Show signature"
+ :supertype 'notmuch-button-invisibility-toggle-type)
+(define-button-type 'notmuch-button-headers-toggle-type 'help-echo "mouse-1, RET: Show headers"
+ :supertype 'notmuch-button-invisibility-toggle-type)
+(define-button-type 'notmuch-button-body-toggle-type 'help-echo "mouse-1, RET: Show message"
+ :supertype 'notmuch-button-invisibility-toggle-type)
+
+(defun notmuch-show-markup-citations-region (beg end depth)
+ (goto-char beg)
+ (beginning-of-line)
+ (while (< (point) end)
+ (let ((beg-sub (point-marker))
+ (indent (make-string depth ? ))
+ (citation "[[:space:]]*>"))
+ (if (looking-at citation)
+ (progn
+ (while (looking-at citation)
+ (forward-line))
+ (let ((overlay (make-overlay beg-sub (point)))
+ (invis-spec (make-symbol "notmuch-citation-region")))
+ (add-to-invisibility-spec invis-spec)
+ (overlay-put overlay 'invisible invis-spec)
+ (let ((p (point))
+ (cite-button-text
+ (concat "[" (number-to-string (count-lines beg-sub (point)))
+ "-line citation.]")))
+ (goto-char (- beg-sub 1))
+ (insert (concat "\n" indent))
+ (insert-button cite-button-text
+ 'invisibility-spec invis-spec
+ :type 'notmuch-button-citation-toggle-type)
+ (insert "\n")
+ (goto-char (+ (length cite-button-text) p))
+ ))))
+ (move-to-column depth)
+ (if (looking-at notmuch-show-signature-regexp)
+ (let ((sig-lines (- (count-lines beg-sub end) 1)))
+ (if (<= sig-lines notmuch-show-signature-lines-max)
+ (progn
+ (let ((invis-spec (make-symbol "notmuch-signature-region")))
+ (add-to-invisibility-spec invis-spec)
+ (overlay-put (make-overlay beg-sub end)
+ 'invisible invis-spec)
+
+ (goto-char (- beg-sub 1))
+ (insert (concat "\n" indent))
+ (let ((sig-button-text (concat "[" (number-to-string sig-lines)
+ "-line signature.]")))
+ (insert-button sig-button-text 'invisibility-spec invis-spec
+ :type 'notmuch-button-signature-toggle-type)
+ )
+ (insert "\n")
+ (goto-char end))))))
+ (forward-line))))
+
+(defun notmuch-show-markup-part (beg end depth mime-message)
+ (if (re-search-forward notmuch-show-part-begin-regexp nil t)
+ (progn
+ (if (eq mime-message nil)
+ (let ((filename (notmuch-show-get-filename)))
+ (with-temp-buffer
+ (insert-file-contents filename nil nil nil t)
+ (setq mime-message (mm-dissect-buffer)))))
+ (forward-line)
+ (let ((part-beg (point-marker)))
+ (re-search-forward notmuch-show-part-end-regexp)
+
+ (let ((part-end (copy-marker (match-beginning 0))))
+ (goto-char part-end)
+ (if (not (bolp))
+ (insert "\n"))
+ (indent-rigidly part-beg part-end depth)
+ (save-excursion
+ (goto-char part-beg)
+ (forward-line -1)
+ (beginning-of-line)
+ (let ((handle-type (mm-handle-type mime-message))
+ mime-type)
+ (if (sequencep (car handle-type))
+ (setq mime-type (car handle-type))
+ (setq mime-type (car (car (cdr handle-type))))
+ )
+ (if (equal mime-type "text/html")
+ (mm-display-part mime-message))))
+
+ (notmuch-show-markup-citations-region part-beg part-end depth)
+ ; Advance to the next part (if any) (so the outer loop can
+ ; determine whether we've left the current message.
+ (if (re-search-forward notmuch-show-part-begin-regexp nil t)
+ (beginning-of-line)))))
+ (goto-char end))
+ mime-message)
+
+(defun notmuch-show-markup-parts-region (beg end depth)
+ (save-excursion
+ (goto-char beg)
+ (let (mime-message)
+ (while (< (point) end)
+ (setq mime-message
+ (notmuch-show-markup-part
+ beg end depth mime-message))))))
+
+(defun notmuch-show-markup-body (depth btn)
+ (re-search-forward notmuch-show-body-begin-regexp)
+ (forward-line)
+ (let ((beg (point-marker)))
+ (re-search-forward notmuch-show-body-end-regexp)
+ (let ((end (copy-marker (match-beginning 0))))
+ (notmuch-show-markup-parts-region beg end depth)
+ (let ((invis-spec (make-symbol "notmuch-show-body-read")))
+ (overlay-put (make-overlay beg end)
+ 'invisible invis-spec)
+ (button-put btn 'invisibility-spec invis-spec)
+ (if (not (notmuch-show-message-unread-p))
+ (add-to-invisibility-spec invis-spec)))
+ (set-marker beg nil)
+ (set-marker end nil)
+ )))
+(defun notmuch-fontify-headers ()
+ (progn
+ (if (looking-at "[Tt]o:")
+ (progn
+ (overlay-put (make-overlay (point) (re-search-forward ":"))
+ 'face 'message-header-name)
+ (overlay-put (make-overlay (point) (re-search-forward ".*$"))
+ 'face 'message-header-to))
+ (if (looking-at "[B]?[Cc][Cc]:")
+ (progn
+ (overlay-put (make-overlay (point) (re-search-forward ":"))
+ 'face 'message-header-name)
+ (overlay-put (make-overlay (point) (re-search-forward ".*$"))
+ 'face 'message-header-cc))
+ (if (looking-at "[Ss]ubject:")
+ (progn
+ (overlay-put (make-overlay (point) (re-search-forward ":"))
+ 'face 'message-header-name)
+ (overlay-put (make-overlay (point) (re-search-forward ".*$"))
+ 'face 'message-header-subject))
+ (if (looking-at "[Ff]rom:")
+ (progn
+ (overlay-put (make-overlay (point) (re-search-forward ":"))
+ 'face 'message-header-name)
+ (overlay-put (make-overlay (point) (re-search-forward ".*$"))
+ 'face 'message-header-other))))))))
+
+(defun notmuch-show-markup-header (depth)
+ (re-search-forward notmuch-show-header-begin-regexp)
+ (forward-line)
+ (let ((beg (point-marker))
+ (btn nil))
+ (end-of-line)
+ ; Inverse video for subject
+ (overlay-put (make-overlay beg (point)) 'face '(:inverse-video t))
+ (setq btn (make-button beg (point) :type 'notmuch-button-body-toggle-type))
+ (forward-line 1)
+ (end-of-line)
+ (let ((beg-hidden (point-marker)))
+ (re-search-forward notmuch-show-header-end-regexp)
+ (beginning-of-line)
+ (let ((end (point-marker)))
+ (goto-char beg)
+ (forward-line)
+ (while (looking-at "[A-Za-z][-A-Za-z0-9]*:")
+ (beginning-of-line)
+ (notmuch-fontify-headers)
+ (forward-line)
+ )
+ (indent-rigidly beg end depth)
+ (let ((invis-spec (make-symbol "notmuch-show-header")))
+ (add-to-invisibility-spec (cons invis-spec t))
+ (overlay-put (make-overlay beg-hidden end)
+ 'invisible invis-spec)
+ (goto-char beg)
+ (forward-line)
+ (make-button (line-beginning-position) (line-end-position)
+ 'invisibility-spec (cons invis-spec t)
+ :type 'notmuch-button-headers-toggle-type))
+ (goto-char end)
+ (insert "\n")
+ (set-marker beg nil)
+ (set-marker beg-hidden nil)
+ (set-marker end nil)
+ ))
+ btn))
+
+(defun notmuch-show-markup-message ()
+ (if (re-search-forward notmuch-show-message-begin-regexp nil t)