12

I'm trying to write a function that will take a heading and refile it to one specific location. The doc for org-refile is

(org-refile &optional GOTO DEFAULT-BUFFER RFLOC MSG)

and RFLOC is

RFLOC can be a refile location obtained in a different way.

but I have no clue what "a different way" would be and I've been googling for half a day and not seen any examples. I know the file and I know the headline for the target but I don't know the syntax to form it into what it wants. The closest I've gotten is:

(org-refile nil #("~/Org/bookmarks.org")

which will then prompt me for the headline, but of course I don't want it to prompt me, I want to provide it.

I'm new to elisp and I've guessed at every syntax I can think of. Does anyone know how to phrase this?

jtgd
  • 944
  • 4
  • 13
  • There must be a way to do what you actually want to here, but if you don't find it, here's a workaround: http://stackoverflow.com/questions/7681326/refiling-to-a-given-subtree-by-a-keybinding/7682841 – Brian Z Feb 07 '15 at 13:18
  • I use the following snippet to do what you are seeking: `(let* ( (org-archive-location "/path/to/org-file::* NAME_OF_HEADING") (org-archive-save-context-info nil)) (org-archive-subtree))` I probably won't be putting this into an answer since you asked about `org-refile`, but the snippet does the job quite nicely. The two colons are **are** needed. I use this all the time, and have even created a custom version of `org-archive-subtree` to suppress the message so that I don't have hundreds of them when I automatically reorganize my entire org file. – lawlist Feb 07 '15 at 16:33
  • Thanks lawlist, this is a nice snippet and I will probably use this in another context. Good to have it documented here. – jtgd Feb 08 '15 at 00:30

2 Answers2

10

I've wondered what RFLOC should look like before, but never investigated. Looking at the org source code, it should be a list consisting of:

  • heading
  • file
  • re (regular expression)
  • pos (position of target heading)

I haven't experimented with the re element, but here is a simple function that will invoke org-refile with a RFLOC built from a given FILE and HEADING:

(defun my/refile (file headline)
  (let ((pos (save-excursion
               (find-file file)
               (org-find-exact-headline-in-buffer headline))))
    (org-refile nil nil (list headline file nil pos))))

This opens the target file and uses an org function to find the position of the target headline, then builds the RFLOC list to pass to org-refile.

glucas
  • 20,175
  • 1
  • 51
  • 83
5

Thanks much @glucas, I've worked your solution into my final one. The key information was knowing the format of the RFLOC. I did experiment with providing a list of filename and headline text, but I was missing those other elements, and the extra nil. This is what I ended up with:

(defun jay/refile-to (file headline)
    "Move current headline to specified location"
    (let ((pos (save-excursion
                 (find-file file)
                 (org-find-exact-headline-in-buffer headline))))
      (org-refile nil nil (list headline file nil pos))))

(defun jay/refile-to-bookmarks ()
    "Move current headline to bookmarks"
    (interactive)
    (org-mark-ring-push)
    (jay/refile-to "~/Org/bookmarks.org" "New")
    (org-mark-ring-goto))

The doc for save-excursion states that we will be returned to the location that we started from, but it does not seem to work that way. It leaves me in the target destination, which might be proper for the general refile-to, but I wanted to just have it move the line and remain where I was so I save and restore within refile-to-bookmark.

The workflow that this is meant for is that I start with a list of HTML links that come from my script for reading RSS feeds. I originally had the script produce maildir files for mu4e, but found myself just following the links to a browser anyway and then bookmarking the ones of interest, so now I just generate a list of ** [[uri][title]] lines. After I follow the link from emacs to the uzbl browser, instead of bookmarking (which generates the same form of lines) I use this command to move the link to my bookmarks.org after setting tags. Just a bit faster since I also use the org speed-commands, t to tag and b for this command. I'm happy now and love to learn more elisp!

jtgd
  • 944
  • 4
  • 13
  • A couple details, not directly relevant to what you're doing here: the first element of the RFLOC can actually be any string. It is only being used as a logical name for the target location, shown in the "refiled to xxx" message. The location is really just defined by the file and position marker. The `re` element of the RFLOC will be ignored, as far as I can tell. It is used in a few other functions in in org.el that deal with target locations. – glucas Feb 08 '15 at 16:28
  • 1
    For reasons I don't understand, I was able to get your `refile-to` function to return to the original position by adding this at the end, after the `let`: `(switch-to-buffer (current-buffer))`. This seems like it shouldn't do anything, but it works for me. – glucas Feb 08 '15 at 16:49
  • Thanks again @glucas. Yes that does seem to work and I've replaced my `-push` and `-goto` with that. It does seem strange that you are left in another buffer and yet it considers the current buffer to be the previous one. – jtgd Feb 09 '15 at 01:12