I am experiencing a very strange behavior with org-babel code blocks. When I operate without the :session tag, I am free to use :dir to set my working directory. As you can see, the following code runs as expected:

enter image description here

but if I now add a :session argument, babel ignores my :dir tag and instead returns my default working directory:

enter image description here

What am I doing wrong?

  • 1
    Please do not include text as images: you can cut and paste it into the question instead and use code formatting.
    – NickD
    Apr 19 '20 at 18:16

You are doing nothing wrong, but a :dir header arg will not affect an existing session. If you kill the existing session and then re-evaluate the source block, the current directory should be the one you specified in the header-arg property.

  • Ah, you are right! Well I definitely don't want the code to just fail silently. But I can see how switching the working directory for an existing session might be problematic. Perhaps a prompt in the minibuffer would be best. Something like "Do you really want to change the working directory of an existing R session? [Y/n]"
    – Adam
    Apr 19 '20 at 22:58
  • It's not failing. It just doesn't see the :dir argument at all. When there is a session, the code block is executed by sending all the commands in the code block to the session: that's all. The header args are used to set up the session in the first place: after that, they are not used again.
    – NickD
    Apr 20 '20 at 1:20
  • I probably should have said "Some header args (like :session or :dir) are used to set up the session...". There are header args (like :results) that are used by org-babel to format the results that it retrieves from the session and those are used every time the code block is executed.
    – NickD
    Apr 20 '20 at 1:57

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
  :header-args: :dir ~/org/studies/study_1

  #+BEGIN_SRC R :session *R*

* 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)
   (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)
        (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)

;; Advise org-babel-execute-src-block
(defadvice org-babel-execute-src-block (before set-working-dir-b activate) 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.