(defvar notmuch-show-marker-regexp "\f\\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$")
(defvar notmuch-show-id-regexp "\\(id:[^ ]*\\)")
-(defvar notmuch-show-depth-regexp " depth:\\([0-9]*\\) ")
+(defvar notmuch-show-depth-match-regexp " depth:\\([0-9]*\\).*match:\\([01]\\) ")
(defvar notmuch-show-filename-regexp "filename:\\(.*\\)$")
(defvar notmuch-show-tags-regexp "(\\([^)]*\\))$")
(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-invisibility-toggle-type
+ 'action 'notmuch-toggle-invisible-action
+ 'follow-link t
+ 'face "default")
(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"
+(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-markup-citations-region (beg end depth)
(notmuch-show-markup-part
beg end depth mime-message))))))
-(defun notmuch-show-markup-body (depth btn)
+(defun notmuch-show-markup-body (depth match btn)
+ "Markup a message body, (indenting, buttonizing citations,
+etc.), and conditionally hiding the body itself if the message
+has been read and 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."
(re-search-forward notmuch-show-body-begin-regexp)
(forward-line)
(let ((beg (point-marker)))
(overlay-put (make-overlay beg end)
'invisible invis-spec)
(button-put btn 'invisibility-spec invis-spec)
- (if (not (notmuch-show-message-unread-p))
+ (if (not (or (notmuch-show-message-unread-p) match))
(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))
+ (while (looking-at "[[:space:]]")
+ (forward-char))
+ (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)
+ '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 (message-begin depth)
+ "Buttonize and decorate faces in a message header.
+
+MESSAGE-BEGIN is the position of the absolute first character in
+the message (including all delimiters that will end up being
+invisible etc.). This is to allow a button to reliably extend to
+the beginning of the message even if point is positioned at an
+invisible character (such as the beginning of the buffer).
+
+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)."
(re-search-forward notmuch-show-header-begin-regexp)
(forward-line)
(let ((beg (point-marker))
(summary-end (copy-marker (line-beginning-position 2)))
+ (subject-end (copy-marker (line-end-position 2)))
+ (invis-spec (make-symbol "notmuch-show-header"))
(btn nil))
- (overlay-put (make-overlay beg summary-end) 'face 'notmuch-message-summary-face)
- (setq btn (make-button beg summary-end :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))
+ (re-search-forward notmuch-show-header-end-regexp)
+ (beginning-of-line)
+ (let ((end (point-marker)))
+ (indent-rigidly beg end depth)
+ (goto-char beg)
+ (setq btn (make-button message-begin summary-end :type 'notmuch-button-body-toggle-type))
+ (forward-line)
+ (add-to-invisibility-spec invis-spec)
+ (overlay-put (make-overlay subject-end end)
+ 'invisible invis-spec)
+ (make-button (line-beginning-position) subject-end
+ 'invisibility-spec invis-spec
+ :type 'notmuch-button-headers-toggle-type)
+ (while (looking-at "[[:space:]]*[A-Za-z][-A-Za-z0-9]*:")
+ (beginning-of-line)
+ (notmuch-fontify-headers)
+ (forward-line)
+ )
+ (goto-char end)
+ (insert "\n")
+ (set-marker beg nil)
+ (set-marker summary-end nil)
+ (set-marker subject-end 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 ((message-begin (match-beginning 0)))
+ (re-search-forward notmuch-show-depth-match-regexp)
(let ((depth (string-to-number (buffer-substring (match-beginning 1) (match-end 1))))
+ (match (string= "1" (buffer-substring (match-beginning 2) (match-end 2))))
(btn nil))
- (setq btn (notmuch-show-markup-header depth))
- (notmuch-show-markup-body depth btn)))
+ (setq btn (notmuch-show-markup-header message-begin depth))
+ (notmuch-show-markup-body depth match btn)))
(goto-char (point-max))))
(defun notmuch-show-hide-markers ()
which this notmuch-show command was executed, (so that the next
thread from that buffer can be show when done with this one)."
(interactive "sNotmuch show: ")
- (let ((buffer (get-buffer-create (concat "*notmuch-show-" thread-id "*"))))
+ (let ((query notmuch-search-query-string)
+ (buffer (get-buffer-create (concat "*notmuch-show-" thread-id "*"))))
(switch-to-buffer buffer)
(notmuch-show-mode)
(set (make-local-variable 'notmuch-show-parent-buffer) parent-buffer)
(erase-buffer)
(goto-char (point-min))
(save-excursion
- (call-process notmuch-command nil t nil "show" "--entire-thread" thread-id)
+ (call-process notmuch-command nil t nil "show" "--entire-thread" thread-id "and (" query ")")
(notmuch-show-markup-messages)
)
(run-hooks 'notmuch-show-hook)
- ; Move straight to the first unread message
- (if (not (notmuch-show-message-unread-p))
- (progn
- (notmuch-show-next-unread-message)
- ; But if there are no unread messages, go back to the
- ; beginning of the buffer, and open up the bodies of all
- ; read message.
- (if (not (notmuch-show-message-unread-p))
- (progn
- (goto-char (point-min))
- (let ((btn (forward-button 1)))
- (while btn
- (if (button-has-type-p btn 'notmuch-button-body-toggle-type)
- (push-button))
- (condition-case err
- (setq btn (forward-button 1))
- (error (setq btn nil)))
- ))
- (goto-char (point-min))
- ))))
+ ; Move straight to the first open message
+ (if (not (notmuch-show-message-open-p))
+ (notmuch-show-next-open-message))
)))
(defvar notmuch-search-authors-width 40
(defvar notmuch-search-oldest-first t
"Show the oldest mail first in the search-mode")
+(defvar notmuch-search-disjunctive-regexp "\\<[oO][rR]\\>")
+
(defun notmuch-search-scroll-up ()
"Move forward through search results by one window's worth."
(interactive)
Runs a new search matching only messages that match both the
current search results AND the additional query string provided."
(interactive "sFilter search: ")
- (notmuch-search (concat notmuch-search-query-string " and " query) notmuch-search-oldest-first))
+ (let ((grouped-query (if (string-match-p notmuch-search-disjunctive-regexp query) (concat "( " query " )") query)))
+ (notmuch-search (concat notmuch-search-query-string " and " grouped-query) notmuch-search-oldest-first)))
(defun notmuch-search-filter-by-tag (tag)
"Filter the current search results based on a single tag.