mu4e: emacs 28.1 modernization
We can now use setq-local, length>, string-empty-p, affixations functions and "choice" defcustoms.
This commit is contained in:
@ -238,8 +238,8 @@ When enabled, this attempts to put mu4e's completions at the
|
||||
start of the buffer-local `completion-at-point-functions'. Other
|
||||
completion functions still apply."
|
||||
(when mu4e-compose-complete-addresses
|
||||
(set (make-local-variable 'completion-ignore-case) t)
|
||||
(set (make-local-variable 'completion-cycle-threshold) 7)
|
||||
(setq-local completion-ignore-case t)
|
||||
(setq-local completion-cycle-threshold 7)
|
||||
(add-to-list (make-local-variable 'completion-styles) 'substring)
|
||||
(add-hook 'completion-at-point-functions
|
||||
#'mu4e--compose-complete-contact-field -10 t)))
|
||||
@ -289,13 +289,13 @@ buffers; lets remap its faces so it uses the ones for mu4e."
|
||||
(when (eq major-mode 'mu4e-compose-mode)
|
||||
(mu4e-warn "Not available in mu4e")))
|
||||
|
||||
(defun mu4e--neutralize-undesirables ()
|
||||
"Beware Gnus commands that do not work with mu4e."
|
||||
;; the Field menu contains many items that don't apply.
|
||||
(advice-add 'gnus-delay-article
|
||||
:before #'mu4e--compose-unsupported) ;; # XXX does not work?!
|
||||
(advice-add 'message-goto-newsgroups :before #'mu4e--compose-unsupported)
|
||||
(advice-add 'message-insert-newsgroups :before #'mu4e--compose-unsupported))
|
||||
;; Neutralize Gnus commands that do not work with mu4e. The advice is a no-op
|
||||
;; outside mu4e-compose-mode (see `mu4e--compose-unsupported'), so it is safe
|
||||
;; to install unconditionally at load time.
|
||||
(advice-add 'gnus-delay-article
|
||||
:before #'mu4e--compose-unsupported) ;; # XXX does not work?!
|
||||
(advice-add 'message-goto-newsgroups :before #'mu4e--compose-unsupported)
|
||||
(advice-add 'message-insert-newsgroups :before #'mu4e--compose-unsupported)
|
||||
|
||||
(define-derived-mode mu4e-compose-mode message-mode "mu4e:compose"
|
||||
"Major mode for the mu4e message composition, derived from `message-mode'.
|
||||
@ -303,13 +303,12 @@ buffers; lets remap its faces so it uses the ones for mu4e."
|
||||
(progn
|
||||
(use-local-map mu4e-compose-mode-map)
|
||||
(mu4e-context-minor-mode)
|
||||
(mu4e--neutralize-undesirables)
|
||||
(mu4e--compose-remap-faces)
|
||||
(setq-local nobreak-char-display nil)
|
||||
;; set this to allow mu4e to work when gnus-agent is unplugged in gnus
|
||||
(set (make-local-variable 'message-send-mail-real-function) nil)
|
||||
(setq-local message-send-mail-real-function nil)
|
||||
;; Set to nil to enable `electric-quote-local-mode' to work:
|
||||
(set (make-local-variable 'comment-use-syntax) nil)
|
||||
(setq-local comment-use-syntax nil)
|
||||
(mu4e--compose-setup-completion) ;; maybe offer address completion
|
||||
(if mu4e-compose-format-flowed ;; format-flowed
|
||||
(progn
|
||||
|
||||
@ -280,7 +280,7 @@ case a phrase contains a quote, it will be escaped."
|
||||
"Get the full combination of name and email address from CONTACT."
|
||||
(let* ((email (mu4e-contact-email contact))
|
||||
(name (mu4e-contact-name contact)))
|
||||
(if (and name (> (length name) 0))
|
||||
(if (and name (not (string-empty-p name)))
|
||||
(format "%s <%s>" (mu4e--rfc822-quote-phrase name) email)
|
||||
email)))
|
||||
|
||||
|
||||
@ -1185,7 +1185,7 @@ The following specs are supported:
|
||||
(use-local-map mu4e-headers-mode-map)
|
||||
(make-local-variable 'mu4e~headers-proc)
|
||||
(make-local-variable 'mu4e~highlighted-docid)
|
||||
(set (make-local-variable 'hl-line-face) 'mu4e-header-highlight-face)
|
||||
(setq-local hl-line-face 'mu4e-header-highlight-face)
|
||||
|
||||
;; Eldoc support
|
||||
(when (and (featurep 'eldoc) mu4e-eldoc-support)
|
||||
@ -1198,8 +1198,8 @@ The following specs are supported:
|
||||
#'mu4e-headers-eldoc-function)))
|
||||
|
||||
;; support bookmarks.
|
||||
(set (make-local-variable 'bookmark-make-record-function)
|
||||
'mu4e--make-bookmark-record)
|
||||
(setq-local bookmark-make-record-function
|
||||
#'mu4e--make-bookmark-record)
|
||||
;; maybe update the current headers upon indexing changes
|
||||
(add-hook 'mu4e-index-updated-hook #'mu4e~headers-maybe-auto-update)
|
||||
(setq
|
||||
|
||||
@ -721,7 +721,7 @@ shorter keys in some cases where there are multiple bindings."
|
||||
;; not a perfect heuristic: e.g. '<up>' is longer that 'C-p'
|
||||
(car-safe
|
||||
(seq-sort (lambda (b1 b2)
|
||||
(< (length b1) (length b2)))
|
||||
(length< b1 (length b2)))
|
||||
(seq-map #'key-description
|
||||
(where-is-internal cmd)))))
|
||||
|
||||
|
||||
@ -205,7 +205,7 @@ binding representation, remove that first letter."
|
||||
(let* ((bindstr (or bindstr (mu4e-key-description cmd) alt
|
||||
(mu4e-error "No binding for %s" cmd)))
|
||||
(bindstr
|
||||
(if (and alt (> (length bindstr) 1)) alt bindstr))
|
||||
(if (and alt (length> bindstr 1)) alt bindstr))
|
||||
(title ;; remove first letter afrer [] if it equal last of binding
|
||||
(string-replace
|
||||
(concat "[@]" (substring bindstr -1)) "[@]" title))
|
||||
|
||||
@ -106,7 +106,7 @@ is the target directory (for \"move\")")
|
||||
|
||||
(defun mu4e--mark-initialize ()
|
||||
"Initialize the marks-subsystem."
|
||||
(set (make-local-variable 'mu4e--mark-map) (make-hash-table))
|
||||
(setq-local mu4e--mark-map (make-hash-table))
|
||||
;; ask user when kill buffer / emacs with live marks.
|
||||
;; (subject to mu4e-headers-leave-behavior)
|
||||
(add-hook 'kill-buffer-query-functions
|
||||
|
||||
@ -72,6 +72,17 @@ See `mu4e--uniquify-file-name' for an example."
|
||||
(mm-destroy-parts mu4e--view-gnus-article-mime-handles)
|
||||
(setq mu4e--view-gnus-article-mime-handles nil)))
|
||||
|
||||
;; Temp directories created to hand attachments to external openers; cleaned up
|
||||
;; when the view buffer is killed.
|
||||
(defvar-local mu4e--view-temp-dirs nil)
|
||||
(put 'mu4e--view-temp-dirs 'permanent-local t)
|
||||
|
||||
(defun mu4e--view-kill-temp-dirs ()
|
||||
"Delete temp dirs created for opening MIME-parts externally."
|
||||
(dolist (dir mu4e--view-temp-dirs)
|
||||
(ignore-errors (delete-directory dir)))
|
||||
(setq mu4e--view-temp-dirs nil))
|
||||
|
||||
;;; MIME-parts
|
||||
(defvar-local mu4e--view-mime-parts nil
|
||||
"Cached MIME parts for this message.")
|
||||
@ -229,7 +240,7 @@ COMPLETIONS is the list of completion strings to affixate."
|
||||
'face 'mu4e-system-face))
|
||||
(target (propertize (or (plist-get part :target-dir) "")
|
||||
'face 'mu4e-system-face))
|
||||
(icon (or (and (> (length raw-filename) 0)
|
||||
(icon (or (and (not (string-empty-p raw-filename))
|
||||
(mu4e-file-name-to-icon raw-filename))
|
||||
(mu4e-mime-type-to-icon
|
||||
(plist-get part :mime-type))))
|
||||
@ -430,32 +441,33 @@ Each of the actions is a plist with keys
|
||||
The filename is deduced from the MIME-part's filename, or
|
||||
otherwise random; the result is placed in a temporary directory
|
||||
with a unique name. Returns the full path for the file created.
|
||||
The directory and file are self-destructed."
|
||||
The directory is registered for cleanup when the current view
|
||||
buffer is killed (see `mu4e--view-kill-temp-dirs')."
|
||||
(let* ((tmpdir (make-temp-file "mu4e-temp-" t))
|
||||
(fname (mm-handle-filename handle))
|
||||
(fname (and fname
|
||||
(gnus-map-function mm-file-name-rewrite-functions
|
||||
(file-name-nondirectory fname))))
|
||||
(fname (if fname
|
||||
(concat tmpdir "/" (replace-regexp-in-string "/" "-" fname))
|
||||
(mu4e-join-paths
|
||||
tmpdir (replace-regexp-in-string "/" "-" fname))
|
||||
(let ((temporary-file-directory tmpdir))
|
||||
(make-temp-file "mimepart")))))
|
||||
(mm-save-part-to-file handle fname)
|
||||
(run-at-time "30 sec" nil
|
||||
(lambda () (ignore-errors (delete-directory tmpdir t))))
|
||||
(push tmpdir mu4e--view-temp-dirs)
|
||||
fname))
|
||||
|
||||
(defun mu4e--view-open-file (file &optional force-ask)
|
||||
"Open FILE with default handler, if any.
|
||||
Otherwise, or if FORCE-ASK is set, ask user for the program to
|
||||
open with."
|
||||
Otherwise, or if FORCE-ASK is set, ask user for the shell command
|
||||
to open with."
|
||||
(if (and (not force-ask)
|
||||
(functionp mu4e-view-open-program))
|
||||
(funcall mu4e-view-open-program file)
|
||||
(let ((opener
|
||||
(or (and (not force-ask) mu4e-view-open-program
|
||||
(executable-find mu4e-view-open-program))
|
||||
(read-shell-command "Open MIME-part with: "))))
|
||||
(read-shell-command "Open MIME-part with shell command: "))))
|
||||
(call-process opener nil 0 nil file))))
|
||||
|
||||
(defun mu4e-view-mime-part-action (&optional n)
|
||||
@ -515,17 +527,16 @@ the third MIME-part."
|
||||
(cond
|
||||
((eq receives 'index)
|
||||
(shell-command
|
||||
(concat handler " " (shell-quote-argument id))))
|
||||
(concat handler " " id)))
|
||||
((eq receives 'pipe)
|
||||
(progn
|
||||
(mm-pipe-part handle handler)))
|
||||
((eq receives 'temp)
|
||||
(shell-command
|
||||
(shell-command
|
||||
(concat
|
||||
handler " "
|
||||
(shell-quote-argument
|
||||
(mu4e--view-mime-part-to-temp-file handle))))))
|
||||
(concat
|
||||
handler " "
|
||||
(shell-quote-argument
|
||||
(mu4e--view-mime-part-to-temp-file handle)))))
|
||||
(t (mu4e-error "Invalid action %S" action))))))))
|
||||
ids)))
|
||||
|
||||
|
||||
@ -281,7 +281,7 @@ limit the stack size."
|
||||
(unless (and stack (string= (car stack) query))
|
||||
(push query stack)
|
||||
;; limit the stack to `mu4e--search-query-stack-size' elements
|
||||
(when (> (length stack) mu4e--search-query-stack-size)
|
||||
(when (length> stack mu4e--search-query-stack-size)
|
||||
(setq stack (cl-subseq stack 0 mu4e--search-query-stack-size)))
|
||||
;; remove all duplicates of the new element
|
||||
(seq-remove (lambda (elm) (string= elm (car stack))) (cdr stack))
|
||||
@ -607,24 +607,30 @@ query before submitting it."
|
||||
(longest-query
|
||||
(seq-max (seq-map (lambda (c) (length (plist-get (cdr c) :query)))
|
||||
candidates)))
|
||||
|
||||
(annotation-func
|
||||
(lambda (candidate)
|
||||
(let* ((item (cdr-safe (assoc candidate candidates)))
|
||||
(name (propertize (or (plist-get item :name) "")
|
||||
'face 'mu4e-header-key-face))
|
||||
(query (propertize (or (plist-get item :query) "")
|
||||
'face 'mu4e-header-value-face)))
|
||||
(concat
|
||||
" "
|
||||
(make-string (- longest-name (length name)) ?\s)
|
||||
query
|
||||
(make-string (- longest-query (length query)) ?\s)
|
||||
" "
|
||||
(mu4e--query-item-display-counts item)))))
|
||||
(completion-extra-properties
|
||||
`(:annotation-function ,annotation-func))
|
||||
(chosen (completing-read "Query: " candidates))
|
||||
(affixation-func
|
||||
(lambda (completions)
|
||||
(mapcar
|
||||
(lambda (candidate)
|
||||
(let* ((item (cdr-safe (assoc candidate candidates)))
|
||||
(query (propertize (or (plist-get item :query) "")
|
||||
'face 'mu4e-header-value-face))
|
||||
(suffix
|
||||
(concat
|
||||
" "
|
||||
(make-string (- longest-name (length candidate)) ?\s)
|
||||
query
|
||||
(make-string (- longest-query (length query)) ?\s)
|
||||
" "
|
||||
(mu4e--query-item-display-counts item))))
|
||||
(list candidate "" suffix)))
|
||||
completions)))
|
||||
(table (lambda (string pred action)
|
||||
(if (eq action 'metadata)
|
||||
`(metadata
|
||||
(category . mu4e-query)
|
||||
(affixation-function . ,affixation-func))
|
||||
(complete-with-action action candidates string pred))))
|
||||
(chosen (completing-read "Query: " table))
|
||||
(query (or (plist-get (cdr-safe (assoc chosen candidates)) :query)
|
||||
(mu4e-warn "No query for %s" chosen))))
|
||||
(mu4e-search-bookmark query edit)))
|
||||
|
||||
@ -651,10 +651,11 @@ activates URLs (in plain-text mode only)."
|
||||
(unless (mu4e--view-html-displayed-p)
|
||||
(mu4e--view-activate-urls))
|
||||
(kill-local-variable 'bookmark-make-record-function)
|
||||
(setq mu4e--gnus-article-mime-handles gnus-article-mime-handles
|
||||
(setq mu4e--view-gnus-article-mime-handles gnus-article-mime-handles
|
||||
gnus-article-decoded-p gnus-article-decode-hook)
|
||||
(set-buffer-modified-p nil)
|
||||
(add-hook 'kill-buffer-hook #'mu4e--view-kill-mime-handles))
|
||||
(add-hook 'kill-buffer-hook #'mu4e--view-kill-mime-handles)
|
||||
(add-hook 'kill-buffer-hook #'mu4e--view-kill-temp-dirs))
|
||||
(epg-error
|
||||
(mu4e-message "EPG error: %s; fall back to raw view"
|
||||
(error-message-string err))))))
|
||||
@ -789,7 +790,7 @@ filename."
|
||||
;; (e.g. :user-agent): derive from the keyword name.
|
||||
(capitalize (substring (symbol-name field) 1))))
|
||||
(help (plist-get info :help)))
|
||||
(if (and val (> (length val) 0))
|
||||
(if (and val (not (string-empty-p val)))
|
||||
(insert (propertize (concat key ":") 'help-echo help)
|
||||
" " val "\n"))))
|
||||
|
||||
@ -803,7 +804,7 @@ filename."
|
||||
field info)))
|
||||
(val (funcall func msg))
|
||||
(help (plist-get info :help)))
|
||||
(when (and val (> (length val) 0))
|
||||
(when (and val (not (string-empty-p val)))
|
||||
(insert (propertize (concat key ":") 'help-echo help) " " val "\n"))))
|
||||
|
||||
(define-advice gnus-icalendar-event-from-handle
|
||||
|
||||
@ -103,7 +103,11 @@ A symbol:
|
||||
|
||||
For backward compatibility with `mu4e-compose-in-new-frame', t is
|
||||
treated as =\\'frame."
|
||||
:type 'symbol
|
||||
:type '(choice (const :tag "New buffer" nil)
|
||||
(const :tag "New window" window)
|
||||
(const :tag "New frame" frame)
|
||||
(const :tag "New frame (compat)" t)
|
||||
(const :tag "Use display-buffer" display-buffer))
|
||||
:group 'mu4e-compose)
|
||||
|
||||
(declare-function mu4e-view-mode "mu4e-view")
|
||||
@ -252,7 +256,7 @@ being created if CREATE is non-nil."
|
||||
;; Required. The call chain of `mu4e-view-mode' ends up
|
||||
;; calling `kill-all-local-variables', which destroys the
|
||||
;; local binding.
|
||||
(set (make-local-variable 'mu4e-linked-headers-buffer) headers-buffer))
|
||||
(setq-local mu4e-linked-headers-buffer headers-buffer))
|
||||
buffer)))
|
||||
|
||||
;; backward compat: `display-buffer-full-frame' only appears in emacs 29.
|
||||
|
||||
Reference in New Issue
Block a user