mu4e-alert
mu4e-alert copied to clipboard
Trouble with latest mu4e
I haven't been able to diagnose exactly what's wrong, but mu4e-alert doesn't seem to update itself as it should whenever I mark mail as unread in recent versions of mu4e. See discussion in https://github.com/djcb/mu/issues/2023. Running mu4e-update-index, waiting for a bit while the index gets updated, then running mu4e-alert-update-mail-count-modeline, works, so I'm guessing some hooks are not run at the right time.
The notification also don't work. At least when after the first notification. Starting mu4e the first bunch of notification will show up. After that no notification will be shown. Don't know if this is related, but it seems the package needs an overhaul.
Looked around a little and fixed the notifications:
(defun mu4e-alert--get-mu4e-frame ()
"Try getting a frame containing a mu4e buffer."
(car (delq nil (mapcar (lambda (buffer)
(when (and buffer
(get-buffer-window buffer t))
(window-frame (get-buffer-window buffer t))))
(list mu4e-main-buffer-name)))))
(defun mu4e-alert-filter-repeated-mails (mails)
"Filters the MAILS that have been seen already."
(cl-remove-if (lambda (mail)
(prog1 (and (not mu4e-alert-notify-repeated-mails)
(ht-get mu4e-alert-repeated-mails
(plist-get mail :message-id)))
(ht-set! mu4e-alert-repeated-mails
(plist-get mail :message-id)
t)
))
mails))
Load this after loading the mu4e-alert package and the notifications should display. @antoine-levitt Does this also fix the modeline issue?
Are you missing the first line?
Are you missing the first line?
Yes... sry for that. Fixed!
It might fix the notifications and the mode line updating on new messages (haven't tested yet) but it doesn't fix the mode line updating issue when eg marking an email as read or unread.
Here is a quick hack which fixes the issues with marking messages read/unread. The idea is to use the same mu
server communication mechanism as mu4e
does itself, thus avoiding caching troubles. mu4e
's callbacks are temporarily overridden when issuing a request and restored after a :found
message from the server is received. It heavily depends on mu4e internals, so it will probably break after updates. Nevertheless, it works quite reliably on 1.6.1
. The following code should be evaluated after mu4e-alert
is loaded.
(defvar mu4e-alert--header-func-save)
(defvar mu4e-alert--found-func-save)
(defvar mu4e-alert--erase-func-save)
(defvar mu4e-alert--messages)
(defun mu4e-alert--erase-func ()
"Erase handler for mu process.")
(defun mu4e-alert--get-found-func (callback)
"Create found handler for mu process.
CALLBACK will be invoked by returned lambda"
(lambda (found)
(funcall callback mu4e-alert--messages)
(setq mu4e-header-func mu4e-alert--header-func-save
mu4e-found-func mu4e-alert--found-func-save
mu4e-erase-func mu4e-alert--erase-func-save)))
(defun mu4e-alert--header-func (msg)
"Message header handler for mu process.
MSG argument is message plist."
(push msg mu4e-alert--messages))
(defun mu4e-alert--get-mu-unread-emails-1 (callback)
"Get messages from mu and invoke CALLBACK."
(setq mu4e-alert--header-func-save mu4e-header-func
mu4e-alert--found-func-save mu4e-found-func
mu4e-alert--erase-func-save mu4e-erase-func)
(setq mu4e-header-func 'mu4e-alert--header-func
mu4e-found-func (mu4e-alert--get-found-func callback)
mu4e-erase-func 'mu4e-alert--erase-func)
(setq mu4e-alert--messages nil)
(mu4e~proc-find mu4e-alert-interesting-mail-query
nil
:date
nil
mu4e-alert-max-messages-to-process
nil
nil))
It says "callback not found" when I put this in my .emacs? Possibly a lexical/dynamical scope thing?
It says "callback not found" when I put this in my .emacs? Possibly a lexical/dynamical scope thing?
Yes, I have lexical scoping enabled for my init file. Looks like the following should work without enabling lexical scoping:
(defvar mu4e-alert--header-func-save)
(defvar mu4e-alert--found-func-save)
(defvar mu4e-alert--erase-func-save)
(defvar mu4e-alert--messages)
(defun mu4e-alert--erase-func ()
"Erase handler for mu process.")
(defun mu4e-alert--get-found-func (callback)
"Create found handler for mu process.
CALLBACK will be invoked by retturned lambda"
(lexical-let ((cb callback))
(lambda (found)
(funcall cb mu4e-alert--messages)
(setq mu4e-header-func mu4e-alert--header-func-save
mu4e-found-func mu4e-alert--found-func-save
mu4e-erase-func mu4e-alert--erase-func-save))))
(defun mu4e-alert--header-func (msg)
"Message header handler for mu process.
MSG argument is message plist."
(push msg mu4e-alert--messages))
(defun mu4e-alert--get-mu-unread-emails-1 (callback)
"Get messages from mu and invoke CALLBACK."
(when (mu4e~proc-running-p)
(setq mu4e-alert--header-func-save mu4e-header-func
mu4e-alert--found-func-save mu4e-found-func
mu4e-alert--erase-func-save mu4e-erase-func)
(setq mu4e-header-func 'mu4e-alert--header-func
mu4e-found-func (mu4e-alert--get-found-func callback)
mu4e-erase-func 'mu4e-alert--erase-func)
(setq mu4e-alert--messages nil)
(mu4e~proc-find mu4e-alert-interesting-mail-query
nil
:date
nil
mu4e-alert-max-messages-to-process
nil
nil)))
Any ideas on how to improve it are welcome! :)
Thanks! It doesn't fix it fully (eg open an email, mark it as unread, quit mu4e, it doesn't update the mode line), but it does seem to improve things.
Looks like it's a different class of problem, i.e. mu4e-alert-update-mail-count-modeline
is not called at the correct time. And the code above actually fixes "mu4e-alert-update-mail-count-modeline
showing wrong number of unread messages". You can check this by evaluating (mu4e-alert-update-mail-count-modeline)
manually when you expect the counter to update. I'll try to look into this. Meanwhile, if I understand your case correctly, you can execute marks via x in the header view, and the mode line counter will update (at least it does so for me).
It turns out that mu4e-message-changed-hook
is not executed when the headers view is not visible, which is your case. So instead of using this hook, we can advice mu4e~headers-update-handler
. It works for me. If you still have issues, please post detailed steps to reproduce it.
(defun mu4e-alert-enable-mode-line-display ()
"Enable display of unread emails in mode-line."
(interactive)
(add-to-list 'global-mode-string '(:eval mu4e-alert-mode-line) t)
(add-hook 'mu4e-view-mode-hook #'mu4e-alert-update-mail-count-modeline)
(add-hook 'mu4e-index-updated-hook #'mu4e-alert-update-mail-count-modeline)
(advice-add #'mu4e~headers-update-handler
:after (lambda (&rest _) (mu4e-alert-update-mail-count-modeline))
'((name . "mu4e-alert")))
(ad-enable-advice #'mu4e-context-switch 'around 'mu4e-alert-update-mail-count-modeline)
(ad-activate #'mu4e-context-switch)
(mu4e-alert-update-mail-count-modeline))
(defun mu4e-alert-disable-mode-line-display ()
"Disable display of unread emails in mode-line."
(interactive)
(setq global-mode-string (delete '(:eval mu4e-alert-mode-line) global-mode-string))
(remove-hook 'mu4e-view-mode-hook #'mu4e-alert-update-mail-count-modeline)
(remove-hook 'mu4e-index-updated-hook #'mu4e-alert-update-mail-count-modeline)
(advice-remove #'mu4e~headers-update-handler "mu4e-alert")
(ad-disable-advice #'mu4e-context-switch 'around 'mu4e-alert-update-mail-count-modeline)
(ad-deactivate #'mu4e-context-switch))
Nice, thanks a lot! It still does not work when showing the headers window (without a view window), marking a message as read/unread (without opening it) and then quitting mu4e, but that's a minor annoyance compared to the previous state of affairs.
Do you mean killing the headers view without executing the marks? I'm not sure if mu4e is supposed to actually change the messages' state in this case.
It does: mu4e-headers-leave-behavior controls what happens. Sorry if I was not clear, I mean quitting the headers view the "normal" way, ie with q
Ahh, I understand now. But this is exactly the case that was fixed for me by using updated mu4e-alert-enable-mode-line-display
from https://github.com/iqbalansari/mu4e-alert/issues/40#issuecomment-899081641. :man_shrugging:
BTW, I pushed the above fixes to a fork at https://github.com/xzz53/mu4e-alert.
Hm, I might have customization interfering with this, I'll take a look when I have more time. Is the original maintainer of mu4e-alet not around to merge this to the main branch?
@xzz53 I'm afraid your fork is going to become the next mu4e-alert :)
@xzz53 I'm afraid your fork is going to become the next mu4e-alert :)
Well that was not intended. The fixes are hacky and prone to breakage with mu4e
updates. The proper solution is to define API in collaboration with mu4e
maintainer and use it. I don't feel like doing it now though. So I'll try to keep it more or less working in my fork until I stop using mu4e
or someone else implements better solution. :)
@xzz53 Thank you for putting all of these changes into a fork :)
I've noticed that it doesn't seem to work with Emacs 28.0.50 however. Specifically it seems that lexical-let
is no longer available. Here's a diff which allows it to work for me: -
diff --git a/mu4e-alert.el b/mu4e-alert.el
index 98130ae..b75f6be 100644
--- a/mu4e-alert.el
+++ b/mu4e-alert.el
@@ -218,14 +218,12 @@ See also https://github.com/jwiegley/alert."
(defun mu4e-alert--get-found-func (callback)
"Create found handler for mu process.
-CALLBACK will be invoked by retturned lambda"
- (lexical-let ((cb callback))
- (lambda (found)
- ;; (message (format "%d unread messages" (length mu4e-alert--messages)))
- (funcall cb mu4e-alert--messages)
- (setq mu4e-header-func mu4e-alert--header-func-save
- mu4e-found-func mu4e-alert--found-func-save
- mu4e-erase-func mu4e-alert--erase-func-save))))
+CALLBACK will be invoked by returned lambda"
+ (lambda (found)
+ (funcall callback mu4e-alert--messages)
+ (setq mu4e-header-func mu4e-alert--header-func-save
+ mu4e-found-func mu4e-alert--found-func-save
+ mu4e-erase-func mu4e-alert--erase-func-save)))
(defun mu4e-alert--header-func (msg)
"Message header handler for mu process.
I don't think you have the issue tracker enabled for your fork on GitHub, so I hope it's OK that I mentioned it here?
@polaris64, thanks, pushed. I've also enabled the issue tracker on the fork repo, not sure I'll have enough time to properly maintain it though.
@xzz53 Thanks for sorting that out :)
Any hopes of getting this fix within the package?
Looked around a little and fixed the notifications:
(defun mu4e-alert--get-mu4e-frame () "Try getting a frame containing a mu4e buffer." (car (delq nil (mapcar (lambda (buffer) (when (and buffer (get-buffer-window buffer t)) (window-frame (get-buffer-window buffer t)))) (list mu4e-main-buffer-name))))) (defun mu4e-alert-filter-repeated-mails (mails) "Filters the MAILS that have been seen already." (cl-remove-if (lambda (mail) (prog1 (and (not mu4e-alert-notify-repeated-mails) (ht-get mu4e-alert-repeated-mails (plist-get mail :message-id))) (ht-set! mu4e-alert-repeated-mails (plist-get mail :message-id) t) )) mails))
Load this after loading the mu4e-alert package and the notifications should display. @antoine-levitt Does this also fix the modeline issue?
@xzz53 Can you include this in your fork?
Hi @archer-65! Please submit a PR against https://github.com/xzz53/mu4e-alert.
Hi @archer-65! Please submit a PR against https://github.com/xzz53/mu4e-alert.
Done!
Hi all, https://github.com/xzz53/mu4e-alert is now official repo in melpa. PRs are welcome!