After several days of hacking my way through eLisp, I may have a working solution. The following code automatically sets the working directory of whichever R process is frontmost to match the :dir
value of whichever org-babel
R block you are working from.
So suppose you manage all of your R projects from a single studies.org
file, where each header represents a new project. Your org
file may look something like this:
* Study 1
:PROPERTIES:
:header-args: :dir ~/org/studies/study_1
:END:
#+BEGIN_SRC R :session *R*
getwd()
#+END_SRC
* Study 2
* Study 3
...
* Study n
If you are working on a code in Study 1, you don't want your output saved to a project folder for Studies 2 or your data loaded from a csv from Study 3 (which is entirely possible under the default configuration).
The following code is intended to do something about this:
;; Get :dir
(defun org-header-arg (p)
(setq args (org-babel-get-src-block-info))
(assoc-default p (nth 2 args)))
;; Get language of source block
(defun get-src-language ()
(setq args (org-babel-get-src-block-info))
(nth 0 args))
;; Send message to R process
(defun send-msg-r (w)
(ess-send-string
(get-process "R")
(format "setwd(\"%s\")" w)))
;; If point is in an R code block then if R is running: setwd()
;; Else if R is not running, run R and setwd().
(defun setwd-dir ()
(if (string= (get-src-language) "R")
(if (eq (get-process "R") nil)
(progn
(setq w (org-header-arg :dir)) ;; Capture before R redirects
(defadvice R (after set-working-dir-R activate) (send-msg-r w))
(save-excursion (R)))
(send-msg-r (org-header-arg :dir)))))
;; Advise org-edit-special
(defadvice org-edit-special (before set-working-dir activate)
(setwd-dir))
;; Advise org-babel-execute-src-block
(defadvice org-babel-execute-src-block (before set-working-dir-b activate)
(setwd-dir))