8

If I run the following babel shell blocks

#+BEGIN_SRC sh :session one :results output
  ssh staging
#+END_SRC

#+BEGIN_SRC sh :session one :results output
  hostname
#+END_SRC

Org creates a shell buffer called one, runs ssh staging and then after connecting, executes hostname on staging. However, if I tweak the ssh command and run it again it attempts to run it from within session one, from the staging host. If I close the buffer one it resets the session as the next time any command is run with that session name it recreates it. What I haven't been able to find is a method to force a particular babel block to always initialize a new session.

I'm aware that for some languages (elisp in particular) this would not be possible. I suppose I could prepend the session with an elisp block containing (kill-buffer "one"), but would rather this was a header argument if possible. I'm also aware that for this example I could simply combine the two into a single block with no session, but I'm interested in more complicated sequences.

Is there a :prologue command or some other special argument to :session that forces that block to initialize a new shell on every invocation?

1
  • There is no such option (or a source code block parameter) in Org 8.2.10, but it should be pretty easy to add. I would start by hacking org-babel-initiate-session. Dec 11, 2014 at 16:59

2 Answers 2

5

Try this

Force an org-babel session to reset or initialize by using an elisp conditional statement to dynamically set the value of the :session header on the first code block.

e.g. :session (if (get-buffer "one") (if (kill-buffer "one") (print "one") (print "one")) (print "one"))

In the above code, get-buffer function checks if buffer named one exists. If true, the kill-buffer function kills the one buffer then returns a value of t or nil which is passed to the if statement. In this specific example, the nested if statement will always return a value of one. Please note, I'm still learning elisp.

Below is the updated example code:

#+BEGIN_SRC sh :session (if (get-buffer "one") (if (kill-buffer "one") (print "one") (print "one")) (print "one")) :results output
  ssh staging
#+END_SRC

#+BEGIN_SRC sh :session one :results output
  hostname
#+END_SRC

Each time the first code block is executed, emacs will ask to kill the one buffer, so you can reset the session when you desire.

EDIT

Oops missed part that you always wanted buffer killed, i.e. no prompting. Execute this block first to temporarily turn off prompting to kill buffer.

#+BEGIN_SRC elisp
  (setq kill-buffer-query-functions
    (remq 'process-kill-buffer-query-function
           kill-buffer-query-functions))
#+END_SRC

Hope that helped!

Note: This code was tested using the following versions of emacs and org-mode.

GNU Emacs 24.4.1 (x86_64-apple-darwin14.0.0, NS apple-appkit-1343.14)
Org-mode version 8.2.10 (8.2.10-29-g89a0ac-elpa)

In conclusion, I found technical inspiration for this answer on the org-scraps website and this kill-buffer example code on stackoverflow.

5
  • @dgtized did this answer help?
    – Melioratus
    Jan 10, 2015 at 7:23
  • 2
    I wasn't aware you could embed elisp in the session call, so thank you for that. That said, as I mentioned in the original question, I was aware that I could automate kill-buffer to force a new session, but was more interested in learning if there was a block argument built into org-mode, or some other established convention for doing this that I was not aware of. Your approach is a nice work-around, but I'm hoping there is a canonical approach for this.
    – dgtized
    Jan 15, 2015 at 22:39
  • @dgtized - Are you looking for an answer like this? :session one :session-reset yes?
    – Melioratus
    Jan 16, 2015 at 5:09
  • Something like that sure. Again, it's as much a question of what the recommended practice is for this example. Surely other people have sessions that need resetting, and if they just kill the buffer that's fine, but I want to know what the standard practice is.
    – dgtized
    Jan 16, 2015 at 18:48
  • 1
    @dgtized - Thanks for clarifying! This is great question! I have not found a documented standard practice but I will keep looking.
    – Melioratus
    Jan 18, 2015 at 17:57
3

Inspired by @Melioratus.

Currently, org-babel provides a hook called org-babel-after-execute-hook. I extended the supported arguments of org-babel src block by using it:

(I'm using org-babel for elixir. If you want supports of other languages, extend cond by yourself.)

(add-hook 'org-babel-after-execute-hook 'semacs/ob-args-ext-session-reset)

(defun semacs/ob-args-ext-session-reset()
  (let* ((src-block-info (org-babel-get-src-block-info 'light))
         (language (nth 0 src-block-info))
         (arguments (nth 2 src-block-info))
         (should-reset (member '(:session-reset . "yes") arguments))
         (session (cdr (assoc :session arguments)))
         (session-process
          (cond ((equal language "elixir") (format "*elixir-%s*" session))
                (t nil))))
    (if (and should-reset (get-process session-process))
        (kill-process session-process))))

After evaluating above code, you can write src block like this:

#+begin_src elixir :session-reset yes
  IO.puts("HELLO WORLD")
#+end_src

After evaluating src block, org-babel will cleanup the corresponding session.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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