diff --git a/modules/email/mu4e/README.org b/modules/email/mu4e/README.org index 4717c5691..b7a285a6c 100644 --- a/modules/email/mu4e/README.org +++ b/modules/email/mu4e/README.org @@ -116,6 +116,8 @@ sudo apt-get install maildir-utils mu4e # mu and mu4e respectivly + Tidied mu4e headers view, with flags from =all-the-icons= + Consistent colouring of reply depths (across compose and gnus modes) + Prettified =mu4e:main= view ++ Cooperative locking of the =mu= process. Another Emacs instance may request + access, or grab the lock when it's available. + =org-msg= integration - can be toggled per-message by applying the universal argument (=SPC u=) to the compose/reply/forward action. diff --git a/modules/email/mu4e/autoload/email.el b/modules/email/mu4e/autoload/email.el index 5fb1b6c99..bef0961e4 100644 --- a/modules/email/mu4e/autoload/email.el +++ b/modules/email/mu4e/autoload/email.el @@ -268,6 +268,7 @@ clicked." (list :style (format "transform: scale(%.3f)" (/ 1.0 (plist-get org-format-latex-options :scale)))))) +;;;###autoload (defun +org-html-latex-fragment-scaled (latex-fragment _contents info) "Transcode a LATEX-FRAGMENT object from Org to HTML. CONTENTS is nil. INFO is a plist holding contextual information. @@ -299,6 +300,7 @@ account for the value of :scale in `org-format-latex-options'." (org-html--format-image source attributes info))))) (t latex-frag)))) +;;;###autoload (defun +org-html-latex-environment-scaled (latex-environment _contents info) "Transcode a LATEX-ENVIRONMENT element from Org to HTML. CONTENTS is nil. INFO is a plist holding contextual information. @@ -343,3 +345,95 @@ scales the image to account for the value of :scale in `org-format-latex-options (org-html--format-image source attributes info) info caption label))))) (t (org-html--wrap-latex-environment latex-frag info caption label))))) + +;; +;; Cooperative locking + +(defvar +mu4e-lock-file "/tmp/mu4e_lock" + "Location of the lock file which stores the PID of the process currenty running mu4e") +(defvar +mu4e-lock-request-file "/tmp/mu4e_lock_request" + "Location of the lock file for which creating indicated that another process wants the lock to be released") + +(defvar +mu4e-lock-greedy nil + "Whether to 'grab' the `+mu4e-lock-file' if nobody else has it, i.e. start Mu4e") +(defvar +mu4e-lock-relaxed nil + "Whether if someone else wants the lock (signaled via `+mu4e-lock-request-file'), we should stop Mu4e and let go of it") + +;;;###autoload +(defun +mu4e-lock-pid-info () + "Get info on the PID refered to in `+mu4e-lock-file' in the form (pid . process-attributes) + If the file or process do not exist, the lock file is deleted an nil returned." + (when (file-exists-p +mu4e-lock-file) + (let* ((pid (string-to-number (f-read-text +mu4e-lock-file 'utf-8))) + (process (process-attributes pid))) + (if process (cons pid process) + (delete-file +mu4e-lock-file) nil)))) + +;;;###autoload +(defun +mu4e-lock-avalible (&optional strict) + "If the `+mu4e-lock-file' is avalible (unset or owned by this emacs) return t. +If STRICT only accept an unset lock file." + (not (when-let* ((lock-info (+mu4e-lock-pid-info)) + (pid (car lock-info))) + (when (or strict (/= (emacs-pid) pid)) t)))) + +;;;###autoload +(defun +mu4e-lock-file-delete-maybe () + "Check `+mu4e-lock-file', and delete it if this process is responsible for it." + (when (+mu4e-lock-avalible) + (delete-file +mu4e-lock-file) + (file-notify-rm-watch +mu4e-lock--request-watcher))) + +;;;###autoload +(defun +mu4e-lock-start (orig-fun &optional callback) + "Check `+mu4e-lock-file', and if another process is responsible for it, abort starting. +Else, write to this process' PID to the lock file" + (unless (+mu4e-lock-avalible) + (shell-command (format "touch %s" +mu4e-lock-request-file)) + (message "Lock file exists, requesting that it be given up") + (sleep-for 0.1) + (delete-file +mu4e-lock-request-file)) + (if (not (+mu4e-lock-avalible)) + (user-error "Unfortunately another Emacs is already doing stuff with Mu4e, and you can only have one at a time") + (f-write-text (number-to-string (emacs-pid)) 'utf-8 +mu4e-lock-file) + (delete-file +mu4e-lock-request-file) + (funcall orig-fun callback) + (setq +mu4e-lock--request-watcher + (file-notify-add-watch +mu4e-lock-request-file + '(change) + #'+mu4e-lock-request)))) + +(defvar +mu4e-lock--file-watcher nil) +(defvar +mu4e-lock--file-just-deleted nil) +(defvar +mu4e-lock--request-watcher nil) + +;;;###autoload +(defun +mu4e-lock-add-watcher () + (setq +mu4e-lock--file-just-deleted nil) + (file-notify-rm-watch +mu4e-lock--file-watcher) + (setq +mu4e-lock--file-watcher + (file-notify-add-watch +mu4e-lock-file + '(change) + #'++mu4e-lock-file-updated))) + +;;;###autoload +(defun +mu4e-lock-request (event) + "Handle another process requesting the Mu4e lock." + (when (equal (nth 1 event) 'created) + (when +mu4e-lock-relaxed + (mu4e~stop) + (file-notify-rm-watch +mu4e-lock--file-watcher) + (message "Someone else wants to use Mu4e, releasing lock") + (delete-file +mu4e-lock-file) + (run-at-time 0.2 nil #'+mu4e-lock-add-watcher)) + (delete-file +mu4e-lock-request-file))) + +;;;###autoload +(defun ++mu4e-lock-file-updated (event) + (if +mu4e-lock--file-just-deleted + (+mu4e-lock-add-watcher) + (when (equal (nth 1 event) 'deleted) + (setq +mu4e-lock--file-just-deleted t) + (when (and +mu4e-lock-greedy (+mu4e-lock-avalible t)) + (message "Noticed Mu4e lock was avalible, grabbed it") + (run-at-time 0.2 nil #'mu4e~start))))) diff --git a/modules/email/mu4e/config.el b/modules/email/mu4e/config.el index 359a210b7..353d2b41f 100644 --- a/modules/email/mu4e/config.el +++ b/modules/email/mu4e/config.el @@ -193,7 +193,17 @@ (advice-add #'mu4e~main-action-str :override #'+mu4e~main-action-str-prettier) (when (featurep! :editor evil) ;; As +mu4e~main-action-str-prettier replaces [k]ey with key q]uit should become quit - (setq evil-collection-mu4e-end-region-misc "quit"))) + (setq evil-collection-mu4e-end-region-misc "quit")) + + ;; process lock control + (when IS-WINDOWS + (setq ;; REVIEW untested + +mu4e-lock-file (expand-file-name "%userprofile%\\AppData\\Local\\Temp\\mu4e_lock") + +mu4e-lock-request-file (expand-file-name "%userprofile%\\AppData\\Local\\Temp\\mu4e_lock_request"))) + + (add-hook 'kill-emacs-hook #'+mu4e-lock-file-delete-maybe) + (advice-add 'mu4e~start :around #'+mu4e-lock-start) + (advice-add 'mu4e-quit :after #'+mu4e-lock-file-delete-maybe)) (use-package! org-msg :after mu4e