config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

ob-maxima.el (8189B)


      1 ;;; ob-maxima.el --- Babel Functions for Maxima      -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) 2009-2024 Free Software Foundation, Inc.
      4 
      5 ;; Author: Eric S Fraga
      6 ;;	Eric Schulte
      7 ;; Keywords: literate programming, reproducible research, maxima
      8 ;; URL: https://orgmode.org
      9 
     10 ;; This file is part of GNU Emacs.
     11 
     12 ;; GNU Emacs is free software: you can redistribute it and/or modify
     13 ;; it under the terms of the GNU General Public License as published by
     14 ;; the Free Software Foundation, either version 3 of the License, or
     15 ;; (at your option) any later version.
     16 
     17 ;; GNU Emacs is distributed in the hope that it will be useful,
     18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     20 ;; GNU General Public License for more details.
     21 
     22 ;; You should have received a copy of the GNU General Public License
     23 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
     24 
     25 ;;; Commentary:
     26 
     27 ;; Org-Babel support for evaluating maxima entries.
     28 ;;
     29 ;; This differs from most standard languages in that
     30 ;; 1) there is no such thing as a "session" in maxima
     31 ;; 2) we are adding the "cmdline" header argument
     32 
     33 ;;; Code:
     34 
     35 (require 'org-macs)
     36 (org-assert-version)
     37 
     38 (require 'ob)
     39 
     40 (defconst org-babel-header-args:maxima
     41   '((batch               . ((batchload batch load)))
     42     (graphics-pkg        . ((plot draw))))
     43   "Maxima-specific header arguments.")
     44 
     45 (defvar org-babel-tangle-lang-exts)
     46 (add-to-list 'org-babel-tangle-lang-exts '("maxima" . "max"))
     47 
     48 (defvar org-babel-default-header-args:maxima '())
     49 
     50 (defcustom org-babel-maxima-command
     51   (if (boundp 'maxima-command) maxima-command "maxima")
     52   "Command used to call maxima on the shell."
     53   :group 'org-babel
     54   :type 'string)
     55 
     56 (defvar org-babel-maxima--command-arguments-default
     57   "--very-quiet"
     58   "Command-line arguments sent to Maxima by default.
     59 If the `:batch' header argument is set to `batchload' or unset,
     60 then the `:cmdline' header argument is appended to this default;
     61 otherwise, if the `:cmdline' argument is set, it over-rides this
     62 default.  See `org-babel-maxima-command' and
     63 `org-babel-execute:maxima'.")
     64 
     65 (defvar org-babel-maxima--graphic-package-options
     66   '((plot . "(set_plot_option ('[gnuplot_term, %s]), set_plot_option ('[gnuplot_out_file, %S]))$")
     67     (draw . "(load(draw), set_draw_defaults(terminal='%s,file_name=%S))$"))
     68   "An alist of graphics packages and Maxima code.
     69 Each element is a cons (PACKAGE-NAME . FORMAT-STRING).
     70 FORMAT-STRING contains Maxima code to configure the graphics
     71 package; it must contain `%s' to set the terminal and `%S' to set
     72 the filename, in that order.  The default graphics package is
     73 `plot'; `draw' is also supported.  See
     74 `org-babel-maxima-expand'.")
     75 
     76 (defvar org-babel-maxima--default-epilogue
     77   '((graphical-output . "gnuplot_close ()$")
     78     (non-graphical-output . ""))
     79   "The final Maxima code executed in a source block.
     80 An alist with the epilogue for graphical and non-graphical
     81 output.  See `org-babel-maxima-expand'.")
     82 
     83 (defun org-babel-maxima-expand (body params)
     84   "Expand Maxima BODY according to its header arguments from PARAMS."
     85   (let* ((vars (org-babel--get-vars params))
     86          (graphic-file (ignore-errors (org-babel-graphical-output-file params)))
     87 	 (epilogue (cdr (assq :epilogue params)))
     88 	 (prologue (cdr (assq :prologue params))))
     89     (mapconcat 'identity
     90                (delq nil
     91 	             (list
     92 		      ;; Any code from the specified prologue at the start.
     93 		      prologue
     94 		      ;; graphic output
     95 		      (if graphic-file
     96                           (let* ((graphics-pkg (intern (or (cdr (assq :graphics-pkg params)) "plot")))
     97                                  (graphic-format-string (cdr (assq graphics-pkg org-babel-maxima--graphic-package-options)))
     98                                  (graphic-terminal (file-name-extension graphic-file))
     99                                  (graphic-file (if (eq graphics-pkg 'plot) graphic-file (file-name-sans-extension graphic-file))))
    100                             (format graphic-format-string graphic-terminal graphic-file)))
    101 		      ;; variables
    102 		      (mapconcat 'org-babel-maxima-var-to-maxima vars "\n")
    103 		      ;; body
    104 		      body
    105 		      ;; Any code from the specified epilogue at the end.
    106 		      epilogue
    107 		      (if graphic-file
    108                           (cdr (assq :graphical-output org-babel-maxima--default-epilogue))
    109                         (cdr (assq :non-graphical-output org-babel-maxima--default-epilogue)))))
    110 	       "\n")))
    111 
    112 (defvar org-babel-maxima--output-filter-regexps
    113   '("batch"                     ;; remove the `batch' or `batchload' line
    114     "^rat: replaced .*$"        ;; remove notices from `rat'
    115     "^;;; Loading #P"           ;; remove notices from the lisp implementation
    116     "^read and interpret"       ;; remove notice from `batch'
    117     "^(%\\([i]-?[0-9]+\\))[ ]$" ;; remove empty input lines from `batch'-ing
    118     )
    119   "Regexps to remove extraneous lines from Maxima's output.
    120 See `org-babel-maxima--output-filter'.")
    121 
    122 (defun org-babel-maxima--output-filter (line)
    123   "Filter empty or undesired lines from Maxima output.
    124 Return nil if LINE is zero-length or it matches a regexp in
    125 `org-babel-maxima--output-filter'; otherwise, return LINE."
    126   (unless (or (= 0 (length line))
    127               (cl-some #'(lambda(r) (string-match r line))
    128                        org-babel-maxima--output-filter-regexps))
    129     line))
    130 
    131 (defun org-babel-execute:maxima (body params)
    132   "Execute Maxima BODY according to PARAMS.
    133 This function is called by `org-babel-execute-src-block'."
    134   (unless noninteractive (message "Executing Maxima source code block"))
    135   (let ((result-params (split-string (or (cdr (assq :results params)) "")))
    136 	(result
    137 	 (let* ((cmdline (or (cdr (assq :cmdline params)) ""))
    138                 (batch/load (or (cdr (assq :batch params)) "batchload"))
    139                 (cmdline (if (or (equal cmdline "") (equal batch/load "batchload"))
    140                              ;; legacy behavior:
    141                              ;; ensure that --very-quiet is on command-line by default
    142                              (concat cmdline " " org-babel-maxima--command-arguments-default)
    143                            ;; if using an alternate loader, :cmdline overwrites default
    144                            cmdline))
    145 		(in-file (org-babel-temp-file "maxima-" ".max"))
    146                 (cmd (format "%s -r %s %s"
    147 			     org-babel-maxima-command
    148                              (shell-quote-argument
    149                               ;; bind linenum to 0 so the first line
    150                               ;; of in-file has line number 1
    151                               (format "(linenum:0, %s(%S))$" batch/load in-file))
    152                              cmdline)))
    153 	   (with-temp-file in-file (insert (org-babel-maxima-expand body params)))
    154 	   (unless noninteractive (message cmd))
    155            ;; " | grep -v batch | grep -v 'replaced' | sed '/^$/d' "
    156 	   (let ((raw (org-babel-eval cmd "")))
    157              (mapconcat
    158               #'identity
    159               (delq nil
    160                     (mapcar #'org-babel-maxima--output-filter
    161                             (split-string raw "[\r\n]"))) "\n")))))
    162     (if (ignore-errors (org-babel-graphical-output-file params))
    163 	nil
    164       (org-babel-result-cond result-params
    165 	result
    166 	(let ((tmp-file (org-babel-temp-file "maxima-res-")))
    167 	  (with-temp-file tmp-file (insert result))
    168 	  (org-babel-import-elisp-from-file tmp-file))))))
    169 
    170 
    171 (defun org-babel-prep-session:maxima (_session _params)
    172 "Throw an error.  Maxima does not support sessions."
    173   (error "Maxima does not support sessions"))
    174 
    175 (defun org-babel-maxima-var-to-maxima (pair)
    176   "Convert an elisp variable-value PAIR to maxima code."
    177   (let ((var (car pair))
    178         (val (cdr pair)))
    179     (when (symbolp val)
    180       (setq val (symbol-name val))
    181       (when (= (length val) 1)
    182         (setq val (string-to-char val))))
    183     (format "%S: %s$" var
    184 	    (org-babel-maxima-elisp-to-maxima val))))
    185 
    186 (defun org-babel-maxima-elisp-to-maxima (val)
    187   "Return a string of maxima code which evaluates to VAL."
    188   (if (listp val)
    189       (concat "[" (mapconcat #'org-babel-maxima-elisp-to-maxima val ", ") "]")
    190     (format "%s" val)))
    191 
    192 (provide 'ob-maxima)
    193 
    194 ;;; ob-maxima.el ends here