X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=emacs%2Fnotmuch-lib.el;h=c146748ac2935206377a8418bfc6a5cf5b105fd2;hp=f93c957d5d72d0cc26704c673341471fc58d20ac;hb=596a2076dcc1ebec2dc217f6d967397ef125aac4;hpb=22472d9def2f6525a9aac62e6481d8d4fa7db5d0 diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el index f93c957d..c146748a 100644 --- a/emacs/notmuch-lib.el +++ b/emacs/notmuch-lib.el @@ -21,6 +21,8 @@ ;; This is an part of an emacs-based interface to the notmuch mail system. +(eval-when-compile (require 'cl)) + (defvar notmuch-command "notmuch" "Command to run the notmuch binary.") @@ -28,17 +30,54 @@ "Notmuch mail reader for Emacs." :group 'mail) +(defgroup notmuch-hello nil + "Overview of saved searches, tags, etc." + :group 'notmuch) + +(defgroup notmuch-search nil + "Searching and sorting mail." + :group 'notmuch) + +(defgroup notmuch-show nil + "Showing messages and threads." + :group 'notmuch) + +(defgroup notmuch-send nil + "Sending messages from Notmuch." + :group 'notmuch) + +(custom-add-to-group 'notmuch-send 'message 'custom-group) + +(defgroup notmuch-crypto nil + "Processing and display of cryptographic MIME parts." + :group 'notmuch) + +(defgroup notmuch-hooks nil + "Running custom code on well-defined occasions." + :group 'notmuch) + +(defgroup notmuch-external nil + "Running external commands from within Notmuch." + :group 'notmuch) + +(defgroup notmuch-faces nil + "Graphical attributes for displaying text" + :group 'notmuch) + (defcustom notmuch-search-oldest-first t "Show the oldest mail first when searching." :type 'boolean - :group 'notmuch) + :group 'notmuch-search) ;; +(defvar notmuch-search-history nil + "Variable to store notmuch searches history.") + (defcustom notmuch-saved-searches nil "A list of saved searches to display." :type '(alist :key-type string :value-type string) - :group 'notmuch) + :group 'notmuch-hello) (defvar notmuch-folders nil "Deprecated name for what is now known as `notmuch-saved-searches'.") @@ -96,6 +135,15 @@ the user hasn't set this variable with the old or new value." (interactive) (kill-buffer (current-buffer))) +(defun notmuch-prettify-subject (subject) + ;; This function is used by `notmuch-search-process-filter' which + ;; requires that we not disrupt its' matching state. + (save-match-data + (if (and subject + (string-match "^[ \t]*$" subject)) + "[No Subject]" + subject))) + ;; (defun notmuch-common-do-stash (text) @@ -105,21 +153,6 @@ the user hasn't set this variable with the old or new value." ;; -;; XXX: This should be a generic function in emacs somewhere, not -;; here. -(defun point-invisible-p () - "Return whether the character at point is invisible. - -Here visibility is determined by `buffer-invisibility-spec' and -the invisible property of any overlays for point. It doesn't have -anything to do with whether point is currently being displayed -within the current window." - (let ((prop (get-char-property (point) 'invisible))) - (if (eq buffer-invisibility-spec t) - prop - (or (memq prop buffer-invisibility-spec) - (assq prop buffer-invisibility-spec))))) - (defun notmuch-remove-if-not (predicate list) "Return a copy of LIST with all items not satisfying PREDICATE removed." (let (out) @@ -129,19 +162,80 @@ within the current window." (setq list (cdr list))) (nreverse out))) -; This lets us avoid compiling these replacement functions when emacs -; is sufficiently new enough to supply them alone. We do the macro -; treatment rather than just wrapping our defun calls in a when form -; specifically so that the compiler never sees the code on new emacs, -; (since the code is triggering warnings that we don't know how to get -; rid of. -; -; A more clever macro here would accept a condition and a list of forms. +;; This lets us avoid compiling these replacement functions when emacs +;; is sufficiently new enough to supply them alone. We do the macro +;; treatment rather than just wrapping our defun calls in a when form +;; specifically so that the compiler never sees the code on new emacs, +;; (since the code is triggering warnings that we don't know how to get +;; rid of. +;; +;; A more clever macro here would accept a condition and a list of forms. (defmacro compile-on-emacs-prior-to-23 (form) "Conditionally evaluate form only on emacs < emacs-23." (list 'when (< emacs-major-version 23) form)) +(defun notmuch-split-content-type (content-type) + "Split content/type into 'content' and 'type'" + (split-string content-type "/")) + +(defun notmuch-match-content-type (t1 t2) + "Return t if t1 and t2 are matching content types, taking wildcards into account" + (let ((st1 (notmuch-split-content-type t1)) + (st2 (notmuch-split-content-type t2))) + (if (or (string= (cadr st1) "*") + (string= (cadr st2) "*")) + (string= (car st1) (car st2)) + (string= t1 t2)))) + +(defvar notmuch-multipart/alternative-discouraged + '( + ;; Avoid HTML parts. + "text/html" + ;; multipart/related usually contain a text/html part and some associated graphics. + "multipart/related" + )) + +(defun notmuch-multipart/alternative-choose (types) + "Return a list of preferred types from the given list of types" + ;; Based on `mm-preferred-alternative-precedence'. + (let ((seq types)) + (dolist (pref (reverse notmuch-multipart/alternative-discouraged)) + (dolist (elem (copy-sequence seq)) + (when (string-match pref elem) + (setq seq (nconc (delete elem seq) (list elem)))))) + seq)) + +(defun notmuch-parts-filter-by-type (parts type) + "Given a list of message parts, return a list containing the ones matching +the given type." + (remove-if-not + (lambda (part) (notmuch-match-content-type (plist-get part :content-type) type)) + parts)) + +;; Helper for parts which are generally not included in the default +;; JSON output. +(defun notmuch-get-bodypart-internal (message-id part-number process-crypto) + (let ((args '("show" "--format=raw")) + (part-arg (format "--part=%s" part-number))) + (setq args (append args (list part-arg))) + (if process-crypto + (setq args (append args '("--decrypt")))) + (setq args (append args (list message-id))) + (with-temp-buffer + (let ((coding-system-for-read 'no-conversion)) + (progn + (apply 'call-process (append (list notmuch-command nil (list t nil) nil) args)) + (buffer-string)))))) + +(defun notmuch-get-bodypart-content (msg part nth process-crypto) + (or (plist-get part :content) + (notmuch-get-bodypart-internal (concat "id:" (plist-get msg :id)) nth process-crypto))) + +(defun notmuch-plist-to-alist (plist) + (loop for (key value . rest) on plist by #'cddr + collect (cons (substring (symbol-name key) 1) value))) + ;; Compatibility functions for versions of emacs before emacs 23. ;; ;; Both functions here were copied from emacs 23 with the following copyright: