+ (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)
+ (progn
+ (re-search-forward notmuch-show-depth-regexp)
+ (let ((depth (string-to-number (buffer-substring (match-beginning 1) (match-end 1))))
+ (btn nil))
+ (setq btn (notmuch-show-markup-header depth))
+ (notmuch-show-markup-body depth btn)))
+ (goto-char (point-max))))
+
+(defun notmuch-show-hide-markers ()
+ (save-excursion
+ (goto-char (point-min))
+ (while (not (eobp))
+ (if (re-search-forward notmuch-show-marker-regexp nil t)
+ (progn
+ (overlay-put (make-overlay (match-beginning 0) (+ (match-end 0) 1))
+ 'invisible 'notmuch-show-marker))
+ (goto-char (point-max))))))
+
+(defun notmuch-show-markup-messages ()
+ (save-excursion
+ (goto-char (point-min))
+ (while (not (eobp))
+ (notmuch-show-markup-message)))
+ (notmuch-show-hide-markers))
+
+(defun notmuch-documentation-first-line (symbol)
+ "Return the first line of the documentation string for SYMBOL."
+ (let ((doc (documentation symbol)))
+ (if doc
+ (with-temp-buffer
+ (insert (documentation symbol t))
+ (goto-char (point-min))
+ (let ((beg (point)))
+ (end-of-line)
+ (buffer-substring beg (point))))
+ "")))
+
+(defun notmuch-prefix-key-description (key)
+ "Given a prefix key code, return a human-readable string representation.
+
+This is basically just `format-kbd-macro' but we also convert ESC to M-."
+ (let ((desc (format-kbd-macro (vector key))))
+ (if (string= desc "ESC")
+ "M-"
+ (concat desc " "))))
+
+; I would think that emacs would have code handy for walking a keymap
+; and generating strings for each key, and I would prefer to just call
+; that. But I couldn't find any (could be all implemented in C I
+; suppose), so I wrote my own here.
+(defun notmuch-substitute-one-command-key-with-prefix (prefix binding)
+ "For a key binding, return a string showing a human-readable
+representation of the prefixed key as well as the first line of
+documentation from the bound function.
+
+For a mouse binding, return nil."
+ (let ((key (car binding))
+ (action (cdr binding)))
+ (if (mouse-event-p key)
+ nil
+ (if (keymapp action)
+ (let ((substitute (apply-partially 'notmuch-substitute-one-command-key-with-prefix (notmuch-prefix-key-description key))))
+ (mapconcat substitute (cdr action) "\n"))
+ (concat prefix (format-kbd-macro (vector key))
+ "\t"
+ (notmuch-documentation-first-line action))))))
+
+(defalias 'notmuch-substitute-one-command-key
+ (apply-partially 'notmuch-substitute-one-command-key-with-prefix nil))
+
+(defun notmuch-substitute-command-keys (doc)
+ "Like `substitute-command-keys' but with documentation, not function names."
+ (let ((beg 0))
+ (while (string-match "\\\\{\\([^}[:space:]]*\\)}" doc beg)
+ (let ((map (substring doc (match-beginning 1) (match-end 1))))
+ (setq doc (replace-match (mapconcat 'notmuch-substitute-one-command-key
+ (cdr (symbol-value (intern map))) "\n") 1 1 doc)))
+ (setq beg (match-end 0)))
+ doc))
+
+(defun notmuch-help ()
+ "Display help for the current notmuch mode."
+ (interactive)
+ (let* ((mode major-mode)
+ (doc (substitute-command-keys (notmuch-substitute-command-keys (documentation mode t)))))
+ (with-current-buffer (generate-new-buffer "*notmuch-help*")
+ (insert doc)
+ (goto-char (point-min))
+ (set-buffer-modified-p nil)
+ (view-buffer (current-buffer) 'kill-buffer-if-not-modified))))