(require 'notmuch-hello)
(require 'notmuch-maildir-fcc)
(require 'notmuch-message)
+(require 'notmuch-parser)
(defcustom notmuch-search-result-format
`(("date" . "%12s ")
(defvar notmuch-search-mode-map
(let ((map (make-sparse-keymap)))
(define-key map "?" 'notmuch-help)
- (define-key map "q" 'notmuch-search-quit)
- (define-key map "x" 'notmuch-search-quit)
+ (define-key map "q" 'notmuch-kill-this-buffer)
+ (define-key map "x" 'notmuch-kill-this-buffer)
(define-key map (kbd "<DEL>") 'notmuch-search-scroll-down)
(define-key map "b" 'notmuch-search-scroll-down)
(define-key map " " 'notmuch-search-scroll-up)
(define-key map "s" 'notmuch-search)
(define-key map "o" 'notmuch-search-toggle-order)
(define-key map "c" 'notmuch-search-stash-map)
- (define-key map "=" 'notmuch-search-refresh-view)
- (define-key map "G" 'notmuch-search-poll-and-refresh-view)
+ (define-key map "=" 'notmuch-refresh-this-buffer)
+ (define-key map "G" 'notmuch-poll-and-refresh-this-buffer)
(define-key map "t" 'notmuch-search-filter-by-tag)
(define-key map "f" 'notmuch-search-filter)
(define-key map [mouse-1] 'notmuch-search-show-thread)
(defvar notmuch-search-query-string)
(defvar notmuch-search-target-thread)
(defvar notmuch-search-target-line)
-(defvar notmuch-search-continuation)
(defvar notmuch-search-disjunctive-regexp "\\<[oO][rR]\\>")
-(defun notmuch-search-quit ()
- "Exit the search buffer, calling any defined continuation function."
- (interactive)
- (let ((continuation notmuch-search-continuation))
- (notmuch-kill-this-buffer)
- (when continuation
- (funcall continuation))))
-
(defun notmuch-search-scroll-up ()
"Move forward through search results by one window's worth."
(interactive)
participants in the thread, a representative subject line, and
any tags).
-Pressing \\[notmuch-search-show-thread] on any line displays that thread. The '\\[notmuch-search-add-tag]' and '\\[notmuch-search-remove-tag]'
-keys can be used to add or remove tags from a thread. The '\\[notmuch-search-archive-thread]' key
-is a convenience for archiving a thread (removing the \"inbox\"
-tag). The '\\[notmuch-search-tag-all]' key can be used to add and/or remove tags from all
-messages (as opposed to threads) that match the current query. Use with caution, as this
-will also tag matching messages that arrived *after* constructing the buffer.
-
-Other useful commands are '\\[notmuch-search-filter]' for filtering the current search
-based on an additional query string, '\\[notmuch-search-filter-by-tag]' for filtering to include
-only messages with a given tag, and '\\[notmuch-search]' to execute a new, global
-search.
+Pressing \\[notmuch-search-show-thread] on any line displays that
+thread. The '\\[notmuch-search-add-tag]' and
+'\\[notmuch-search-remove-tag]' keys can be used to add or remove
+tags from a thread. The '\\[notmuch-search-archive-thread]' key
+is a convenience for archiving a thread (applying changes in
+`notmuch-archive-tags'). The '\\[notmuch-search-tag-all]' key can
+be used to add and/or remove tags from all messages (as opposed
+to threads) that match the current query. Use with caution, as
+this will also tag matching messages that arrived *after*
+constructing the buffer.
+
+Other useful commands are '\\[notmuch-search-filter]' for
+filtering the current search based on an additional query string,
+'\\[notmuch-search-filter-by-tag]' for filtering to include only
+messages with a given tag, and '\\[notmuch-search]' to execute a
+new, global search.
Complete list of currently available key bindings:
(make-local-variable 'notmuch-search-oldest-first)
(make-local-variable 'notmuch-search-target-thread)
(make-local-variable 'notmuch-search-target-line)
- (set (make-local-variable 'notmuch-search-continuation) nil)
+ (setq notmuch-buffer-refresh-function #'notmuch-search-refresh-view)
(set (make-local-variable 'scroll-preserve-screen-position) t)
(add-to-invisibility-spec (cons 'ellipsis t))
(use-local-map notmuch-search-mode-map)
(defun notmuch-search-tag-region (beg end &optional tag-changes)
"Change tags for threads in the given region."
(let ((search-string (notmuch-search-find-thread-id-region-search beg end)))
- (setq tag-changes (funcall 'notmuch-tag search-string tag-changes))
+ (setq tag-changes (notmuch-tag search-string tag-changes))
(notmuch-search-foreach-result beg end
(lambda (pos)
(notmuch-search-set-tags
(interactive)
(let* ((beg (if (region-active-p) (region-beginning) (point)))
(end (if (region-active-p) (region-end) (point))))
- (funcall 'notmuch-search-tag-region beg end tag-changes)))
+ (notmuch-search-tag-region beg end tag-changes)))
(defun notmuch-search-add-tag ()
"Same as `notmuch-search-tag' but sets initial input to '+'."
(insert "Incomplete search results (search process was killed).\n"))
(when (eq status 'exit)
(insert "End of search results.\n")
- (condition-case nil
- (notmuch-check-async-exit-status proc msg)
- ;; Suppress the error signal since strange
- ;; things happen if a sentinel signals.
- (error (throw 'return nil)))
+ ;; For version mismatch, there's no point in
+ ;; showing the search buffer
+ (when (or (= exit-status 20) (= exit-status 21))
+ (kill-buffer)
+ (throw 'return nil))
(if (and atbob
(not (string= notmuch-search-target-thread "found")))
(set 'never-found-target-thread t)))))
(notmuch-search-insert-authors format-string (plist-get result :authors)))
((string-equal field "tags")
- (let ((tags-str (mapconcat 'identity (plist-get result :tags) " ")))
- (insert (propertize (format format-string tags-str)
- 'face 'notmuch-tag-face))))))
+ (let ((tags (plist-get result :tags)))
+ (insert (format format-string (notmuch-tag-format-tags tags)))))))
(defun notmuch-search-show-result (result &optional pos)
"Insert RESULT at POS or the end of the buffer if POS is null."
(setq notmuch-search-target-thread "found")
(goto-char beg)))))
-(defun notmuch-search-show-error (string &rest objects)
- (save-excursion
- (goto-char (point-max))
- (insert "Error: Unexpected output from notmuch search:\n")
- (insert (apply #'format string objects))
- (insert "\n")))
-
(defun notmuch-search-process-filter (proc string)
"Process and filter the output of \"notmuch search\""
(let ((results-buf (process-buffer proc))
(parse-buf (process-get proc 'parse-buf))
(inhibit-read-only t)
done)
- (if (not (buffer-live-p results-buf))
- (delete-process proc)
+ (when (buffer-live-p results-buf)
(with-current-buffer parse-buf
;; Insert new data
(save-excursion
(goto-char (point-max))
(insert string))
- (notmuch-json-parse-partial-list 'notmuch-search-show-result
- 'notmuch-search-show-error
+ (notmuch-sexp-parse-partial-list 'notmuch-search-show-result
results-buf)))))
(defun notmuch-search-tag-all (&optional tag-changes)
'notmuch-search-history nil nil)))))
;;;###autoload
-(defun notmuch-search (&optional query oldest-first target-thread target-line continuation)
+(defun notmuch-search (&optional query oldest-first target-thread target-line)
"Run \"notmuch search\" with the given `query' and display results.
If `query' is nil, it is read interactively from the minibuffer.
target-thread: A thread ID (without the thread: prefix) that will be made
current if it appears in the search results.
target-line: The line number to move to if the target thread does not
- appear in the search results."
- (interactive)
- (if (null query)
- (setq query (notmuch-read-query "Notmuch search: ")))
- (let ((buffer (get-buffer-create (notmuch-search-buffer-title query))))
+ appear in the search results.
+
+When called interactively, this will prompt for a query and use
+the configured default sort order."
+ (interactive
+ (list
+ ;; Prompt for a query
+ nil
+ ;; Use the default search order (if we're doing a search from a
+ ;; search buffer, ignore any buffer-local overrides)
+ (default-value notmuch-search-oldest-first)))
+
+ (let* ((query (or query (notmuch-read-query "Notmuch search: ")))
+ (buffer (get-buffer-create (notmuch-search-buffer-title query))))
(switch-to-buffer buffer)
(notmuch-search-mode)
;; Don't track undo information for this buffer
(set 'notmuch-search-oldest-first oldest-first)
(set 'notmuch-search-target-thread target-thread)
(set 'notmuch-search-target-line target-line)
- (set 'notmuch-search-continuation continuation)
(let ((proc (get-buffer-process (current-buffer)))
(inhibit-read-only t))
(if proc
(erase-buffer)
(goto-char (point-min))
(save-excursion
- (let ((proc (start-process
- "notmuch-search" buffer
- notmuch-command "search"
- "--format=json"
+ (let ((proc (notmuch-start-notmuch
+ "notmuch-search" buffer #'notmuch-search-process-sentinel
+ "search" "--format=sexp" "--format-version=1"
(if oldest-first
"--sort=oldest-first"
"--sort=newest-first")
;; should be called no matter how the process dies.
(parse-buf (generate-new-buffer " *notmuch search parse*")))
(process-put proc 'parse-buf parse-buf)
- (set-process-sentinel proc 'notmuch-search-process-sentinel)
(set-process-filter proc 'notmuch-search-process-filter)
(set-process-query-on-exit-flag proc nil))))
(run-hooks 'notmuch-search-hook)))
the new search results, then point will be placed on the same
thread. Otherwise, point will be moved to attempt to be in the
same relative position within the new buffer."
- (interactive)
(let ((target-line (line-number-at-pos))
(oldest-first notmuch-search-oldest-first)
(target-thread (notmuch-search-find-thread-id 'bare))
- (query notmuch-search-query-string)
- (continuation notmuch-search-continuation))
+ (query notmuch-search-query-string))
(notmuch-kill-this-buffer)
- (notmuch-search query oldest-first target-thread target-line continuation)
+ (notmuch-search query oldest-first target-thread target-line)
(goto-char (point-min))))
-(defcustom notmuch-poll-script nil
- "An external script to incorporate new mail into the notmuch database.
-
-This variable controls the action invoked by
-`notmuch-search-poll-and-refresh-view' and
-`notmuch-hello-poll-and-update' (each have a default keybinding
-of 'G') to incorporate new mail into the notmuch database.
-
-If set to nil (the default), new mail is processed by invoking
-\"notmuch new\". Otherwise, this should be set to a string that
-gives the name of an external script that processes new mail. If
-set to the empty string, no command will be run.
-
-The external script could do any of the following depending on
-the user's needs:
-
-1. Invoke a program to transfer mail to the local mail store
-2. Invoke \"notmuch new\" to incorporate the new mail
-3. Invoke one or more \"notmuch tag\" commands to classify the mail
-
-Note that the recommended way of achieving the same is using
-\"notmuch new\" hooks."
- :type '(choice (const :tag "notmuch new" nil)
- (const :tag "Disabled" "")
- (string :tag "Custom script"))
- :group 'notmuch-external)
-
-(defun notmuch-poll ()
- "Run \"notmuch new\" or an external script to import mail.
-
-Invokes `notmuch-poll-script', \"notmuch new\", or does nothing
-depending on the value of `notmuch-poll-script'."
- (interactive)
- (if (stringp notmuch-poll-script)
- (unless (string= notmuch-poll-script "")
- (call-process notmuch-poll-script nil nil))
- (call-process notmuch-command nil nil nil "new")))
-
-(defun notmuch-search-poll-and-refresh-view ()
- "Invoke `notmuch-poll' to import mail, then refresh the current view."
- (interactive)
- (notmuch-poll)
- (notmuch-search-refresh-view))
-
(defun notmuch-search-toggle-order ()
"Toggle the current search order.
-By default, the \"inbox\" view created by `notmuch' is displayed
-in chronological order (oldest thread at the beginning of the
-buffer), while any global searches created by `notmuch-search'
-are displayed in reverse-chronological order (newest thread at
-the beginning of the buffer).
-
-This command toggles the sort order for the current search.
-
-Note that any filtered searches created by
-`notmuch-search-filter' retain the search order of the parent
-search."
+This command toggles the sort order for the current search. The
+default sort order is defined by `notmuch-search-oldest-first'."
(interactive)
(set 'notmuch-search-oldest-first (not notmuch-search-oldest-first))
(notmuch-search-refresh-view))