X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=emacs%2Fnotmuch-lib.el;h=25d83fd61b49ca01aaa129de9f3ead93bec30ae6;hp=2f015b0d29b0d007136b711354f503e9d86f1c62;hb=8dcc38ce85ce084d3f0f3cbeac7e4a768e651614;hpb=07dff496304d6dc2e8033a18691b095ed9cd212f diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el index 2f015b0d..25d83fd6 100644 --- a/emacs/notmuch-lib.el +++ b/emacs/notmuch-lib.el @@ -27,6 +27,7 @@ (require 'mm-view) (require 'mm-decode) (require 'cl) +(require 'notmuch-compat) (unless (require 'notmuch-version nil t) (defconst notmuch-emacs-version "unknown" @@ -57,6 +58,10 @@ (custom-add-to-group 'notmuch-send 'message 'custom-group) +(defgroup notmuch-tag nil + "Tags and tagging in Notmuch." + :group 'notmuch) + (defgroup notmuch-crypto nil "Processing and display of cryptographic MIME parts." :group 'notmuch) @@ -69,6 +74,10 @@ "Running external commands from within Notmuch." :group 'notmuch) +(defgroup notmuch-address nil + "Address completion." + :group 'notmuch) + (defgroup notmuch-faces nil "Graphical attributes for displaying text" :group 'notmuch) @@ -147,6 +156,7 @@ For example, if you wanted to remove an \"inbox\" tag and add an (define-key map "z" 'notmuch-tree) (define-key map "m" 'notmuch-mua-new-mail) (define-key map "=" 'notmuch-refresh-this-buffer) + (define-key map (kbd "M-=") 'notmuch-refresh-all-buffers) (define-key map "G" 'notmuch-poll-and-refresh-this-buffer) (define-key map "j" 'notmuch-jump-search) map) @@ -413,10 +423,8 @@ of its command symbol." "Refresh the current buffer." (interactive) (when notmuch-buffer-refresh-function - (if (commandp notmuch-buffer-refresh-function) - ;; Pass prefix argument, etc. - (call-interactively notmuch-buffer-refresh-function) - (funcall notmuch-buffer-refresh-function)))) + ;; Pass prefix argument, etc. + (call-interactively notmuch-buffer-refresh-function))) (defun notmuch-poll-and-refresh-this-buffer () "Invoke `notmuch-poll' to import mail, then refresh the current buffer." @@ -424,6 +432,21 @@ of its command symbol." (notmuch-poll) (notmuch-refresh-this-buffer)) +(defun notmuch-refresh-all-buffers () + "Invoke `notmuch-refresh-this-buffer' on all notmuch major-mode buffers. + +The buffers are silently refreshed, i.e. they are not forced to +be displayed." + (interactive) + (dolist (buffer (buffer-list)) + (let ((buffer-mode (buffer-local-value 'major-mode buffer))) + (when (memq buffer-mode '(notmuch-show-mode + notmuch-tree-mode + notmuch-search-mode + notmuch-hello-mode)) + (with-current-buffer buffer + (notmuch-refresh-this-buffer)))))) + (defun notmuch-prettify-subject (subject) ;; This function is used by `notmuch-search-process-filter' which ;; requires that we not disrupt its' matching state. @@ -570,7 +593,7 @@ the given type." (set-buffer-multibyte nil)) (let ((args `("show" "--format=raw" ,(format "--part=%s" (plist-get part :id)) - ,@(when process-crypto '("--decrypt")) + ,@(when process-crypto '("--decrypt=true")) ,(notmuch-id-to-query (plist-get msg :id)))) (coding-system-for-read (if binaryp 'no-conversion @@ -745,23 +768,23 @@ signaled error. This function does not return." (error "%s" (concat msg (when extra " (see *Notmuch errors* for more details)")))) -(defun notmuch-check-async-exit-status (proc msg &optional command err-file) +(defun notmuch-check-async-exit-status (proc msg &optional command err) "If PROC exited abnormally, pop up an error buffer and signal an error. This is a wrapper around `notmuch-check-exit-status' for asynchronous process sentinels. PROC and MSG must be the -arguments passed to the sentinel. COMMAND and ERR-FILE, if -provided, are passed to `notmuch-check-exit-status'. If COMMAND -is not provided, it is taken from `process-command'." +arguments passed to the sentinel. COMMAND and ERR, if provided, +are passed to `notmuch-check-exit-status'. If COMMAND is not +provided, it is taken from `process-command'." (let ((exit-status (case (process-status proc) ((exit) (process-exit-status proc)) ((signal) msg)))) (when exit-status (notmuch-check-exit-status exit-status (or command (process-command proc)) - nil err-file)))) + nil err)))) -(defun notmuch-check-exit-status (exit-status command &optional output err-file) +(defun notmuch-check-exit-status (exit-status command &optional output err) "If EXIT-STATUS is non-zero, pop up an error buffer and signal an error. If EXIT-STATUS is non-zero, pop up a notmuch error buffer @@ -770,9 +793,9 @@ be a number indicating the exit status code of a process or a string describing the signal that terminated the process (such as returned by `call-process'). COMMAND must be a list giving the command and its arguments. OUTPUT, if provided, is a string -giving the output of command. ERR-FILE, if provided, is the name -of a file containing the error output of command. OUTPUT and the -contents of ERR-FILE will be included in the error message." +giving the output of command. ERR, if provided, is the error +output of command. OUTPUT and ERR will be included in the error +message." (cond ((eq exit-status 0) t) @@ -785,12 +808,7 @@ You may need to restart Emacs or upgrade your notmuch Emacs package.")) Emacs requested a newer output format than supported by the notmuch CLI. You may need to restart Emacs or upgrade your notmuch package.")) (t - (let* ((err (when err-file - (with-temp-buffer - (insert-file-contents err-file) - (unless (eobp) - (buffer-string))))) - (command-string + (let* ((command-string (mapconcat (lambda (arg) (shell-quote-argument (cond ((stringp arg) arg) @@ -866,9 +884,13 @@ error." (with-temp-buffer (let ((err-file (make-temp-file "nmerr"))) (unwind-protect - (let ((status (notmuch-call-notmuch--helper (list t err-file) args))) + (let ((status (notmuch-call-notmuch--helper (list t err-file) args)) + (err (with-temp-buffer + (insert-file-contents err-file) + (unless (eobp) + (buffer-string))))) (notmuch-check-exit-status status (cons notmuch-command args) - (buffer-string) err-file) + (buffer-string) err) (goto-char (point-min)) (read (current-buffer))) (delete-file err-file))))) @@ -887,30 +909,58 @@ invoke `set-process-sentinel' directly on the returned process, as that will interfere with the handling of stderr and the exit status." - ;; There is no way (as of Emacs 24.3) to capture stdout and stderr - ;; separately for asynchronous processes, or even to redirect stderr - ;; to a file, so we use a trivial shell wrapper to send stderr to a - ;; temporary file and clean things up in the sentinel. - (let* ((err-file (make-temp-file "nmerr")) - ;; Use a pipe - (process-connection-type nil) - ;; Find notmuch using Emacs' `exec-path' - (command (or (executable-find notmuch-command) - (error "command not found: %s" notmuch-command))) - (proc (apply #'start-process name buffer - "/bin/sh" "-c" - "exec 2>\"$1\"; shift; exec \"$0\" \"$@\"" - command err-file args))) - (process-put proc 'err-file err-file) + (let (err-file err-buffer proc err-proc + ;; Find notmuch using Emacs' `exec-path' + (command (or (executable-find notmuch-command) + (error "Command not found: %s" notmuch-command)))) + (if (fboundp 'make-process) + (progn + (setq err-buffer (generate-new-buffer " *notmuch-stderr*")) + ;; Emacs 25 and newer has `make-process', which allows + ;; redirecting stderr independently from stdout to a + ;; separate buffer. As this allows us to avoid using a + ;; temporary file and shell invocation, use it when + ;; available. + (setq proc (make-process + :name name + :buffer buffer + :command (cons command args) + :connection-type 'pipe + :stderr err-buffer) + err-proc (get-buffer-process err-buffer)) + (process-put proc 'err-buffer err-buffer) + + (process-put err-proc 'err-file err-file) + (process-put err-proc 'err-buffer err-buffer) + (set-process-sentinel err-proc #'notmuch-start-notmuch-error-sentinel)) + + ;; On Emacs versions before 25, there is no way to capture + ;; stdout and stderr separately for asynchronous processes, or + ;; even to redirect stderr to a file, so we use a trivial shell + ;; wrapper to send stderr to a temporary file and clean things + ;; up in the sentinel. + (setq err-file (make-temp-file "nmerr")) + (let ((process-connection-type nil)) ;; Use a pipe + (setq proc (apply #'start-process name buffer + "/bin/sh" "-c" + "exec 2>\"$1\"; shift; exec \"$0\" \"$@\"" + command err-file args))) + (process-put proc 'err-file err-file)) + (process-put proc 'sub-sentinel sentinel) (process-put proc 'real-command (cons notmuch-command args)) (set-process-sentinel proc #'notmuch-start-notmuch-sentinel) proc)) (defun notmuch-start-notmuch-sentinel (proc event) - (let ((err-file (process-get proc 'err-file)) - (sub-sentinel (process-get proc 'sub-sentinel)) - (real-command (process-get proc 'real-command))) + "Process sentinel function used by `notmuch-start-notmuch'." + (let* ((err-file (process-get proc 'err-file)) + (err-buffer (or (process-get proc 'err-buffer) + (find-file-noselect err-file))) + (err (when (not (zerop (buffer-size err-buffer))) + (with-current-buffer err-buffer (buffer-string)))) + (sub-sentinel (process-get proc 'sub-sentinel)) + (real-command (process-get proc 'real-command))) (condition-case err (progn ;; Invoke the sub-sentinel, if any @@ -922,12 +972,13 @@ status." ;; and there's no point in telling the user that (but we ;; still check for and report stderr output below). (when (buffer-live-p (process-buffer proc)) - (notmuch-check-async-exit-status proc event real-command err-file)) + (notmuch-check-async-exit-status proc event real-command err)) ;; If that didn't signal an error, then any error output was ;; really warning output. Show warnings, if any. (let ((warnings - (with-temp-buffer - (unless (= (second (insert-file-contents err-file)) 0) + (when err + (with-current-buffer err-buffer + (goto-char (point-min)) (end-of-line) ;; Show first line; stuff remaining lines in the ;; errors buffer. @@ -941,7 +992,15 @@ status." ;; Emacs behaves strangely if an error escapes from a sentinel, ;; so turn errors into messages. (message "%s" (error-message-string err)))) - (ignore-errors (delete-file err-file)))) + (when err-file (ignore-errors (delete-file err-file))))) + +(defun notmuch-start-notmuch-error-sentinel (proc event) + (let* ((err-file (process-get proc 'err-file)) + ;; When `make-process' is available, use the error buffer + ;; associated with the process, otherwise the error file. + (err-buffer (or (process-get proc 'err-buffer) + (find-file-noselect err-file)))) + (when err-buffer (kill-buffer err-buffer)))) ;; This variable is used only buffer local, but it needs to be ;; declared globally first to avoid compiler warnings.