summaryrefslogtreecommitdiff
path: root/.config/emacs/config.org
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2023-08-15 21:35:01 +0200
committerThomas Voss <mail@thomasvoss.com> 2023-08-15 21:35:01 +0200
commitc22aec07904e2a089b70d52d801a8887d0134bfe (patch)
tree50b0dd2003fdb0db90d488e8e35e9eb286e6d06e /.config/emacs/config.org
parentd521cc0183a83606e387ccbd2b300128632d2a99 (diff)
emacs: Auto-create directories with ‘find-file’
Diffstat (limited to '.config/emacs/config.org')
-rw-r--r--.config/emacs/config.org67
1 files changed, 67 insertions, 0 deletions
diff --git a/.config/emacs/config.org b/.config/emacs/config.org
index 2af442f..32a0b17 100644
--- a/.config/emacs/config.org
+++ b/.config/emacs/config.org
@@ -1102,6 +1102,73 @@ mixed on when I do and -don’t want it. I always want it in ~org-mode~ though.
#+END_SRC
+** Auto-Directories
+
+When creating new files, the parent directories often don’t exist and I need to
+make them manually with =M-x make-directory RET RET=. I would prefer that these
+directories just get created automatically.
+
+#+BEGIN_SRC elisp
+
+ (defun mango--auto-create-directories
+ (original-function filename &rest args)
+ "Automatically create and delete parent directories of files. This is an
+ ‘:override’ advice for ‘find-file’ and friends. It automatically creates the
+ parent directory (or directories) of the file being visited, if necessary. It
+ also sets a buffer-local variable so that the user will be prompted to delete
+ the newly created directories if they kill the buffer without saving it."
+ (let (dirs-to-delete)
+ (unless (file-exists-p filename)
+ (let* ((dir-to-create (file-name-directory filename))
+ (current-dir dir-to-create))
+ ;; We want to go up each directory component and add them to
+ ;; ‘dirs-to-delete’ individually.
+ (while (not (file-exists-p current-dir))
+ (push current-dir dirs-to-delete)
+ (setq current-dir (file-name-directory
+ (directory-file-name current-dir))))
+
+ (unless (file-exists-p dir-to-create)
+ (make-directory dir-to-create t))))
+
+ ;; Use ‘prog1’ so that we maintain the original return value
+ (prog1 (apply original-function filename args)
+ (when dirs-to-delete
+ (setq-local mango--dirs-to-delete (reverse dirs-to-delete))
+
+ ;; When we kill the buffer we want to ask if we should delete parent
+ ;; directories *unless* the buffer was saved, in which case we don’t
+ ;; want to do anything.
+ (add-hook 'kill-buffer-hook #'mango--delete-directories-if-appropriate
+ t t)
+ (add-hook 'after-save-hook #'mango--remove-auto-directory-hooks t t)))))
+
+ (mm-for-each #'(find-file
+ find-alternate-file
+ write-file
+ project-find-file)
+ (advice-add x :around #'mango--auto-create-directories))
+
+ (defun mango--delete-directories-if-appropriate ()
+ "Delete parent directories if appropriate. This is a function for
+ ‘kill-buffer-hook’. If ‘mango--auto-create-directories’ created the directory
+ containing the file for the current buffer automatically, then offer to delete
+ it. Otherwise, do nothing. Also clean up related hooks."
+ (when (not (file-exists-p buffer-file-name))
+ (cl-dolist (dir-to-delete mango--dirs-to-delete)
+ (when (and (stringp dir-to-delete)
+ (file-exists-p dir-to-delete))
+ (when (y-or-n-p (format "Also delete directory ‘%s’?"
+ (directory-file-name dir-to-delete)))
+ (delete-directory dir-to-delete))))))
+
+ (defun mango--remove-auto-directory-hooks ()
+ "Clean up directory-deletion hooks, if necessary."
+ (remove-hook 'kill-buffer-hook #'mango--delete-directories-if-appropriate t)
+ (remove-hook 'after-save-hook #'mango--remove-auto-directory-hooks t))
+
+#+END_SRC
+
** Email
#+BEGIN_SRC elisp