mu4e-alert icon indicating copy to clipboard operation
mu4e-alert copied to clipboard

Trouble with latest mu4e

Open antoine-levitt opened this issue 3 years ago • 26 comments

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.

antoine-levitt avatar Jun 11 '21 07:06 antoine-levitt

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.

OlMon avatar Jul 31 '21 08:07 OlMon

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?

OlMon avatar Jul 31 '21 16:07 OlMon

Are you missing the first line?

antoine-levitt avatar Jul 31 '21 16:07 antoine-levitt

Are you missing the first line?

Yes... sry for that. Fixed!

OlMon avatar Jul 31 '21 16:07 OlMon

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.

antoine-levitt avatar Jul 31 '21 16:07 antoine-levitt

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))

xzz53 avatar Aug 12 '21 17:08 xzz53

It says "callback not found" when I put this in my .emacs? Possibly a lexical/dynamical scope thing?

antoine-levitt avatar Aug 13 '21 11:08 antoine-levitt

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! :)

xzz53 avatar Aug 13 '21 12:08 xzz53

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.

antoine-levitt avatar Aug 15 '21 09:08 antoine-levitt

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).

xzz53 avatar Aug 15 '21 14:08 xzz53

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))

xzz53 avatar Aug 15 '21 16:08 xzz53

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.

antoine-levitt avatar Aug 15 '21 18:08 antoine-levitt

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.

xzz53 avatar Aug 15 '21 18:08 xzz53

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

antoine-levitt avatar Aug 16 '21 06:08 antoine-levitt

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.

xzz53 avatar Aug 16 '21 13:08 xzz53

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?

antoine-levitt avatar Aug 19 '21 07:08 antoine-levitt

@xzz53 I'm afraid your fork is going to become the next mu4e-alert :)

nbarrientos avatar Aug 23 '21 15:08 nbarrientos

@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 avatar Aug 23 '21 15:08 xzz53

@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 avatar Aug 23 '21 15:08 polaris64

@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 avatar Aug 23 '21 16:08 xzz53

@xzz53 Thanks for sorting that out :)

polaris64 avatar Aug 23 '21 16:08 polaris64

Any hopes of getting this fix within the package?

simurgh9 avatar Nov 06 '21 21:11 simurgh9

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?

archer-65 avatar Jan 02 '22 22:01 archer-65

Hi @archer-65! Please submit a PR against https://github.com/xzz53/mu4e-alert.

xzz53 avatar Jan 03 '22 01:01 xzz53

Hi @archer-65! Please submit a PR against https://github.com/xzz53/mu4e-alert.

Done!

archer-65 avatar Jan 03 '22 13:01 archer-65

Hi all, https://github.com/xzz53/mu4e-alert is now official repo in melpa. PRs are welcome!

xzz53 avatar Mar 20 '22 20:03 xzz53