From 5e5a74ed22a3f15c656743f9179cc8d2f7b75c94 Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Sun, 8 Jan 2023 13:39:42 +0200 Subject: [PATCH] mu4e: use caching for modeline items Avoid excessive (unnecessary) recalculation. --- mu4e/mu4e-bookmarks.el | 124 +++++++++++++++++++---------------------- mu4e/mu4e-context.el | 14 +++-- mu4e/mu4e-main.el | 6 +- mu4e/mu4e-modeline.el | 43 +++++++++----- mu4e/mu4e-search.el | 4 +- mu4e/mu4e.el | 11 ++-- 6 files changed, 105 insertions(+), 97 deletions(-) diff --git a/mu4e/mu4e-bookmarks.el b/mu4e/mu4e-bookmarks.el index 1189172e..c22937c1 100644 --- a/mu4e/mu4e-bookmarks.el +++ b/mu4e/mu4e-bookmarks.el @@ -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)))))) diff --git a/mu4e/mu4e-context.el b/mu4e/mu4e-context.el index f6b4847d..042b9220 100644 --- a/mu4e/mu4e-context.el +++ b/mu4e/mu4e-context.el @@ -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." diff --git a/mu4e/mu4e-main.el b/mu4e/mu4e-main.el index 8462462b..b1ef5d7f 100644 --- a/mu4e/mu4e-main.el +++ b/mu4e/mu4e-main.el @@ -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)) diff --git a/mu4e/mu4e-modeline.el b/mu4e/mu4e-modeline.el index 51d966b3..22d81c72 100644 --- a/mu4e/mu4e-modeline.el +++ b/mu4e/mu4e-modeline.el @@ -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 diff --git a/mu4e/mu4e-search.el b/mu4e/mu4e-search.el index b6b48105..6e7da095 100644 --- a/mu4e/mu4e-search.el +++ b/mu4e/mu4e-search.el @@ -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))))) diff --git a/mu4e/mu4e.el b/mu4e/mu4e.el index 0abb1156..8cb272f2 100644 --- a/mu4e/mu4e.el +++ b/mu4e/mu4e.el @@ -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))))))