;; Have fun, and let us know if you have any comment, questions, or
;; kudos: Notmuch list <notmuch@notmuchmail.org> (subscription is not
;; required, but is available from https://notmuchmail.org).
-
+;;
+;; Note for MELPA users (and others tracking the development version
+;; of notmuch-emacs):
+;;
+;; This emacs package needs a fairly closely matched version of the
+;; notmuch program. If you use the MELPA version of notmuch.el (as
+;; opposed to MELPA stable), you should be prepared to track the
+;; master development branch (i.e. build from git) for the notmuch
+;; program as well. Upgrading notmuch-emacs too far beyond the notmuch
+;; program can CAUSE YOUR EMAIL TO STOP WORKING.
+;;
+;; TL;DR: notmuch-emacs from MELPA and notmuch from distro packages is
+;; NOT SUPPORTED.
+;;
;;; Code:
(eval-when-compile (require 'cl))
(define-key map "-" 'notmuch-search-remove-tag)
(define-key map "+" 'notmuch-search-add-tag)
(define-key map (kbd "RET") 'notmuch-search-show-thread)
+ (define-key map (kbd "M-RET") 'notmuch-tree-from-search-thread)
(define-key map "Z" 'notmuch-tree-from-search-current-query)
map)
"Keymap for \"notmuch search\" buffers.")
:group 'notmuch-faces)
(defface notmuch-search-flagged-face
- '((t
+ '((((class color)
+ (background dark))
+ (:foreground "LightBlue1"))
+ (((class color)
+ (background light))
(:foreground "blue")))
"Face used in search mode face for flagged threads.
(set (make-local-variable 'scroll-preserve-screen-position) t)
(add-to-invisibility-spec (cons 'ellipsis t))
(setq truncate-lines t)
- (setq buffer-read-only t))
+ (setq buffer-read-only t)
+ (setq imenu-prev-index-position-function
+ #'notmuch-search-imenu-prev-index-position-function)
+ (setq imenu-extract-index-name-function
+ #'notmuch-search-imenu-extract-index-name-function))
(defun notmuch-search-get-result (&optional pos)
"Return the result object for the thread at POS (or point).
(next-single-property-change (or pos (point)) 'notmuch-search-result
nil (point-max))))
-(defun notmuch-search-foreach-result (beg end function)
- "Invoke FUNCTION for each result between BEG and END.
+(defun notmuch-search-foreach-result (beg end fn)
+ "Invoke FN for each result between BEG and END.
-FUNCTION should take one argument. It will be applied to the
+FN should take one argument. It will be applied to the
character position of the beginning of each result that overlaps
the region between points BEG and END. As a special case, if (=
-BEG END), FUNCTION will be applied to the result containing point
+BEG END), FN will be applied to the result containing point
BEG."
(lexical-let ((pos (notmuch-search-result-beginning beg))
- ;; End must be a marker in case function changes the
+ ;; End must be a marker in case fn changes the
;; text.
(end (copy-marker end))
;; Make sure we examine at least one result, even if
;; pos.
(while (and pos (or (< pos end) first))
(when (notmuch-search-get-result pos)
- (funcall function pos))
+ (funcall fn pos))
(setq pos (notmuch-search-result-end pos)
first nil))))
;; Unindent the function argument of notmuch-search-foreach-result so
(setq output (append output (notmuch-search-get-tags pos)))))
output))
-(defun notmuch-search-interactive-region ()
- "Return the bounds of the current interactive region.
-
-This returns (BEG END), where BEG and END are the bounds of the
-region if the region is active, or both `point' otherwise."
- (if (region-active-p)
- (list (region-beginning) (region-end))
- (list (point) (point))))
-
(defun notmuch-search-interactive-tag-changes (&optional initial-input)
"Prompt for tag changes for the current thread or region.
Returns (TAG-CHANGES REGION-BEGIN REGION-END)."
- (let* ((region (notmuch-search-interactive-region))
+ (let* ((region (notmuch-interactive-region))
(beg (first region)) (end (second region))
(prompt (if (= beg end) "Tag thread" "Tag region")))
(cons (notmuch-read-tag-changes
See `notmuch-tag' for information on the format of TAG-CHANGES.
When called interactively, this uses the region if the region is
active. When called directly, BEG and END provide the region.
-If these are nil or not provided, this applies to the thread at
-point.
+If these are nil or not provided, then, if the region is active
+this applied to all threads meeting the region, and if the region
+is inactive this applies to the thread at point.
If ONLY-MATCHED is non-nil, only tag matched messages."
(interactive (notmuch-search-interactive-tag-changes))
- (unless (and beg end) (setq beg (point) end (point)))
+ (unless (and beg end)
+ (setq beg (car (notmuch-interactive-region))
+ end (cadr (notmuch-interactive-region))))
(let ((search-string (notmuch-search-find-stable-query-region
beg end only-matched)))
(notmuch-tag search-string tag-changes)
`notmuch-archive-tags' will be reversed).
This function advances the next thread when finished."
- (interactive (cons current-prefix-arg (notmuch-search-interactive-region)))
+ (interactive (cons current-prefix-arg (notmuch-interactive-region)))
(when notmuch-archive-tags
(notmuch-search-tag
(notmuch-tag-change-list notmuch-archive-tags unarchive) beg end))
Here is an example of how to color search results based on tags.
(the following text would be placed in your ~/.emacs file):
- (setq notmuch-search-line-faces '((\"unread\" . (:foreground \"green\"))
+ (setq notmuch-search-line-faces \\='((\"unread\" . (:foreground \"green\"))
(\"deleted\" . (:foreground \"red\"
:background \"blue\"))))
"Return the current query in this search buffer"
notmuch-search-query-string)
-;;;###autoload
(put 'notmuch-search 'notmuch-doc "Search for messages.")
+;;;###autoload
(defun notmuch-search (&optional query oldest-first target-thread target-line no-display)
"Display threads matching QUERY in a notmuch-search buffer.
(save-excursion
(let ((proc (notmuch-start-notmuch
"notmuch-search" buffer #'notmuch-search-process-sentinel
- "search" "--format=sexp" "--format-version=2"
+ "search" "--format=sexp" "--format-version=4"
(if oldest-first
"--sort=oldest-first"
"--sort=newest-first")
Runs a new search matching only messages that match both the
current search results AND that are tagged with the given tag."
(interactive
- (list (notmuch-select-tag-with-completion "Filter by tag: ")))
+ (list (notmuch-select-tag-with-completion "Filter by tag: " notmuch-search-query-string)))
(notmuch-search (concat notmuch-search-query-string " and tag:" tag) notmuch-search-oldest-first))
;;;###autoload
(with-current-buffer b
(memq major-mode '(notmuch-show-mode
notmuch-search-mode
+ notmuch-tree-mode
notmuch-hello-mode
- message-mode))))
+ notmuch-message-mode))))
;;;###autoload
(defun notmuch-cycle-notmuch-buffers ()
;; Find the first notmuch buffer.
(setq first (loop for buffer in (buffer-list)
- if (notmuch-interesting-buffer buffer)
- return buffer))
+ if (notmuch-interesting-buffer buffer)
+ return buffer))
(if first
;; If the first one we found is any other than the starting
(switch-to-buffer first))
(notmuch))))
+;;;; Imenu Support
+
+(defun notmuch-search-imenu-prev-index-position-function ()
+ "Move point to previous message in notmuch-search buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'."
+ (notmuch-search-previous-thread))
+
+(defun notmuch-search-imenu-extract-index-name-function ()
+ "Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line."
+ (let ((subject (notmuch-search-find-subject))
+ (author (notmuch-search-find-authors)))
+ (format "%s (%s)" subject author)))
+
(setq mail-user-agent 'notmuch-user-agent)
(provide 'notmuch)