| ;; Adapted from https://emacs.stackexchange.com/questions/8045/org-refile-to-a-known-fixed-location | |
| (defun my/refile (file headline &optional arg) | |
| "Refile to a specific location. | |
| With a 'C-u' ARG argument, we jump to that location (see | |
| `org-refile'). | |
| Use `org-agenda-refile' in `org-agenda' mode." | |
| (let* ((pos (with-current-buffer (or (get-buffer file) ;Is the file open in a buffer already? | |
| (find-file-noselect file)) ;Otherwise, try to find the file by name (Note, default-directory matters here if it isn't absolute) | |
| (or (org-find-exact-headline-in-buffer headline) | |
| (error "Can't find headline `%s'" headline)))) | |
| (filepath (buffer-file-name (marker-buffer pos)));If we're given a relative name, find absolute path | |
| (rfloc (list headline filepath nil pos))) | |
| (if (and (eq major-mode 'org-agenda-mode) (not (and arg (listp arg)))) ;Don't use org-agenda-refile if we're just jumping | |
| (org-agenda-refile nil rfloc) | |
| (org-refile arg nil rfloc)))) | |
| (defun josh/refile (file headline &optional arg) | |
| "Refile to HEADLINE in FILE. Clean up org-capture if it's activated. | |
| With a `C-u` ARG, just jump to the headline." | |
| (interactive "P") | |
| (let ((is-capturing (and (boundp 'org-capture-mode) org-capture-mode))) | |
| (cond | |
| ((and arg (listp arg)) ;Are we jumping? | |
| (my/refile file headline arg)) | |
| ;; Are we in org-capture-mode? | |
| (is-capturing ;Minor mode variable that's defined when capturing | |
| (josh/org-capture-refile-but-with-args file headline arg)) | |
| (t | |
| (my/refile file headline arg))) | |
| (when (or arg is-capturing) | |
| (setq hydra-deactivate t)))) | |
| (defun josh/org-capture-refile-but-with-args (file headline &optional arg) | |
| "Copied from `org-capture-refile' since it doesn't allow passing arguments. This does." | |
| (unless (eq (org-capture-get :type 'local) 'entry) | |
| (error | |
| "Refiling from a capture buffer makes only sense for `entry'-type templates")) | |
| (let ((pos (point)) | |
| (base (buffer-base-buffer (current-buffer))) | |
| (org-capture-is-refiling t) | |
| (kill-buffer (org-capture-get :kill-buffer 'local))) | |
| (org-capture-put :kill-buffer nil) | |
| (org-capture-finalize) | |
| (save-window-excursion | |
| (with-current-buffer (or base (current-buffer)) | |
| (org-with-wide-buffer | |
| (goto-char pos) | |
| (my/refile file headline arg)))) | |
| (when kill-buffer (kill-buffer base)))) | |
| (defmacro josh/make-org-refile-hydra (hydraname file keyandheadline) | |
| "Make a hydra named HYDRANAME with refile targets to FILE. | |
| KEYANDHEADLINE should be a list of cons cells of the form (\"key\" . \"headline\")" | |
| `(defhydra ,hydraname (:color blue :after-exit (unless (or hydra-deactivate | |
| current-prefix-arg) ;If we're just jumping to a location, quit the hydra | |
| (josh/org-refile-hydra/body))) | |
| ,file | |
| ,@(cl-loop for kv in keyandheadline | |
| collect (list (car kv) (list 'josh/refile file (cdr kv) 'current-prefix-arg) (cdr kv))) | |
| ("q" nil "cancel"))) | |
| ;;;;;;;;;; | |
| ;; Here we'll define our refile headlines | |
| ;;;;;;;;;; | |
| (josh/make-org-refile-hydra josh/org-refile-hydra-file-a | |
| "file-a.org" | |
| (("1" . "Headline 1") | |
| ("2" . "Headline 2"))) | |
| (josh/make-org-refile-hydra josh/org-refile-hydra-file-b | |
| "file-b.org" | |
| (("1" . "One") | |
| ("2" . "Two"))) | |
| (josh/make-org-refile-hydra josh/org-refile-hydra-file-c | |
| "file-c.org" | |
| (("1" . "1") | |
| ("2" . "2"))) | |
| (defhydra josh/org-refile-hydra (:foreign-keys run) | |
| "Refile" | |
| ("a" josh/org-refile-hydra-file-a/body "File A" :exit t) | |
| ("b" josh/org-refile-hydra-file-b/body "File B" :exit t) | |
| ("c" josh/org-refile-hydra-file-c/body "File C" :exit t) | |
| ("j" org-refile-goto-last-stored "Jump to last refile" :exit t) | |
| ("q" nil "cancel")) | |
| (global-set-key (kbd "<f9> r") 'josh/org-refile-hydra/body) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment