Browse Source

moving generalized comint functions to new file org-babel-comint.el

Eric Schulte 16 years ago
parent
commit
c5a58ad6aa
2 changed files with 171 additions and 71 deletions
  1. 93 0
      lisp/org-babel-comint.el
  2. 78 71
      org-babel.org

+ 93 - 0
lisp/org-babel-comint.el

@@ -0,0 +1,93 @@
+;;; org-babel-comint.el --- org-babel functions for interaction with comint buffers
+
+;; Copyright (C) 2009 Eric Schulte
+
+;; Author: Eric Schulte
+;; Keywords: literate programming, reproducible research, comint
+;; Homepage: http://orgmode.org
+;; Version: 0.01
+
+;;; License:
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;; Commentary:
+
+;; This file should provide support for passing commands and results
+;; to and from `comint-mode' buffers.
+
+;;; Code:
+(require 'org-babel)
+
+(defun org-babel-comint-initiate-buffer (buffer ignite)
+  "If BUFFER does not currently have a process use IGNITE to
+create one."
+  (unless (and (buffer-live-p buffer) (get-buffer buffer))
+    (save-excursion
+      (eval ignite)
+      (setf buffer (current-buffer))
+      (org-babel-comint-wait-for-output)
+      (org-babel-comint-input-command ""))))
+
+(defun org-babel-comint-command-to-string (buffer command)
+  "Send COMMEND to BUFFER's process, and return the results as a string."
+  (org-babel-comint-input-command buffer command)
+  (org-babel-comint-last-output buffer))
+
+(defun org-babel-comint-input-command (buffer command)
+  "Pass COMMAND to the process running in BUFFER."
+  (save-excursion
+    (save-match-data
+      (set-buffer buffer)
+      (goto-char (process-mark (get-buffer-process (current-buffer))))
+      (insert command)
+      (comint-send-input)
+      (org-babel-comint-wait-for-output))))
+
+(defun org-babel-comint-wait-for-output (buffer)
+  "Wait until output arrives"
+  (save-excursion
+    (save-match-data
+      (set-buffer buffer)
+      (while (progn
+	       (goto-char comint-last-input-end)
+	       (not (re-search-forward comint-prompt-regexp nil t)))
+	(accept-process-output (get-buffer-process (current-buffer)))))))
+
+(defun org-babel-comint-last-output (buffer)
+  "Return BUFFER's the last output as a string"
+  (save-excursion
+    (save-match-data
+      (set-buffer buffer)
+      (goto-char (process-mark (get-buffer-process (current-buffer))))
+      (forward-line 0)
+      (let ((raw (buffer-substring comint-last-input-end (- (point) 1)))
+            output output-flag)
+        (mapconcat
+         (lambda (el)
+           (if (stringp el)
+               (format "%s" el)
+             (format "%S" el)))
+         (delq nil
+               (mapcar
+                (lambda (line)
+                  (unless (string-match "^>" line)
+                    (and (string-match "\\[[[:digit:]]+\\] *\\(.*\\)$" line)
+                         (match-string 1 line))))
+                ;; drop first, because it's the last line of input
+                (cdr (split-string raw "[\n\r]")))) "\n")))))
+
+;;; org-babel-comint.el ends here

+ 78 - 71
org-babel.org

@@ -115,6 +115,84 @@ and the results to be collected in the same table.
 
 
 * Tasks [20/32]
+** TODO Create objects in top level (global) environment in R?
+*** initial requirement statement [DED]
+   At the moment, objects created by computations performed in the
+   code block are evaluated in the scope of the
+   code-block-function-body and therefore disappear when the code
+   block is evaluated {unless you employ some extra trickery like
+   assign('name', object, env=globalenv()) }. I think it will be
+   desirable to also allow for a style wherein objects that are
+   created in one code block persist in the R global environment and
+   can be re-used in a separate block.
+
+   This is what Sweave does, and while I'm not saying we have to be
+   the same as Sweave, it wouldn't be hard for us to provide the same
+   behaviour in this case; if we don't, we risk undeservedly being
+   written off as an oddity by some.
+
+   IOW one aspect of org-babel is that of a sort of functional
+   meta-programming language. This is crazy, in a very good
+   way. Nevertheless, wrt R I think there's going to be a lot of value
+   in providing for a working style in which the objects are stored in
+   the R session, rather than elisp/org buffer. This will be a very
+   familiar working style to lots of people.
+
+   There are no doubt a number of different ways of accomplishing
+   this, the simplest being a hack like adding
+
+#+begin_src R
+for(objname in ls())
+    assign(objname, get(objname), envir=globalenv())
+#+end_src
+
+to the source code block function body. (Maybe wrap it in an on.exit() call).
+
+However this may deserve to be thought about more carefully, perhaps
+with a view to having a uniform approach across languages. E.g. shell
+code blocks have the same semantics at the moment (no persistence of
+variables across code blocks), because the body is evaluated in a new
+bash shell process rather than a running shell. And I guess the same
+is true for python. However, in both these cases, you could imagine
+implementing the alternative in which the body is evaluated in a
+persistent interactive session. It's just that it's particularly
+natural for R, seeing as both ESS and org-babel evaluate commands in a
+single persistent R session.
+
+*** sessions [Eric]
+
+Thanks for bringing this up.  I think you are absolutely correct that we
+should provide support for a persistent environment (maybe called a
+*session*) in which to evaluate code blocks.  I think the current setup
+demonstrates my personal bias for a functional style of programming
+which is certainly not ideal in all contexts.
+
+While the R function you mention does look like an elegant solution, I
+think we should choose an implementation that would be the same across
+all source code types.  Specifically I think we should allow the user to
+specify an optional *session* as a header variable (when not present we
+assume a default session for each language).  The session name could be
+used to name a comint buffer (like the *R* buffer) in which all
+evaluation would take place (within which variables would retain their
+values --at least once I remove some of the functional method wrappings
+currently in place-- ).
+
+This would allow multiple environments to be used in the same buffer,
+and once this setup was implemented we should be able to fairly easily
+implement commands for jumping between source code blocks and the
+related session buffers, as well as for dumping the last N commands from
+a session into a new or existing source code block.
+
+Please let me know if you foresee any problems with this proposed setup,
+or if you think any parts might be confusing for people coming from
+Sweave.  I'll hopefully find some time to work on this later in the
+week.
+*** implementation
+in [[file:lisp/org-babel-comint.el][org-babel-comint.el]]
+
+Currently I've coppied and begun generalizing the functions for
+interacting with R buffers.
+
 ** TODO improve the source-block snippet
 
 [[file:~/src/emacs-starter-kit/src/snippets/text-mode/rst-mode/chap::name%20Chapter%20title][file:~/src/emacs-starter-kit/src/snippets/text-mode/rst-mode/chap::name Chapter title]]
@@ -247,77 +325,6 @@ Another example is in the [[*operations%20in%20on%20tables][grades example]].
 ** TODO pass mutliple reference arguments into R
    Can we do this? I wasn't sure how to supply multiple 'var' header
    args. Just delete this TODO if I'm being dense.
-** TODO Create objects in top level (global) environment in R?
-   At the moment, objects created by computations performed in the
-   code block are evaluated in the scope of the
-   code-block-function-body and therefore disappear when the code
-   block is evaluated {unless you employ some extra trickery like
-   assign('name', object, env=globalenv()) }. I think it will be
-   desirable to also allow for a style wherein objects that are
-   created in one code block persist in the R global environment and
-   can be re-used in a separate block.
-
-   This is what Sweave does, and while I'm not saying we have to be
-   the same as Sweave, it wouldn't be hard for us to provide the same
-   behaviour in this case; if we don't, we risk undeservedly being
-   written off as an oddity by some.
-
-   IOW one aspect of org-babel is that of a sort of functional
-   meta-programming language. This is crazy, in a very good
-   way. Nevertheless, wrt R I think there's going to be a lot of value
-   in providing for a working style in which the objects are stored in
-   the R session, rather than elisp/org buffer. This will be a very
-   familiar working style to lots of people.
-
-   There are no doubt a number of different ways of accomplishing
-   this, the simplest being a hack like adding
-
-#+begin_src R
-for(objname in ls())
-    assign(objname, get(objname), envir=globalenv())
-#+end_src
-
-to the source code block function body. (Maybe wrap it in an on.exit() call).
-
-However this may deserve to be thought about more carefully, perhaps
-with a view to having a uniform approach across languages. E.g. shell
-code blocks have the same semantics at the moment (no persistence of
-variables across code blocks), because the body is evaluated in a new
-bash shell process rather than a running shell. And I guess the same
-is true for python. However, in both these cases, you could imagine
-implementing the alternative in which the body is evaluated in a
-persistent interactive session. It's just that it's particularly
-natural for R, seeing as both ESS and org-babel evaluate commands in a
-single persistent R session.
-
-*** sessions [Eric]
-
-Thanks for bringing this up.  I think you are absolutely correct that we
-should provide support for a persistent environment (maybe called a
-*session*) in which to evaluate code blocks.  I think the current setup
-demonstrates my personal bias for a functional style of programming
-which is certainly not ideal in all contexts.
-
-While the R function you mention does look like an elegant solution, I
-think we should choose an implementation that would be the same across
-all source code types.  Specifically I think we should allow the user to
-specify an optional *session* as a header variable (when not present we
-assume a default session for each language).  The session name could be
-used to name a comint buffer (like the *R* buffer) in which all
-evaluation would take place (within which variables would retain their
-values --at least once I remove some of the functional method wrappings
-currently in place-- ).
-
-This would allow multiple environments to be used in the same buffer,
-and once this setup was implemented we should be able to fairly easily
-implement commands for jumping between source code blocks and the
-related session buffers, as well as for dumping the last N commands from
-a session into a new or existing source code block.
-
-Please let me know if you foresee any problems with this proposed setup,
-or if you think any parts might be confusing for people coming from
-Sweave.  I'll hopefully find some time to work on this later in the
-week.
 
 ** PROPOSED support for passing paths to files between source blocks
 Maybe this should be it's own result type (in addition to scalars and