For context, I was inspired to try to configure emacs to execute Mathematica source blocks in org files after watching this video wherein someone demonstrates the use of another CAS, SageMath, in emacs org mode. I would use SageMath instead of Mathematica since I can just install ob-sagemath from MELPA, but the problem is I'm using macOS Big Sur and SageMath doesn't support my operating system.
I read this article from 2014 in which the author talks about creating support for mathematica in org mode and I've copied his source code into /.emacs.d/ob/ob-mathematica.el
(require 'ob)
(require 'ob-ref)
(require 'ob-comint)
(require 'ob-eval)
;; Optionally require mma.el for font lock, etc
(require 'mma nil 'noerror)
(add-to-list 'org-src-lang-modes '("mathematica" . "mma"))
(defvar org-babel-tangle-lang-exts)
(add-to-list 'org-babel-tangle-lang-exts '("mathematica" . "m"))
(defvar org-babel-default-header-args:mathematica '())
(defvar org-babel-mathematica-command "MathematicaScript -script"
"Name of the command for executing Mathematica code.")
(defun org-babel-expand-body:mathematica (body params)
"Expand BODY according to PARAMS, return the expanded body."
(let ((vars (mapcar #'cdr (org-babel-get-header params :var))))
(concat
(mapconcat ;; define any variables
(lambda (pair)
(format "%s=%s;"
(car pair)
(org-babel-mathematica-var-to-mathematica (cdr pair))))
vars "\n") "\nPrint[\n" body "\n]\n")))
(defun org-babel-execute:mathematica (body params)
"Execute a block of Mathematica code with org-babel. This function is
called by `org-babel-execute-src-block'"
(let* ((result-params (cdr (assoc :result-params params)))
(full-body (org-babel-expand-body:mathematica body params))
(tmp-script-file (org-babel-temp-file "mathematica-")))
;; actually execute the source-code block
(with-temp-file tmp-script-file (insert full-body))
;; (with-temp-file "/tmp/dbg" (insert full-body))
((lambda (raw)
(if (or (member "code" result-params)
(member "pp" result-params)
(and (member "output" result-params)
(not (member "table" result-params))))
raw
(org-babel-script-escape (org-babel-trim raw))))
(org-babel-eval (concat org-babel-mathematica-command " " tmp-script-file) ""))))
(defun org-babel-prep-session:mathematica (session params)
"This function does nothing so far"
(error "Currently no support for sessions"))
(defun org-babel-prep-session:mathematica (session body params)
"This function does nothing so far"
(error "Currently no support for sessions"))
(defun org-babel-mathematica-var-to-mathematica (var)
"Convert an elisp value to a Mathematica variable.
Convert an elisp value, VAR, into a string of Mathematica source code
specifying a variable of the same value."
(if (listp var)
(concat "{" (mapconcat #'org-babel-mathematica-var-to-mathematica var ", ") "}")
(format "%S" var)))
(provide 'ob-mathematica)
I then put the following in my .emacs
file:
;; ...
(add-to-list 'load-path "/Users/duncanbritt/.emacs.d/ob/")
(load "/Users/duncanbritt/.emacs.d/ob/ob-mathematica.el")
(org-babel-do-load-languages
'org-babel-load-languages
'(
;; ...
(mathematica . t)
))
;; ...
When I try to run mathematica source blocks in org mode, such as
#+begin_SRC mathematica
1 + 1
#+end_SRC mathematica
I get the following message in the mini-buffer: Symbol's function definition is void: org-babel-get-header
, which I assume references a line in my ob-mathematica.el
file. As I understand it, this occurs because org-babel-get-header was removed in 0d000f5 (babel: small change in API., 2015-10-29). (By the way, the solution in the linked post is not applicable in my case. The poster was trying to execute shell scripts and was able to resolve the issue by changing (sh . t) to (shell . t)
in their emacs configuration. This won't work for me because I'm trying to execute mathematica code using a custom .el file, since there isn't an official emacs package that I can use to evaluate mathematica code in org files in emacs.)
I'm not familiar with emacs lisp. My question is, how can I update this code to use current emacs API's, such that the above error is resolved?