浏览代码

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

Eric Schulte 16 年之前
父节点
当前提交
c5a58ad6aa
共有 2 个文件被更改,包括 171 次插入71 次删除
  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]
 * 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
 ** 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]]
 [[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
 ** TODO pass mutliple reference arguments into R
    Can we do this? I wasn't sure how to supply multiple 'var' header
    Can we do this? I wasn't sure how to supply multiple 'var' header
    args. Just delete this TODO if I'm being dense.
    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
 ** PROPOSED support for passing paths to files between source blocks
 Maybe this should be it's own result type (in addition to scalars and
 Maybe this should be it's own result type (in addition to scalars and