From 47be8e292eba96fa8ebc05157b8922f962df29b9 Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 11 Sep 2021 21:05:43 +0800 Subject: [PATCH 01/10] feat(mu4e): reintroduce A and p view keybindings When viewing a message, in mu4e < 1.6 'A' gives actions that can be performed on the attachments, and 'p' / 'P' save attachments. The functions are removed in 1.6, and their nearest replacements are not bound. I think it makes sense to actually bind them. --- modules/email/mu4e/config.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/email/mu4e/config.el b/modules/email/mu4e/config.el index 2bddb3935..c38d45e11 100644 --- a/modules/email/mu4e/config.el +++ b/modules/email/mu4e/config.el @@ -181,6 +181,12 @@ (map! :map mu4e-headers-mode-map :vne "l" #'+mu4e/capture-msg-to-agenda) + ;; Functionality otherwise obscured in mu4e 1.6 + (when (version<= "1.6" mu4e-mu-version) + (map! :map mu4e-view-mode-map + :ne "A" #'mu4e-view-mime-part-action + :ne "p" #'mu4e-view-save-attachments)) + (map! :localleader :map mu4e-compose-mode-map :desc "send and exit" "s" #'message-send-and-exit From 251705149b4c1e9ebd400f8ede0e500d10df043f Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 11 Sep 2021 22:16:02 +0800 Subject: [PATCH 02/10] feat(mu4e): reimplement attachment opening command This can be done via 'a', but it's a nice convenience to have, particularly as it filters out non-attachment MIME parts. Closes #5027. --- modules/email/mu4e/config.el | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/modules/email/mu4e/config.el b/modules/email/mu4e/config.el index c38d45e11..7b75112d7 100644 --- a/modules/email/mu4e/config.el +++ b/modules/email/mu4e/config.el @@ -183,9 +183,29 @@ ;; Functionality otherwise obscured in mu4e 1.6 (when (version<= "1.6" mu4e-mu-version) + (defun +mu4e-select-attachment () + "Use completing-read to select a single attachment. +Acts like a singular `mu4e-view-save-attachments', without the saving." + (let ((parts (mu4e~view-gather-mime-parts)) files) + (dolist (part parts) + (let ((fname (cdr (assoc 'filename (assoc "attachment" (cdr part)))))) + (when fname + (push (cons fname part) files)))) + (if files + (cdr (assoc (completing-read "Select attachment: " (mapcar #'car files)) + files)) + (user-error (mu4e-format "No attached files found"))))) + + (defun +mu4e-open-attachment () + "Select an attachment, and open it." + (interactive) + (mu4e~view-open-file + (mu4e~view-mime-part-to-temp-file (cdr (+mu4e-select-attachment))))) + (map! :map mu4e-view-mode-map :ne "A" #'mu4e-view-mime-part-action - :ne "p" #'mu4e-view-save-attachments)) + :ne "p" #'mu4e-view-save-attachments + :ne "o" #'+mu4e-open-attachment)) (map! :localleader :map mu4e-compose-mode-map From c4aba242a30c30812f327aa3f4bf86534fb3f912 Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 11 Sep 2021 22:07:39 +0800 Subject: [PATCH 03/10] feat(mu4e): improve part selection experience It's not nice having to think of the index of the MIME part you want to look at, it's much nicer to get a completing read with information about those parts. --- modules/email/mu4e/config.el | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/modules/email/mu4e/config.el b/modules/email/mu4e/config.el index 7b75112d7..ae4edb589 100644 --- a/modules/email/mu4e/config.el +++ b/modules/email/mu4e/config.el @@ -202,8 +202,25 @@ Acts like a singular `mu4e-view-save-attachments', without the saving." (mu4e~view-open-file (mu4e~view-mime-part-to-temp-file (cdr (+mu4e-select-attachment))))) + (defun +mu4e-select-part () + (let ((parts (mu4e~view-gather-mime-parts)) labeledparts) + (dolist (part parts) + (push (cons (concat (propertize (format "%-2s " (car part)) 'face '(bold font-lock-type-face)) + (or (cdr (assoc 'filename (assoc "attachment" (cdr part)))) + (propertize "unnamed" 'face '(italic font-lock-doc-face))) + (propertize (format " [%s]" (caaddr part)) 'face 'font-lock-constant-face)) + part) + labeledparts)) + (cdr (assoc (completing-read "Select part: " (mapcar #'car labeledparts)) + labeledparts)))) + + (defun +mu4e-view-select-mime-part-action () + "Select a MIME part, and perform an action on it." + (interactive) + (mu4e-view-mime-part-action (car (+mu4e-select-part)))) + (map! :map mu4e-view-mode-map - :ne "A" #'mu4e-view-mime-part-action + :ne "A" #'+mu4e-view-select-mime-part-action :ne "p" #'mu4e-view-save-attachments :ne "o" #'+mu4e-open-attachment)) From 6d1e86affcd6992fe9481b0137643e764834124d Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 11 Sep 2021 22:18:41 +0800 Subject: [PATCH 04/10] tweak(mu4e): be consistent with mu4e naming style --- modules/email/mu4e/config.el | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/email/mu4e/config.el b/modules/email/mu4e/config.el index ae4edb589..45909ac0b 100644 --- a/modules/email/mu4e/config.el +++ b/modules/email/mu4e/config.el @@ -183,7 +183,7 @@ ;; Functionality otherwise obscured in mu4e 1.6 (when (version<= "1.6" mu4e-mu-version) - (defun +mu4e-select-attachment () + (defun +mu4e-view-select-attachment () "Use completing-read to select a single attachment. Acts like a singular `mu4e-view-save-attachments', without the saving." (let ((parts (mu4e~view-gather-mime-parts)) files) @@ -196,13 +196,13 @@ Acts like a singular `mu4e-view-save-attachments', without the saving." files)) (user-error (mu4e-format "No attached files found"))))) - (defun +mu4e-open-attachment () + (defun +mu4e-view-open-attachment () "Select an attachment, and open it." (interactive) (mu4e~view-open-file - (mu4e~view-mime-part-to-temp-file (cdr (+mu4e-select-attachment))))) + (mu4e~view-mime-part-to-temp-file (cdr (+mu4e-view-select-attachment))))) - (defun +mu4e-select-part () + (defun +mu4e-view-select-part () (let ((parts (mu4e~view-gather-mime-parts)) labeledparts) (dolist (part parts) (push (cons (concat (propertize (format "%-2s " (car part)) 'face '(bold font-lock-type-face)) @@ -217,12 +217,12 @@ Acts like a singular `mu4e-view-save-attachments', without the saving." (defun +mu4e-view-select-mime-part-action () "Select a MIME part, and perform an action on it." (interactive) - (mu4e-view-mime-part-action (car (+mu4e-select-part)))) + (mu4e-view-mime-part-action (car (+mu4e-view-select-part)))) (map! :map mu4e-view-mode-map :ne "A" #'+mu4e-view-select-mime-part-action :ne "p" #'mu4e-view-save-attachments - :ne "o" #'+mu4e-open-attachment)) + :ne "o" #'+mu4e-view-open-attachment)) (map! :localleader :map mu4e-compose-mode-map From ea53ab9ef190e9a3c15b4bbb4e398238384da6d0 Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 11 Sep 2021 22:20:34 +0800 Subject: [PATCH 05/10] tweak(mu4e): end default attachment-dir with "/" Having "/" at the end allows for a single backspace to remove the directory, instead of just the last character - making it easier to select a different location in a completing read. --- modules/email/mu4e/config.el | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/email/mu4e/config.el b/modules/email/mu4e/config.el index 45909ac0b..20747d164 100644 --- a/modules/email/mu4e/config.el +++ b/modules/email/mu4e/config.el @@ -52,12 +52,14 @@ ((featurep! :completion vertico) #'completing-read) (t #'ido-completing-read)) mu4e-attachment-dir - (if (executable-find "xdg-user-dir") - ;; remove trailing newline - (substring (shell-command-to-string "xdg-user-dir DOWNLOAD") 0 -1) - (expand-file-name (or (getenv "XDG_DOWNLOAD_DIR") - "Downloads") - "~")) + (concat + (if (executable-find "xdg-user-dir") + ;; remove trailing newline + (substring (shell-command-to-string "xdg-user-dir DOWNLOAD") 0 -1) + (expand-file-name (or (getenv "XDG_DOWNLOAD_DIR") + "Downloads") + "~")) + "/") ;; no need to ask mu4e-confirm-quit nil mu4e-headers-thread-single-orphan-prefix '("─>" . "─▶") From b05d8e80827536cbb7dc47d17b2e518c4d3fe86c Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 11 Sep 2021 23:08:59 +0800 Subject: [PATCH 06/10] feat(mu4e): use file icons in part/attachment pick Along with some other improvements and refactoring to the part picker for a generally nicer experience, improved readability, and more flexibility. --- modules/email/mu4e/config.el | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/modules/email/mu4e/config.el b/modules/email/mu4e/config.el index 20747d164..f11cd4632 100644 --- a/modules/email/mu4e/config.el +++ b/modules/email/mu4e/config.el @@ -192,7 +192,12 @@ Acts like a singular `mu4e-view-save-attachments', without the saving." (dolist (part parts) (let ((fname (cdr (assoc 'filename (assoc "attachment" (cdr part)))))) (when fname - (push (cons fname part) files)))) + (push (cons (if (featurep 'all-the-icons) + (concat (all-the-icons-icon-for-file fname) + " " fname) + fname) + part) + files)))) (if files (cdr (assoc (completing-read "Select attachment: " (mapcar #'car files)) files)) @@ -205,13 +210,28 @@ Acts like a singular `mu4e-view-save-attachments', without the saving." (mu4e~view-mime-part-to-temp-file (cdr (+mu4e-view-select-attachment))))) (defun +mu4e-view-select-part () - (let ((parts (mu4e~view-gather-mime-parts)) labeledparts) + (let ((parts (mu4e~view-gather-mime-parts)) partinfo labeledparts maxfnamelen fnamefmt) (dolist (part parts) - (push (cons (concat (propertize (format "%-2s " (car part)) 'face '(bold font-lock-type-face)) - (or (cdr (assoc 'filename (assoc "attachment" (cdr part)))) - (propertize "unnamed" 'face '(italic font-lock-doc-face))) - (propertize (format " [%s]" (caaddr part)) 'face 'font-lock-constant-face)) - part) + (push (list :index (car part) + :mimetype (if (string= "text/plain" (caaddr part)) + (format "%s (%s)" + (caaddr part) + (alist-get 'charset (cdaddr part))) + (caaddr part)) + :type (car (nth 5 part)) + :filename (cdr (assoc 'filename (assoc "attachment" (cdr part)))) + :part part) + partinfo)) + (setq maxfnamelen (apply #'max 7 (mapcar (lambda (i) (length (plist-get i :filename))) partinfo)) + fnamefmt (format " %%-%ds " maxfnamelen)) + (dolist (pinfo partinfo) + (push (cons (concat (propertize (format "%-2s " (plist-get pinfo :index)) 'face '(bold font-lock-type-face)) + (when (featurep 'all-the-icons) + (all-the-icons-icon-for-file (or (plist-get pinfo :filename) ""))) + (format fnamefmt (or (plist-get pinfo :filename) + (propertize (plist-get pinfo :type) 'face '(italic font-lock-doc-face)))) + (propertize (plist-get pinfo :mimetype) 'face 'font-lock-constant-face)) + (plist-get pinfo :part)) labeledparts)) (cdr (assoc (completing-read "Select part: " (mapcar #'car labeledparts)) labeledparts)))) From b489ae6452fae9ab31d86a73c07db094957d77a0 Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 11 Sep 2021 23:19:30 +0800 Subject: [PATCH 07/10] feat(mu4e): show size in part/attachment picker --- modules/email/mu4e/config.el | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/modules/email/mu4e/config.el b/modules/email/mu4e/config.el index f11cd4632..ce6dbafac 100644 --- a/modules/email/mu4e/config.el +++ b/modules/email/mu4e/config.el @@ -192,10 +192,10 @@ Acts like a singular `mu4e-view-save-attachments', without the saving." (dolist (part parts) (let ((fname (cdr (assoc 'filename (assoc "attachment" (cdr part)))))) (when fname - (push (cons (if (featurep 'all-the-icons) - (concat (all-the-icons-icon-for-file fname) - " " fname) - fname) + (push (cons (concat (format "%-2s " (car part)) + (when (featurep 'all-the-icons) (all-the-icons-icon-for-file fname)) + (format " %s " fname) + (format "(%s)" (file-size-human-readable (with-current-buffer (cadr part) (buffer-size))))) part) files)))) (if files @@ -210,7 +210,8 @@ Acts like a singular `mu4e-view-save-attachments', without the saving." (mu4e~view-mime-part-to-temp-file (cdr (+mu4e-view-select-attachment))))) (defun +mu4e-view-select-part () - (let ((parts (mu4e~view-gather-mime-parts)) partinfo labeledparts maxfnamelen fnamefmt) + (let ((parts (mu4e~view-gather-mime-parts)) partinfo labeledparts + maxfnamelen fnamefmt maxsizelen sizefmt) (dolist (part parts) (push (list :index (car part) :mimetype (if (string= "text/plain" (caaddr part)) @@ -220,16 +221,20 @@ Acts like a singular `mu4e-view-save-attachments', without the saving." (caaddr part)) :type (car (nth 5 part)) :filename (cdr (assoc 'filename (assoc "attachment" (cdr part)))) + :size (file-size-human-readable (with-current-buffer (cadr part) (buffer-size))) :part part) partinfo)) (setq maxfnamelen (apply #'max 7 (mapcar (lambda (i) (length (plist-get i :filename))) partinfo)) - fnamefmt (format " %%-%ds " maxfnamelen)) + fnamefmt (format " %%-%ds " maxfnamelen) + maxsizelen (apply #'max (mapcar (lambda (i) (length (plist-get i :size))) partinfo)) + sizefmt (format "%%-%ds " maxsizelen)) (dolist (pinfo partinfo) (push (cons (concat (propertize (format "%-2s " (plist-get pinfo :index)) 'face '(bold font-lock-type-face)) (when (featurep 'all-the-icons) (all-the-icons-icon-for-file (or (plist-get pinfo :filename) ""))) (format fnamefmt (or (plist-get pinfo :filename) (propertize (plist-get pinfo :type) 'face '(italic font-lock-doc-face)))) + (format sizefmt (propertize (plist-get pinfo :size) 'face 'font-lock-builtin-face)) (propertize (plist-get pinfo :mimetype) 'face 'font-lock-constant-face)) (plist-get pinfo :part)) labeledparts)) From 4fee7cf9538750cb3e6d7b994a07f0770b10ac36 Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 11 Sep 2021 23:27:52 +0800 Subject: [PATCH 08/10] refactor(mu4e): extract part pickers duplication Both the attachment and part selection functions generate string representations of the parts. No need to do the same thing twice. --- modules/email/mu4e/config.el | 96 ++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/modules/email/mu4e/config.el b/modules/email/mu4e/config.el index ce6dbafac..99e7b193c 100644 --- a/modules/email/mu4e/config.el +++ b/modules/email/mu4e/config.el @@ -188,20 +188,14 @@ (defun +mu4e-view-select-attachment () "Use completing-read to select a single attachment. Acts like a singular `mu4e-view-save-attachments', without the saving." - (let ((parts (mu4e~view-gather-mime-parts)) files) - (dolist (part parts) - (let ((fname (cdr (assoc 'filename (assoc "attachment" (cdr part)))))) - (when fname - (push (cons (concat (format "%-2s " (car part)) - (when (featurep 'all-the-icons) (all-the-icons-icon-for-file fname)) - (format " %s " fname) - (format "(%s)" (file-size-human-readable (with-current-buffer (cadr part) (buffer-size))))) - part) - files)))) - (if files - (cdr (assoc (completing-read "Select attachment: " (mapcar #'car files)) - files)) - (user-error (mu4e-format "No attached files found"))))) + (if-let ((parts (delq nil (mapcar + (lambda (part) + (when (assoc "attachment" (cdr part)) + part)) + (mu4e~view-gather-mime-parts)))) + (files (+mu4e-part-selectors parts))) + (cdr (assoc (completing-read "Select attachment: " (mapcar #'car files)) files)) + (user-error (mu4e-format "No attached files found")))) (defun +mu4e-view-open-attachment () "Select an attachment, and open it." @@ -209,47 +203,53 @@ Acts like a singular `mu4e-view-save-attachments', without the saving." (mu4e~view-open-file (mu4e~view-mime-part-to-temp-file (cdr (+mu4e-view-select-attachment))))) - (defun +mu4e-view-select-part () - (let ((parts (mu4e~view-gather-mime-parts)) partinfo labeledparts - maxfnamelen fnamefmt maxsizelen sizefmt) - (dolist (part parts) - (push (list :index (car part) - :mimetype (if (string= "text/plain" (caaddr part)) - (format "%s (%s)" - (caaddr part) - (alist-get 'charset (cdaddr part))) - (caaddr part)) - :type (car (nth 5 part)) - :filename (cdr (assoc 'filename (assoc "attachment" (cdr part)))) - :size (file-size-human-readable (with-current-buffer (cadr part) (buffer-size))) - :part part) - partinfo)) - (setq maxfnamelen (apply #'max 7 (mapcar (lambda (i) (length (plist-get i :filename))) partinfo)) - fnamefmt (format " %%-%ds " maxfnamelen) - maxsizelen (apply #'max (mapcar (lambda (i) (length (plist-get i :size))) partinfo)) - sizefmt (format "%%-%ds " maxsizelen)) - (dolist (pinfo partinfo) - (push (cons (concat (propertize (format "%-2s " (plist-get pinfo :index)) 'face '(bold font-lock-type-face)) - (when (featurep 'all-the-icons) - (all-the-icons-icon-for-file (or (plist-get pinfo :filename) ""))) - (format fnamefmt (or (plist-get pinfo :filename) - (propertize (plist-get pinfo :type) 'face '(italic font-lock-doc-face)))) - (format sizefmt (propertize (plist-get pinfo :size) 'face 'font-lock-builtin-face)) - (propertize (plist-get pinfo :mimetype) 'face 'font-lock-constant-face)) - (plist-get pinfo :part)) - labeledparts)) - (cdr (assoc (completing-read "Select part: " (mapcar #'car labeledparts)) - labeledparts)))) - (defun +mu4e-view-select-mime-part-action () "Select a MIME part, and perform an action on it." (interactive) - (mu4e-view-mime-part-action (car (+mu4e-view-select-part)))) + (let ((labeledparts (+mu4e-part-selectors (mu4e~view-gather-mime-parts)))) + (if labeledparts + (mu4e-view-mime-part-action + (cadr (assoc (completing-read "Select part: " (mapcar #'car labeledparts)) + labeledparts))) + (user-error (mu4e-format "No parts found"))))) (map! :map mu4e-view-mode-map :ne "A" #'+mu4e-view-select-mime-part-action :ne "p" #'mu4e-view-save-attachments - :ne "o" #'+mu4e-view-open-attachment)) + :ne "o" #'+mu4e-view-open-attachment) + + (defun +mu4e-part-selectors (parts) + "Generate selection strings for PARTS." + (if parts + (let (partinfo labeledparts maxfnamelen fnamefmt maxsizelen sizefmt) + (dolist (part parts) + (push (list :index (car part) + :mimetype (if (and (string= "text/plain" (caaddr part)) + (alist-get 'charset (cdaddr part))) + (format "%s (%s)" + (caaddr part) + (alist-get 'charset (cdaddr part))) + (caaddr part)) + :type (car (nth 5 part)) + :filename (cdr (assoc 'filename (assoc "attachment" (cdr part)))) + :size (file-size-human-readable (with-current-buffer (cadr part) (buffer-size))) + :part part) + partinfo)) + (setq maxfnamelen (apply #'max 7 (mapcar (lambda (i) (length (plist-get i :filename))) partinfo)) + fnamefmt (format " %%-%ds " maxfnamelen) + maxsizelen (apply #'max (mapcar (lambda (i) (length (plist-get i :size))) partinfo)) + sizefmt (format "%%-%ds " maxsizelen)) + (dolist (pinfo partinfo) + (push (cons (concat (propertize (format "%-2s " (plist-get pinfo :index)) 'face '(bold font-lock-type-face)) + (when (featurep 'all-the-icons) + (all-the-icons-icon-for-file (or (plist-get pinfo :filename) ""))) + (format fnamefmt (or (plist-get pinfo :filename) + (propertize (plist-get pinfo :type) 'face '(italic font-lock-doc-face)))) + (format sizefmt (propertize (plist-get pinfo :size) 'face 'font-lock-builtin-face)) + (propertize (plist-get pinfo :mimetype) 'face 'font-lock-constant-face)) + (plist-get pinfo :part)) + labeledparts)) + labeledparts)))) (map! :localleader :map mu4e-compose-mode-map From 7ab825157f2b60e9b2e846d57a5af9a896bb5adf Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 11 Sep 2021 23:44:37 +0800 Subject: [PATCH 09/10] feat(mu4e): make the unicode bullet customizable By popular demand. Close #5452. --- modules/email/mu4e/autoload/advice.el | 6 +++--- modules/email/mu4e/config.el | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/email/mu4e/autoload/advice.el b/modules/email/mu4e/autoload/advice.el index b38bffc59..28a581a8c 100644 --- a/modules/email/mu4e/autoload/advice.el +++ b/modules/email/mu4e/autoload/advice.el @@ -13,7 +13,7 @@ clicked." (lambda(m) (format "%s" (propertize (match-string 1 m) 'face '(mode-line-emphasis bold)))) - (replace-regexp-in-string "\t\\*" "\t⚫" str))) + (replace-regexp-in-string "\t\\*" (format "\t%s" +mu4e-main-bullet) str))) (map (make-sparse-keymap)) (func (if (functionp func-or-shortcut) func-or-shortcut @@ -29,8 +29,8 @@ clicked." ;;;###autoload (defun +mu4e~main-keyval-str-prettier-a (str) - "Replace '*' with '⚫' in STR." - (replace-regexp-in-string "\t\\*" "\t⚫" str)) + "Replace '*' with `+mu4e-main-bullet' in STR." + (replace-regexp-in-string "\t\\*" (format "\t%s" +mu4e-main-bullet) str)) ;; Org msg LaTeX image scaling diff --git a/modules/email/mu4e/config.el b/modules/email/mu4e/config.el index 99e7b193c..850fb8115 100644 --- a/modules/email/mu4e/config.el +++ b/modules/email/mu4e/config.el @@ -279,6 +279,11 @@ This should already be the case yet it does not always seem to be." :before #'mu4e-compose-resend (read-only-mode -1)) + (defvar +mu4e-main-bullet "⚫" + "Prefix to use instead of \" *\" in the mu4e main view. +This is enacted by `+mu4e~main-action-str-prettier-a' and +`+mu4e~main-keyval-str-prettier-a'.") + (advice-add #'mu4e~key-val :filter-return #'+mu4e~main-keyval-str-prettier-a) (advice-add #'mu4e~main-action-str :override #'+mu4e~main-action-str-prettier-a) (when (featurep! :editor evil) From 083c81e44b7e97661c17100bebfbc66f3207e38e Mon Sep 17 00:00:00 2001 From: TEC Date: Wed, 15 Sep 2021 02:41:02 +0800 Subject: [PATCH 10/10] refactor(mu4e): use doom-call-process to check XDG This is a bit safer than shell-command-to-string, and we also now check that the command exited successfully, and fall back if not. --- modules/email/mu4e/config.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/email/mu4e/config.el b/modules/email/mu4e/config.el index 850fb8115..b4818f86d 100644 --- a/modules/email/mu4e/config.el +++ b/modules/email/mu4e/config.el @@ -53,13 +53,14 @@ (t #'ido-completing-read)) mu4e-attachment-dir (concat - (if (executable-find "xdg-user-dir") - ;; remove trailing newline - (substring (shell-command-to-string "xdg-user-dir DOWNLOAD") 0 -1) + (if-let ((xdg-download-query (and (executable-find "xdg-user-dir") + (doom-call-process "xdg-user-dir" "DOWNLOAD"))) + (xdg-download-dir (and (= 0 (car xdg-download-query)) (cdr xdg-download-query)))) + xdg-download-dir (expand-file-name (or (getenv "XDG_DOWNLOAD_DIR") "Downloads") "~")) - "/") + "/") ; a trailing / makes it easier to change directory in `read-file-name' ;; no need to ask mu4e-confirm-quit nil mu4e-headers-thread-single-orphan-prefix '("─>" . "─▶")