Babel Bug: execute scheme code blocks in batch mode
Table of Contents
1 The problem
Few days ago I wrote a scheme code block in one of my org file, then I run a command(call emacs in batch mode) to export it into html, and I encounter an error.
You can reproduce the error (with org-mode version 8.2.5h ) by these steps:
- install/setup org-mode and geiser.
write an org file (e.g.
scheme-test.org
) with below content:#+BEGIN_SRC scheme :exports results :results output raw (display "Hello Scheme in OrgMode") #+END_SRC
export the org file with command:
emacs --batch --eval='(load "~/.emacs.d/init.el")' scheme-test.org -f org-html-export-to-html
then you will see the error if you have set
debug-on-error
to non-nil:... Guile REPL up and running! => "Hello Scheme in OrgMode" Debugger entered--Lisp error: (wrong-type-argument arrayp nil) org-babel-scheme-execute-with-geiser("(display \"Hello Scheme in OrgMode\")" t guile nil) org-babel-execute:scheme("(display \"Hello Scheme in OrgMode\")" ((:comments . "") (:shebang . "") (:cache . "no") (:padline . "") (:noweb . "no") (:tangle . "no") (:exports . "results") (:results . "raw output replace") (:colname-names) (:hlines . "no") (:result-params "replace" "output" "raw") (:result-type . output) (:rowname-names) (:session . "none"))) org-babel-execute-src-block(nil ("scheme" "(display \"Hello Scheme in OrgMode\")" ((:colname-names) (:rowname-names) (:result-params "replace" "output" "raw" "replace" "output" "raw") (:result-type . output) (:comments . "") (:shebang . "") (:cache . "no") (:padline . "") (:noweb . "no") (:tangle . "no") (:exports . "results") (:results . "replace output raw") (:session . "none") (:rowname-names) (:result-type . output) (:result-params "replace" "output" "raw") (:hlines . "no") (:colname-names)) "" nil 0 2)) org-babel-exp-results(("scheme" "(display \"Hello Scheme in OrgMode\")" ((:cache . "no") (:colname-names) (:comments . "") (:exports . "results") (:hlines . "no") (:noweb . "no") (:padline . "") (:result-params "replace" "output" "raw") (:result-type . output) (:results . "replace output raw") (:rowname-names) (:session . "none") (:shebang . "") (:tangle . "no")) "" nil 0 2) block nil "a01854650514fd2cec7ce6957a4622b52118fcd3") ...
- But, if you export this org file in interactive mode (not batch mode), no error occurs.
2 The simple solution
After doing a little investigation of ob-scheme.el and geiser, I find the root cause:
function `current-message' always returns nil in batch mode
ob-scheme uses geiser repl to execute the scheme code block, geiser
repl shows the results with function message
, then ob-scheme gets
the results by calling function current-message
, and this exactly
the problem is.
So I write a macro to capture the current message in both interactive mode and batch mode:
(defmacro org-babel-scheme-capture-current-message (&rest body) "Capture current message in both interactive and noninteractive mode" `(if noninteractive (let ((current-message nil)) (flet ((message (fmt &rest args) (setq current-message (apply #'format fmt args)))) ,@body current-message)) (progn ,@body (current-message))))
Then wrap the geiser-eval-region call with the macro to get the results. Fortunately it works for me.
3 The patch
Here is the patch:
diff --git a/lisp/ob-scheme.el b/lisp/ob-scheme.el index b7117e9..3b7ceb2 100644 --- a/lisp/ob-scheme.el +++ b/lisp/ob-scheme.el @@ -118,6 +118,17 @@ org-babel-scheme-execute-with-geiser will use a temporary session." (name)))) result)) +(defmacro org-babel-scheme-capture-current-message (&rest body) + "Capture current message in both interactive and noninteractive mode" + `(if noninteractive + (let ((current-message nil)) + (flet ((message (fmt &rest args) (setq current-message (apply #'format fmt args)))) + ,@body + current-message)) + (progn + ,@body + (current-message)))) + (defun org-babel-scheme-execute-with-geiser (code output impl repl) "Execute code in specified REPL. If the REPL doesn't exist, create it using the given scheme implementation. @@ -142,10 +153,11 @@ is true; otherwise returns the last value." (current-buffer))))) (setq geiser-repl--repl repl-buffer) (setq geiser-impl--implementation nil) - (geiser-eval-region (point-min) (point-max)) + (setq result (org-babel-scheme-capture-current-message + (geiser-eval-region (point-min) (point-max)))) (setq result - (if (equal (substring (current-message) 0 3) "=> ") - (replace-regexp-in-string "^=> " "" (current-message)) + (if (and (stringp result) (equal (substring result 0 3) "=> ")) + (replace-regexp-in-string "^=> " "" result) "\"An error occurred.\"")) (when (not repl) (save-current-buffer (set-buffer repl-buffer)
4 Notice
flet
(the dynamic flet) is obsolete since emacs 24.3, but this is a
quick way I found to fix the problem without upstream package
(geiser) changes.
5 Update 1
I refactored a new patch without flet
, and it has been merge into
orgmode, see
http://orgmode.org/cgit.cgi/org-mode.git/commit/?id=21d6d7c3a0b08382e4dfc5d7300f61ba5afe6f12
.