├── splitting-windows.gif ├── mu4e-view-save-all-attachments.el └── README.org /splitting-windows.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sje30/emacs/HEAD/splitting-windows.gif -------------------------------------------------------------------------------- /mu4e-view-save-all-attachments.el: -------------------------------------------------------------------------------- 1 | ;;; mu4e-view-save-all-attachments.el -- Save all attachments from view mode. 2 | ;;; Stephen J Eglen 2021 3 | 4 | 5 | ;; I've created this based on the work of Phil Jackson that required 6 | ;; an older version of mu4e. This version requires the GNUS article 7 | ;; code for reading mu4e messages. 8 | ;; https://gist.github.com/philjackson/aecfab1706f05079aec7000e328fd183 9 | 10 | ;; Suggested keybinding 11 | ;; mnemnonic: > is to redirect the files to output everything. 12 | ;; (define-key mu4e-view-mode-map ">" 'mu4e-view-save-all-attachments) 13 | 14 | (defvar bulk-saved-attachments-dir mu4e-attachment-dir) 15 | 16 | 17 | (defun cleanse-subject (sub) 18 | (replace-regexp-in-string 19 | "[^A-Z0-9]+" 20 | "-" 21 | (downcase sub))) 22 | 23 | (defun mu4e-view-save-all-attachments (&optional arg) 24 | "Save all MIME parts from currsent mu4e gnus view buffer." 25 | ;; Copied from mu4e-view-save-attachments 26 | (interactive "P") 27 | (cl-assert (and (eq major-mode 'mu4e-view-mode) 28 | (derived-mode-p 'gnus-article-mode))) 29 | (let* ((msg (mu4e-message-at-point)) 30 | (id (cleanse-subject (mu4e-message-field msg :subject))) 31 | (attachdir (concat bulk-saved-attachments-dir "/" id)) 32 | (parts (mu4e--view-gather-mime-parts)) 33 | (handles '()) 34 | (files '()) 35 | dir) 36 | (mkdir attachdir t) 37 | (dolist (part parts) 38 | (let ((fname (or 39 | (cdr (assoc 'filename (assoc "attachment" (cdr part)))) 40 | (seq-find #'stringp 41 | (mapcar (lambda (item) (cdr (assoc 'name item))) 42 | (seq-filter 'listp (cdr part))))))) 43 | (when fname 44 | (push `(,fname . ,(cdr part)) handles) 45 | (push fname files)))) 46 | (if files 47 | (progn 48 | (setq dir 49 | (if arg (read-directory-name "Save to directory: ") 50 | attachdir)) 51 | (cl-loop for (f . h) in handles 52 | when (member f files) 53 | do (mm-save-part-to-file h 54 | (sje-next-free 55 | (expand-file-name f dir))))) 56 | (mu4e-message "No attached files found")))) 57 | 58 | 59 | 60 | (defun sje-next-free (file) 61 | "Return name of next unique 'free' FILE. 62 | If /tmp/foo.txt and /tmp/foo-1.txt exist, when this is called 63 | with /tmp/foo.txt, return /tmp/foo-2.txt. See 64 | `sje-test-next-free' for a test case. This is not very efficient 65 | if there are a large number of files already in the directory 66 | with the same base name, as it simply starts searching from 1 67 | each time until it finds a gap. An alternative might be to do a 68 | wildcard search for all the filenames, extract the highest number 69 | and then increment it." 70 | ;; base case is easy; does file exist already? 71 | (if (not (file-exists-p file)) 72 | file 73 | ;; othwerwise need to iterate through f-1.pdf 74 | ;; f-2.pdf, f-3.pdf ... until we no longer find a file. 75 | (let ((prefix (file-name-sans-extension file)) 76 | (suffix (file-name-extension file)) 77 | (looking t) 78 | (n 0) 79 | (f) 80 | ) 81 | (while looking 82 | (setq n (1+ n)) 83 | (setq f (concat prefix "-" (number-to-string n) "." suffix)) 84 | (setq looking (file-exists-p f))) 85 | f 86 | ))) 87 | 88 | 89 | (defun sje-test-next-free () 90 | (let (f) 91 | (dotimes (i 100) 92 | (setq f (sje-next-free "/tmp/rabbit.txt")) 93 | (write-region "hello" nil f) 94 | ))) 95 | ;; (sje-test-next-free) 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * Notes about Emacs 2 | 3 | ** dired -- Create a dired buffer of files listed on stdin. 4 | 5 | 6 | Often I find I would like to create a list of files using some unix 7 | command and have a dired buffer containing those files. This short 8 | script does that. It creates a temporary file .my-dired.el which is 9 | not deleted by default for debugging purposes. 10 | 11 | #+begin_src perl :noweb yes :tangle ~/langs/bin/perl/dired :tangle-mode (identity #o755) 12 | #!/usr/bin/perl 13 | # this file generated from <> 14 | use Cwd qw(getcwd); 15 | 16 | $elfile = ".my-dired.el"; 17 | 18 | ## (dired-other-window '("my dired" "~" "txt" "~/txt/add.tex" ".emacs" "foreign.pdf")) 19 | open(OUT, '>', $elfile) or die $!; 20 | 21 | $buffer = "my-dired"; 22 | $dir = getcwd(); 23 | 24 | 25 | ## Can use `dired' or `dired-other-window'. 26 | 27 | print OUT "(dired '(\"$buffer\" \"$dir\"\n"; 28 | 29 | while(<>) { 30 | chomp; 31 | print OUT "\"$_\"\n"; 32 | } 33 | 34 | print OUT "))\n"; 35 | 36 | close(OUT); 37 | 38 | system("emacsclient -n -e '(load-file \"$elfile\")'"); 39 | 40 | ##unlink($elfile); 41 | 42 | 43 | 44 | #+end_src 45 | 46 | 47 | Example: find all the PDFs and open in dired. 48 | 49 | fd -x pdf | dired 50 | 51 | Example: show all files that are currently registered 52 | 53 | git ls-files --exclude-standard --other | dired 54 | 55 | *** references 56 | https://github.com/magit/magit/issues/4054 57 | 58 | 59 | ** Alternative C-x 3 and C-x 2 60 | 61 | The default behaviour for C-x 2 (split-window-below) is to divide a 62 | window into two, showing the same buffer in each window. I would 63 | prefer the two windows to show the most recent two buffers. Alex Branham 64 | had solved this problem before 65 | https://gitlab.com/jabranham/emacs/blob/master/init.el#L2537 66 | 67 | I simply added the extra configuration to switch-to-prev-buffer-skip 68 | so that if you use C-x 2 or C-x 3 n times, then you see the n+1 recent 69 | buffers. Thank you Alex. 70 | 71 | 72 | 73 | #+begin_src emacs-lisp :tangle no 74 | ;; Split the windows sensibly. 75 | ;; https://gitlab.com/jabranham/emacs/blob/master/init.el#L2537 76 | (defun my/split-below-last-buffer (prefix) 77 | "Split the window above/below and display the previous buffer. 78 | If prefix arg is provided, show current buffer twice." 79 | (interactive "p") 80 | (split-window-below) 81 | (other-window 1 nil) 82 | (if (= prefix 1) 83 | (switch-to-next-buffer))) 84 | 85 | (defun my/split-right-last-buffer (prefix) 86 | "Split the window left/right and display the previous buffer 87 | If prefix arg is provided, show current buffer twice." 88 | (interactive "p") 89 | (split-window-right) 90 | (other-window 1 nil) 91 | (if (= prefix 1) (switch-to-next-buffer))) 92 | 93 | (global-set-key (kbd "C-x 2") 'my/split-below-last-buffer) 94 | (global-set-key (kbd "C-x 3") 'my/split-right-last-buffer) 95 | (setq switch-to-prev-buffer-skip 'this) 96 | #+end_src 97 | 98 | Screenshot: 99 | 100 | [[file:splitting-windows.gif]] 101 | 102 | 103 | 104 | ** using pdf-tools via xdg-open 105 | 106 | I use mu4e to read email, which opens pdf attachments using 107 | xdg-open. So, to get mu4e to open pdfs attachments using [[https://github.com/politza/pdf-tools][pdf-tools]], I 108 | needed to configure xdg-open accordingly. This required two 109 | steps, below. I also use the following setting in mu4e: 110 | 111 | #+begin_src emacs-lisp :tangle no 112 | (setq mu4e-view-use-gnus t) 113 | #+end_src 114 | 115 | *** Create a pdf-tools.desktop 116 | 117 | This file lives in =~/.local/share/applications/pdf-tools.desktop= 118 | 119 | 120 | #+begin_src sh :tangle ~/.local/share/applications/pdf-tools.desktop 121 | [Desktop Entry] 122 | Encoding=UTF-8 123 | Version=0.1 124 | Type=Application 125 | NoDisplay=true 126 | Exec=emacsclient %u 127 | Name=pdf-tools 128 | Comment=Use Emacs to open pdf files 129 | #+end_src 130 | 131 | #+RESULTS: 132 | 133 | *** Tell xdg-mine to use pdf-tools.desktop to read pdfs 134 | 135 | #+begin_src sh 136 | xdg-mime default pdf-tools.desktop application/pdf 137 | #+end_src 138 | 139 | This updates the list in ~/.config/mimeapps.list 140 | 141 | You should then find that =xdg-open file.pdf= opens the file in Emacs, 142 | and (at least for me), pdf-attachments from mu4e also open in Emacs. 143 | 144 | 145 | ** mu4e-view-save-all-attachments 146 | 147 | [[mu4e-view-save-all-attachments.el][mu4e-view-save-all-attachments.el]] is a script for mu4e 1.6.x onwards to save all attachments from the 148 | article buffer. 149 | 150 | * noweb 151 | 152 | Taken from https://www.reddit.com/r/orgmode/comments/kmpfpf/adding_tangle_results_to_tangle_file/ 153 | 154 | #+NAME: filename 155 | #+BEGIN_SRC emacs-lisp :tangle no 156 | (buffer-file-name) 157 | #+END_SRC 158 | 159 | #+RESULTS: filename 160 | : /home/stephen/txt/computing/emacs/README.org 161 | 162 | 163 | 164 | 165 | --------------------------------------------------------------------------------