mu4e: use caching for modeline items

Avoid excessive (unnecessary) recalculation.
This commit is contained in:
Dirk-Jan C. Binnema 2023-01-08 13:39:42 +02:00
parent f77bc903e7
commit 5e5a74ed22
6 changed files with 105 additions and 97 deletions

View File

@ -167,11 +167,11 @@ the latest query-results.")
(defun mu4e--reset-baseline ()
(setq mu4e--baseline (mu4e-server-query-results)
mu4e--baseline-tstamp (current-time))
(mu4e-last-query-results 'force)) ; for side-effects
(mu4e-last-query-results 'refresh)) ; for side-effects
(defvar mu4e--last-query-results-cached nil)
(defun mu4e-last-query-results(&optional force)
(defun mu4e-last-query-results(&optional refresh)
"Get the results (counts) of the latest queries.
Either read form the cache or update them when oudated or FORCE
@ -195,32 +195,32 @@ The results are a list of elements of the form
baseline part is optional (see `mu4e-reset-query-results') for
more details).
Uses a cached string unless its nil or FORCE is non-nil."
(if (and mu4e--last-query-results-cached (not force))
mu4e--last-query-results-cached ;; use cache
;; otherwise, recalculate.
(let* ((favorite (mu4e-favorite-bookmark))
(favorite-query
(and favorite (mu4e--bookmark-query favorite))))
(setq mu4e--last-query-results-cached ;; walk over the remembered queries
;; and augment them with the baseline data and ':favorite' flag, if
;; any.
(seq-map
(lambda (qres)
;; note: queries can be _functions_ too; use their
;; string value.
(let* ((query (mu4e--bookmark-query qres))
(bres (seq-find ;; find the corresponding baseline entry
(lambda (bq)
(string= query (mu4e--bookmark-query bq)))
mu4e--baseline)))
(when (string= query (or favorite-query ""))
(plist-put qres :favorite t))
(when bres
(plist-put qres :baseline
`(:count ,(plist-get bres :count)
:unread ,(plist-get bres :unread))))
qres)) (mu4e-server-query-results))))))
Uses a cached string unless it is nil or REFRESH is non-nil."
(or (and (not refresh) mu4e--last-query-results-cached)
(setq mu4e--last-query-results-cached
(let* ((favorite (mu4e-favorite-bookmark))
(favorite-query
(and favorite (mu4e--bookmark-query favorite))))
;; walk over the remembered queries
;; and augment them with the baseline data and ':favorite' flag, if
;; any.
(seq-map
(lambda (qres)
;; note: queries can be _functions_ too; use their
;; string value.
(let* ((query (mu4e--bookmark-query qres))
(bres (seq-find ;; find the corresponding baseline entry
(lambda (bq)
(string= query (mu4e--bookmark-query bq)))
mu4e--baseline)))
(when (string= query (or favorite-query ""))
(plist-put qres :favorite t))
(when bres
(plist-put qres :baseline
`(:count ,(plist-get bres :count)
:unread ,(plist-get bres :unread))))
qres))
(mu4e-server-query-results))))))
(defun mu4e-last-query-result (query)
"Get the last result for some QUERY or nil if not found.
@ -247,51 +247,39 @@ I.e., very new messages.")
(when-let ((fav (mu4e--bookmark-query (mu4e-favorite-bookmark))))
(mu4e-search-bookmark fav)))
(defvar mu4e--bookmarks-modeline-cached nil)
(defun mu4e--bookmarks-modeline-item ()
"Modeline item showing message counts for the favorite bookmark.
This uses the one special ':favorite' bookmark, and if there is
one, creates a propertized string for display in the modeline."
(or mu4e--bookmarks-modeline-cached
(setq mu4e--bookmarks-modeline-cached
(when-let ((fav ;; any results for the favorite bookmark item?
(seq-find (lambda (bm) (plist-get bm :favorite))
(mu4e-last-query-results))))
(let* ((unread (plist-get fav :unread))
(count (plist-get fav :count))
(baseline (plist-get fav :baseline))
(baseline-unread
(or (when baseline (plist-get baseline :unread)) unread))
(delta (- unread baseline-unread)))
(propertize
(format "%s%s%s/%s "
(funcall (if mu4e-use-fancy-chars 'cdr 'car)
(cond
((> delta 0) mu4e-modeline-new-items)
((> unread 0) mu4e-modeline-unread-items)
((> count 0) mu4e-modeline-all-read)
(t mu4e-modeline-all-clear)))
(propertize (number-to-string unread) 'face 'mu4e-header-key-face)
(if (<= delta 0) ""
(propertize (format "(%+d)" delta)
'face 'mu4e-unread-face))
(number-to-string count))
'help-echo (format "mu4e query: '%s'" (mu4e--bookmark-query fav))
'mouse-face 'mode-line-highlight
'keymap '(mode-line keymap
(mouse-1 . mu4e-jump-to-favorite)
(mouse-2 . mu4e-jump-to-favorite)
(mouse-3 . mu4e-jump-to-favorite))))))))
(defun mu4e--modeline-update()
"Update the modeline and redisplay if mu4e-modeline-mode is
active."
(when mu4e-modeline-mode
(setq mu4e--bookmarks-modeline-cached nil) ;; force recalculation
(force-mode-line-update)))
(when-let ((fav ;; any results for the favorite bookmark item?
(seq-find (lambda (bm) (plist-get bm :favorite))
(mu4e-last-query-results))))
(let* ((unread (plist-get fav :unread))
(count (plist-get fav :count))
(baseline (plist-get fav :baseline))
(baseline-unread
(or (when baseline (plist-get baseline :unread)) unread))
(delta (- unread baseline-unread)))
(propertize
(format "%s%s%s/%s "
(funcall (if mu4e-use-fancy-chars 'cdr 'car)
(cond
((> delta 0) mu4e-modeline-new-items)
((> unread 0) mu4e-modeline-unread-items)
((> count 0) mu4e-modeline-all-read)
(t mu4e-modeline-all-clear)))
(propertize (number-to-string unread) 'face 'mu4e-header-key-face)
(if (<= delta 0) ""
(propertize (format "(%+d)" delta)
'face 'mu4e-unread-face))
(number-to-string count))
'help-echo (format "mu4e query: '%s'" (mu4e--bookmark-query fav))
'mouse-face 'mode-line-highlight
'keymap '(mode-line keymap
(mouse-1 . mu4e-jump-to-favorite)
(mouse-2 . mu4e-jump-to-favorite)
(mouse-3 . mu4e-jump-to-favorite))))))

View File

@ -146,6 +146,7 @@ non-nil."
(setq mu4e--context-current context)
(run-hooks 'mu4e-context-changed-hook)
(mu4e--modeline-update)
(mu4e-message "Switched context to %s" (mu4e-context-name context)))
context))
@ -207,12 +208,13 @@ as it is."
(eval ,@body))))
(defun mu4e--context-modeline-item ()
"Propertized string with the current context name.
An empty string \"\" if there is none."
(if (mu4e-context-current)
(concat "[" (propertize (mu4e-quote-for-modeline
(mu4e-context-name (mu4e-context-current)))
'face 'mu4e-context-face) "] " ) ""))
"Propertized string with the current context or nil."
(when (mu4e-context-current)
(concat
"["
(propertize (mu4e-quote-for-modeline
(mu4e-context-name (mu4e-context-current)))
'face 'mu4e-context-face) "] " )))
(define-minor-mode mu4e-context-minor-mode
"Mode for switching the mu4e context."

View File

@ -130,6 +130,7 @@ This version handles updating the current screen as well."
(mu4e-context-minor-mode)
(mu4e-search-minor-mode)
(mu4e-update-minor-mode)
(mu4e-modeline-mode)
(setq-local revert-buffer-function
(lambda (_ignore-auto _noconfirm)
(mu4e--main-view 'refresh))))
@ -352,13 +353,14 @@ character of the keyboard shortcut
(declare-function mu4e--start "mu4e")
(defun mu4e--main-view (&optional refresh)
(defun mu4e--main-view (&optional refresh no-reset)
"Create or refresh the mu4e main-view, and switch to it.
When REFRESH is non nil refresh infos from server.
If `mu4e-split-view' equals \='single-window, show a mu4e menu
instead."
(mu4e--reset-baseline)
(unless no-reset
(mu4e--reset-baseline))
(if (eq mu4e-split-view 'single-window)
(mu4e--main-menu)
(let ((buf (get-buffer-create mu4e-main-buffer-name))

View File

@ -22,8 +22,8 @@
;;; Commentary:
;; This file contains functionality for putting mu4e-related information
;; in the emacs modeline, both buffer-specific and globally.
;; This file contains functionality for putting mu4e-related information in the
;; Emacs modeline, both buffer-specific and globally.
;;; Code:
@ -38,24 +38,35 @@ Each element is function that evaluates to a string.")
Each element is function that evaluates to a string.")
(defun mu4e--modeline-register (func &optional global)
"Register a function for calculating some mu4e modeline part.
"Register FUNC for calculating some mu4e modeline part.
If GLOBAL is non-nil, add to the global-modeline; otherwise use
the buffer-local one."
(add-to-list
(if global 'mu4e--modeline-global-items 'mu4e--modeline-buffer-items)
(if global
'mu4e--modeline-global-items
'mu4e--modeline-buffer-items)
func))
(defvar mu4e--modeline-item nil
"Mu4e item for the global-mode-line.")
(defvar mu4e--modeline-string-cached nil
"Cached version of the modeline string.")
(defun mu4e--modeline-string ()
"Calculate the current mu4e modeline string."
(mapconcat
(lambda (item)
(if (functionp item)
(or (funcall item) "")
""))
(append mu4e--modeline-buffer-items mu4e--modeline-global-items) " "))
"Get the current mu4e modeline string."
(or mu4e--modeline-string-cached
(setq mu4e--modeline-string-cached
(mapconcat
(lambda (func) (or (funcall func) ""))
(append mu4e--modeline-buffer-items
mu4e--modeline-global-items)
" "))))
(defun mu4e--modeline-update ()
"Recalculate and force-update the modeline."
(setq mu4e--modeline-string-cached nil)
(force-mode-line-update))
(define-minor-mode mu4e-modeline-mode
"Minor mode for showing mu4e information on the modeline."
@ -68,12 +79,14 @@ the buffer-local one."
(if mu4e-modeline-mode
(progn
(setq mu4e--modeline-item '(:eval (mu4e--modeline-string)))
(add-to-list 'global-mode-string mu4e--modeline-item))
(add-to-list 'global-mode-string mu4e--modeline-item)
(mu4e--modeline-update))
(progn
(setq global-mode-string
(seq-remove (lambda (item) (equal item mu4e--modeline-item))
global-mode-string))))
(force-mode-line-update))
global-mode-string)))
(force-mode-line-update)))
(provide 'mu4e-modeline)
;; mu4e-modeline.el ends here
;;; mu4e-modeline.el ends here

View File

@ -204,7 +204,8 @@ show the message with MSGID."
(mu4e-mark-handle-when-leaving)
(mu4e--search-execute expr ignore-history)
(setq mu4e--search-msgid-target msgid
mu4e--search-view-target show)))
mu4e--search-view-target show)
(mu4e--modeline-update)))
(defun mu4e-search-edit ()
"Edit the last search expression."
@ -459,6 +460,7 @@ If KEY is provided, use it instead of asking user."
(when choice
(set choice (not (symbol-value choice)))
(mu4e-message "Set `%s' to %s" (symbol-name choice) (symbol-value choice))
(mu4e--modeline-update)
(unless dont-refresh
(mu4e-search-rerun)))))

View File

@ -156,10 +156,11 @@ Invoke FUNC if non-nil."
;; (if any) and the modeline.
;; 1. update the query results (i.e. process the new server queries)
(mu4e-last-query-results 'force-update)
(unless mu4e--baseline
(mu4e--reset-baseline))
(mu4e--modeline-update)
(mu4e-last-query-results 'refresh)
(if mu4e--baseline
(mu4e-last-query-results 'refresh)
(mu4e--reset-baseline))
;; note: mu4e-reset-baseline implies mu4e--last-query-results
;; 2. update the main view, if any
(when (buffer-live-p mu4e-main-buffer-name)
@ -261,7 +262,7 @@ Otherwise, check requirements, then start mu4e. When successful, invoke
(when (and (buffer-live-p mainbuf) (get-buffer-window mainbuf))
(save-window-excursion
(select-window (get-buffer-window mainbuf))
(mu4e--main-view 'refresh))))))
(mu4e--main-view 'refresh 'no-reset))))))
((plist-get info :message)
(mu4e-index-message "%s" (plist-get info :message))))))