diff --git a/mu4e/mu4e-main.el b/mu4e/mu4e-main.el index 68ce1a74..dd00763f 100644 --- a/mu4e/mu4e-main.el +++ b/mu4e/mu4e-main.el @@ -45,7 +45,6 @@ (define-key map "m" 'mu4e~main-toggle-mail-sending-mode) (define-key map "f" 'smtpmail-send-queued-mail) - ;; (define-key map "U" 'mu4e-update-mail-and-index) (define-key map (kbd "C-S-u") 'mu4e-update-mail-and-index) @@ -106,6 +105,35 @@ clicked." (- (length newstr) 1) 'mouse-face 'highlight newstr) newstr)) + +(defun mu4e~main-bookmarks () + ;; TODO: it's a bit uncool to hard-code the "b" shortcut... + (mapconcat + (lambda (bm) + (unless (plist-get bm :hide) + (let* ((key (plist-get bm :key)) + (name (plist-get bm :name)) + (query (plist-get bm :query)) + (qcounts + (seq-filter (lambda (q) + (string= (plist-get q :query) query)) + (plist-get mu4e~server-props :queries)))) + (concat + ;; menu entry + (mu4e~main-action-str + (concat "\t* [b" (make-string 1 key) "] " name) + (concat "b" (make-string 1 key))) + ;; append all/unread numbers, if available. + (if qcounts + (let ((unread (propertize (format "%s" (plist-get (car qcounts) :unread)) + 'face 'mu4e-header-key-face)) + (count (propertize(format "%s" (plist-get (car qcounts) :count)) + 'face 'default))) + (concat " (" unread "/" count ")")) + ""))))) + (mu4e-bookmarks) "\n")) + + ;; NEW ;; This is the old `mu4e~main-view' function but without ;; buffer switching at the end. @@ -132,15 +160,7 @@ clicked." "\t* [C]ompose a new message\n" 'mu4e-compose-new) "\n" (propertize " Bookmarks\n\n" 'face 'mu4e-title-face) - ;; TODO: it's a bit uncool to hard-code the "b" shortcut... - (mapconcat - (lambda (bm) - (unless (plist-get bm :hide) - (mu4e~main-action-str - (concat "\t* [b" (make-string 1 (plist-get bm :key)) "] " - (plist-get bm :name)) - (concat "b" (make-string 1 (plist-get bm :key)))))) - (mu4e-bookmarks) "\n") + (mu4e~main-bookmarks) "\n\n" (propertize " Misc\n\n" 'face 'mu4e-title-face) diff --git a/mu4e/mu4e-proc.el b/mu4e/mu4e-proc.el index 1bf2b550..7eca9643 100644 --- a/mu4e/mu4e-proc.el +++ b/mu4e/mu4e-proc.el @@ -468,9 +468,12 @@ to a temporary file, then respond with :what ,what :param ,param))) -(defun mu4e~proc-ping () - "Sends a ping to the mu server, expecting a (:pong ...) in response." - (mu4e~call-mu '(ping))) +(defun mu4e~proc-ping (&optional queries) + "Sends a ping to the mu server, expecting a (:pong ...) in response. +QUERIES is a list of queries for the number of results with read/unread status +are returned in the 'pong' response." + (mu4e~call-mu `(ping + :queries ,queries))) (defun mu4e~proc-contacts (personal after tstamp) "Ask for contacts with PERSONAL AFTER TSTAMP. diff --git a/mu4e/mu4e-utils.el b/mu4e/mu4e-utils.el index 690423e4..1918e970 100644 --- a/mu4e/mu4e-utils.el +++ b/mu4e/mu4e-utils.el @@ -693,8 +693,10 @@ This is used by the completion function in mu4e-compose." (puthash address (cdr contact) mu4e~contacts)))) (setq mu4e~contacts-tstamp (or tstamp "0")) - (mu4e-index-message "Contacts updated: %d; total %d" - n (hash-table-count mu4e~contacts)))) + + (unless (zerop n) + (mu4e-index-message "Contacts updated: %d; total %d" + n (hash-table-count mu4e~contacts))))) (defun mu4e-contacts-info () "Display information about the cache used for contacts @@ -784,6 +786,23 @@ nothing." (mu4e-parse-time-string mu4e-compose-complete-only-after)))) mu4e~contacts-tstamp))) +(defun mu4e~pong-handler (props func) + "Handle 'pong' responses from the mu server." + (setq mu4e~server-props props) ;; save props from the server + (let ((version (plist-get props :version)) + (doccount (plist-get props :doccount))) + (mu4e~check-requirements) + (when func (funcall func)) + (when (zerop doccount) + (mu4e-message "Store is empty; (re)indexing. This can take a while.") ; + (mu4e-update-index)) + (when (and mu4e-update-interval (null mu4e~update-timer)) + (setq mu4e~update-timer + (run-at-time 0 mu4e-update-interval + (lambda () (mu4e-update-mail-and-index + mu4e-index-update-in-background))))))) + + (defun mu4e~start (&optional func) "If `mu4e-contexts' have been defined, but we don't have a context yet, switch to the matching one, or none matches, the @@ -791,7 +810,7 @@ first. If mu4e is already running, execute function FUNC (if non-nil). Otherwise, check various requireme`'nts, then start mu4e. When successful, call FUNC (if non-nil) afterwards." ;; if we're already running, simply go to the main view - (if (mu4e-running-p) ;; already running? + (if (and nil mu4e-running-p) ;; already running? (when func (funcall func)) ;; yes! run func if defined (progn ;; no! try to set a context, do some checks, set up pong handler and ping @@ -799,26 +818,15 @@ When successful, call FUNC (if non-nil) afterwards." (mu4e~context-autoswitch nil mu4e-context-policy) (mu4e~check-requirements) ;; set up the 'pong' handler func - (setq mu4e-pong-func - (lambda (props) - (setq mu4e~server-props props) ;; save props from the server - (let ((version (plist-get props :version)) - (doccount (plist-get props :doccount))) - (mu4e~check-requirements) - (when func (funcall func)) - (when (zerop doccount) - (mu4e-message "Store is empty; (re)indexing. This can take a while.") ; - (mu4e-update-index)) - (when (and mu4e-update-interval (null mu4e~update-timer)) - (setq mu4e~update-timer - (run-at-time - 0 mu4e-update-interval - (lambda () (mu4e-update-mail-and-index - mu4e-index-update-in-background))))) - (mu4e-message "Started mu4e with %d message%s in store" - doccount (if (= doccount 1) "" "s"))))) + (setq mu4e-pong-func #'(lambda (props) (mu4e~pong-handler props func))) ;; wake up server - (mu4e~proc-ping) + (mu4e~proc-ping + (mapcar ;; send it a list of queries we'd like to see read/unread info + ;; for. + (lambda(bm) (plist-get bm :query)) + (seq-filter (lambda (bm) ;; exclude bookmarks with these flags. + (not (or (plist-get bm :hide) (plist-get bm :hide-unread)))) + mu4e-bookmarks))) ;; maybe request the list of contacts, automatically refresh after ;; reindexing (mu4e~request-contacts-maybe)))) @@ -961,7 +969,7 @@ run in the background; otherwise, pop up a window." ;; ;;(switch-to-buffer buf) ;; (set-window-dedicated-p win t) (erase-buffer) - (insert "\n") ;; FIXME -- needed so output start + (insert "\n") ;; FIXME -- needed so output starts (mu4e~update-mail-mode))) (setq mu4e~progress-reporter (unless mu4e-hide-index-messages diff --git a/mu4e/mu4e-vars.el b/mu4e/mu4e-vars.el index afe974b8..863d1929 100644 --- a/mu4e/mu4e-vars.el +++ b/mu4e/mu4e-vars.el @@ -81,8 +81,6 @@ already retrieved in another way." :group 'mu4e :safe 'stringp) - - (defcustom mu4e-index-update-error-warning t "Whether to display warnings during the retrieval process. This depends on the `mu4e-get-mail-command' exit code." @@ -206,6 +204,8 @@ If the string exceeds this limit, it will be truncated to fit." "Create a mu4e proplist with the following elements: - `name': the user-visible name of the bookmark - `key': a single key to search for this bookmark +- `show-unread' whether to show an indicator for read/unread messages. Specifying +this for too many bookmarks may incur slowdowns in showing the mu4e main page. - `query': the query for this bookmark. Either a literal string or a function that evaluates to a string." `(:name ,name :query ,query :key ,key)) @@ -221,6 +221,7 @@ are plists" "1.3.7") :key ?t) ( :name "Last 7 days" :query "date:7d..now" + :show-unread t :key ?w) ( :name "Messages with images" :query "mime:image/*" @@ -234,6 +235,9 @@ Each of the list elements is a plist with at least: Optionally, you add the following: :hide - if t, bookmark is hdden from the main-view and speedbar. +:hide-unread - do not show the counts of unread/total number + of matches for the query. This can be useful if a bookmark uses + a very slow query. :hide-unread is implied from :hide. " :type '(repeat (plist)) :group 'mu4e) diff --git a/mu4e/mu4e.texi b/mu4e/mu4e.texi index b7c033dc..b2976389 100644 --- a/mu4e/mu4e.texi +++ b/mu4e/mu4e.texi @@ -12,7 +12,7 @@ @c %**end of header @copying -Copyright @copyright{} 2012-2019 Dirk-Jan C. Binnema +Copyright @copyright{} 2012-2020 Dirk-Jan C. Binnema @quotation Permission is granted to copy, distribute and/or modify this document @@ -674,7 +674,7 @@ The main view looks something like the following: @cartouche @verbatim -* mu4e - mu for emacs version 0.X.X CG +* mu4e - mu for emacs version @value{VERSION}; (in store: 78379 messages) Basics @@ -684,14 +684,10 @@ The main view looks something like the following: Bookmarks - * [bu] Unread messages - * [bt] Today's messages - * [bw] Last 7 days - * [bp] Messages with images - * [bs] Sent mail - * [bf] Flagged messages - * [b]] Flow - * [b/] Test + * [bu] Unread messages (26217/26217) + * [bt] Today's messages (2/8) + * [bw] Last 7 days (7/34) + * [bp] Messages with images (276/2315) Misc @@ -706,15 +702,6 @@ The main view looks something like the following: @end verbatim @end cartouche -In the example above, you can see the letters ``@t{CG}'', which indicate: -@itemize -@item @t{C}: support for decryption of encrypted messages, and verifying -signatures. See @ref{MSGV Crypto} in the @ref{Message view} for details. -@item @t{G}: support for the Guile 2.0 programming language -@end itemize -Whether you see both, one or none of these letters depends on the way @t{mu} -is built. - Let's walk through the menu. @node Basic actions @@ -738,11 +725,16 @@ the @ref{Editor view} to write a new message. @node MV Bookmarks @section Bookmarks -The next item in the Main view is @emph{Bookmarks}. Bookmarks are predefined -queries with a descriptive name and a shortcut --- in the example above, we see -the default bookmarks. You can view the list of messages matching a certain -bookmark by pressing @key{b} followed by the bookmark's shortcut. If you'd -like to edit the bookmarked query first before invoking it, use @key{B}. +The next item in the Main view is @emph{Bookmarks}. + +Bookmarks are predefined queries with a descriptive name and a +shortcut --- in the example above, we see the default bookmarks. You +can view the list of messages matching a certain bookmark by pressing +@key{b} followed by the bookmark's shortcut. If you'd like to edit the +bookmarked query first before invoking it, use @key{B}. + +Next to each bookmark there is the number of (unread/all) messages +that match. Bookmarks are stored in the variable @code{mu4e-bookmarks}; you can add your own and/or replace the default ones; @xref{Bookmarks}. @@ -1966,27 +1958,35 @@ mu4e-search-bookmark-edit}) which lets you edit the bookmark first. be instructive: @lisp -(defvar mu4e-bookmarks - '( ( :name "Unread messages" - :query "flag:unread AND NOT flag:trashed" - :key ?u) - ( :name "Today's messages" - :query "date:today..now" - :key ?t) - ( :name "Last 7 days" - :query "date:7d..now" - :key ?w) - ( :name "Messages with images" - :query "mime:image/*" - :key ?p)) - "A list of pre-defined queries. Each query is represented by a -mu4e-bookmark structure with parameters @t{:name} with the name -of the bookmark, @t{:query} with the query expression (a query -string or an s-expression that evaluates to query string) and a -@t{:key}, which is the shortcut-key for the query. +(defcustom mu4e-bookmarks + '(( :name "Unread messages" + :query "flag:unread AND NOT flag:trashed" + :key ?u) + ( :name "Today's messages" + :query "date:today..now" + :key ?t) + ( :name "Last 7 days" + :query "date:7d..now" + :show-unread t + :key ?w) + ( :name "Messages with images" + :query "mime:image/*" + :key ?p)) + "List of pre-defined queries that are shown on the main screen. -An older form of bookmark, a 3-item list with (QUERY DESCRIPTION -KEY) is still recognized as well, for backward-compatibility.") +Each of the list elements is a plist with at least: +:name - the name of the queryt +:query - the query expression +:key - the shortcut key. + +Optionally, you add the following: +:hide - if t, bookmark is hdden from the main-view and speedbar. +:hide-unread - do not show the counts of unread/total number + of matches for the query. This can be useful if a bookmark uses + a very slow query. :hide-unread is implied from :hide. +" + :type '(repeat (plist)) + :group 'mu4e) @end lisp You can replace these or add your own items, by putting in your