+ (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-next-open-message)
+ (if last
+ (notmuch-show-archive-thread))))))
+
+(defun notmuch-show-next-button ()
+ "Advance point to the next button in the buffer."
+ (interactive)
+ (forward-button 1))
+
+(defun notmuch-show-previous-button ()
+ "Move point back to the previous button in the buffer."
+ (interactive)
+ (backward-button 1))
+
+(defun notmuch-toggle-invisible-action (cite-button)
+ (let ((invis-spec (button-get cite-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))
+
+(defun notmuch-show-toggle-current-body ()
+ "Toggle the display of the current message body."
+ (interactive)
+ (save-excursion
+ (notmuch-show-move-to-current-message-summary-line)
+ (unless (button-at (point))
+ (notmuch-show-next-button))
+ (push-button))
+ )
+
+(defun notmuch-show-toggle-current-header ()
+ "Toggle the display of the current message header."
+ (interactive)
+ (save-excursion
+ (notmuch-show-move-to-current-message-summary-line)
+ (forward-line)
+ (unless (button-at (point))
+ (notmuch-show-next-button))
+ (push-button))
+ )
+
+(define-button-type 'notmuch-button-invisibility-toggle-type
+ 'action 'notmuch-toggle-invisible-action
+ 'follow-link t
+ 'face 'font-lock-comment-face)
+(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"
+ 'face 'notmuch-message-summary-face
+ :supertype 'notmuch-button-invisibility-toggle-type)
+
+(defun notmuch-show-citation-regexp (depth)
+ "Build a regexp for matching citations at a given DEPTH (indent)"
+ (let ((line-regexp (format "[[:space:]]\\{%d\\}>.*\n" depth)))
+ (concat "\\(?:^" line-regexp
+ "\\(?:[[:space:]]*\n" line-regexp
+ "\\)?\\)+")))
+
+(defun notmuch-show-region-to-button (beg end type prefix button-text)
+ "Auxilary function to do the actual making of overlays and buttons
+
+BEG and END are buffer locations. TYPE should a string, either
+\"citation\" or \"signature\". PREFIX is some arbitrary text to
+insert before the button, probably for indentation. BUTTON-TEXT
+is what to put on the button."
+
+;; This uses some slightly tricky conversions between strings and
+;; symbols because of the way the button code works. Note that
+;; replacing intern-soft with make-symbol will cause this to fail,
+;; since the newly created symbol has no plist.
+
+ (let ((overlay (make-overlay beg end))
+ (invis-spec (make-symbol (concat "notmuch-" type "-region")))
+ (button-type (intern-soft (concat "notmuch-button-"
+ type "-toggle-type"))))
+ (add-to-invisibility-spec invis-spec)
+ (overlay-put overlay 'invisible invis-spec)
+ (goto-char (1+ end))
+ (save-excursion
+ (goto-char (1- beg))
+ (insert prefix)
+ (insert-button button-text
+ 'invisibility-spec invis-spec
+ :type button-type)
+ )))
+
+
+(defun notmuch-show-markup-citations-region (beg end depth)
+ "Markup citations, and up to one signature in the given region"
+ ;; it would be nice if the untabify was not required, but
+ ;; that would require notmuch to indent with spaces.
+ (untabify beg end)
+ (let ((citation-regexp (notmuch-show-citation-regexp depth))
+ (signature-regexp (concat (format "^[[:space:]]\\{%d\\}" depth)
+ notmuch-show-signature-regexp))
+ (indent (concat "\n" (make-string depth ? ))))
+ (goto-char beg)
+ (beginning-of-line)
+ (while (and (< (point) end)
+ (re-search-forward citation-regexp end t))
+ (let* ((cite-start (match-beginning 0))
+ (cite-end (match-end 0))
+ (cite-lines (count-lines cite-start cite-end)))
+ (when (> cite-lines (1+ notmuch-show-citation-lines-prefix))
+ (goto-char cite-start)
+ (forward-line notmuch-show-citation-lines-prefix)
+ (notmuch-show-region-to-button
+ (point) cite-end
+ "citation"
+ indent
+ (format notmuch-show-citation-button-format
+ (- cite-lines notmuch-show-citation-lines-prefix))
+ ))))
+ (if (and (< (point) end)
+ (re-search-forward signature-regexp end t))
+ (let* ((sig-start (match-beginning 0))
+ (sig-end (match-end 0))
+ (sig-lines (1- (count-lines sig-start end))))
+ (if (<= sig-lines notmuch-show-signature-lines-max)
+ (notmuch-show-region-to-button
+ sig-start
+ end
+ "signature"
+ indent
+ (format notmuch-show-signature-button-format sig-lines)
+ ))))))
+
+(defun notmuch-show-markup-part (beg end depth)
+ (if (re-search-forward notmuch-show-part-begin-regexp nil t)
+ (progn
+ (let (mime-message mime-type)
+ (save-excursion
+ (re-search-forward notmuch-show-contentype-regexp end t)
+ (setq mime-type (car (split-string (buffer-substring
+ (match-beginning 1) (match-end 1))))))
+
+ (if (equal mime-type "text/html")
+ (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 ((beg (point-marker)))
+ (re-search-forward notmuch-show-part-end-regexp)
+ (let ((end (copy-marker (match-beginning 0))))
+ (goto-char end)
+ (if (not (bolp))
+ (insert "\n"))
+ (indent-rigidly beg end depth)
+ (if (not (eq mime-message nil))
+ (save-excursion
+ (goto-char beg)
+ (forward-line -1)
+ (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 beg 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))
+ (goto-char end)))
+
+(defun notmuch-show-markup-parts-region (beg end depth)
+ (save-excursion
+ (goto-char beg)
+ (while (< (point) end)
+ (notmuch-show-markup-part beg end depth))))
+
+(defun notmuch-show-markup-body (depth match btn)
+ "Markup a message body, (indenting, buttonizing citations,
+etc.), and hiding the body itself if the message does not match
+the current search.
+
+DEPTH specifies the depth at which this message appears in the
+tree of the current thread, (the top-level messages have depth 0
+and each reply increases depth by 1). MATCH indicates whether
+this message is regarded as matching the current search. BTN is
+the button which is used to toggle the visibility of this
+message.
+
+When this function is called, point must be within the message, but
+before the delimiter marking the beginning of the body."