From: Leo Butler <Leo.Butler@umanitoba.ca>
To: Ihor Radchenko <yantar92@posteo.net>
Cc: Bastien <bzg@gnu.org>,
Lockywolf <for_org-bugs_2023-09-01@lockywolf.net>,
"emacs-orgmode@gnu.org" <emacs-orgmode@gnu.org>
Subject: [PATCH] ob-maxima.el, etc. (was Re: [MAINTENANCE] On how much we can expose internals into defcustom)
Date: Tue, 12 Sep 2023 21:09:03 +0000 [thread overview]
Message-ID: <87y1hb5cb4.fsf_-_@t14.reltub.ca> (raw)
In-Reply-To: <87ledinrl5.fsf@localhost> (Ihor Radchenko's message of "Thu, 07 Sep 2023 11:35:50 +0000")
[-- Attachment #1: Type: text/plain, Size: 3012 bytes --]
On Thu, Sep 07 2023, Ihor Radchenko <yantar92@posteo.net> wrote:
> `org-babel-execute:maxima' relies on certain output that maxima
> produces. Removing --very-quiet will make the assumptions in the code no
> longer valid. Worse - it might happen that in the absence of --very-quiet
> `org-babel-execute:maxima' (or its future code) will work _almost_
> correctly, with problems going unnoticed to the user.
>
> If we want to support use-case when --very-quiet is absent, we need to
> explicitly change `org-babel-execute:maxima' to account for it,
> maintaining this support forever.
>
> Either way, it will be an extra maintenance burden, which must be
> justified.
>
> The baseline is - we cannot put the burden of wrongly changing
> customization onto the user. Because the user may or may not notice
> them problem, especially when it is subtle and requires good knowledge
> of the Elisp code in ob-maxima.
>
> Of course, the above statement is not 100% strict. If you describe cases
> when customization is necessary for certain valid use cases, we may
> still put in such dangerous customization with all the appropriate
> warnings in the docstring. But it should be justified.
>
>>> So, leaving essential settings customizeable is not necessarily a good idea.
>>
>> I understand your hesitation about full-blown customization using
>> `defcustom'. However, I would still like to have more dials to turn.
>>
>> Perhaps we could add header arguments to get the desired customization?
>
> Header arguments are generally better, because they provide more
> fine-grained control compared to global customization.
>
>> E.g.
>>
>> - :batch :: Control how the Maxima source is evaluated by Maxima.
>> 1. Default. If nil or no, then use batchload with the --very-quiet
>> command-line flag.
>> 2. If t or yes, then use batch with the --quiet command-line flag;
>
> Is there a place where I can see the differences between batch and batchload?
>
>> - :plot-engine :: Set the plotting package.
>> 1. Default. If nil or no, the use `plot';
>> 2. If `draw', then use `draw'.
>
> Sounds reasonable.
>
>> - Similarly, we could do something like ob-R.el does, and construct the
>> graphics instructions using some additional header arguments and
>> grovelling the terminal from the filename (see
>> org-babel-R-construct-graphics-device-call).
>>
>> My sense is that this would be more in keeping with how other ob-*.el
>> packages do things.
>
> Yes.
Attached is a patch that tries to address some of Ihor's concerns. I
have added two header arguments for maxima src blocks:
- :graphics-pkg lets the user choose the graphics package to use;
- :batch lets the user choose which source-code loader Maxima will use.
I have also moved two defaults, that were embedded in the code, to
`defvar' forms.
I have added tests in test-ob-maxima.el and in ob-maxima-test.org to
demonstrate the use of these header arguments.
Leo
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-On-ltb-ob-max-ob-maxima.el-add-headers-and-custs.patch --]
[-- Type: text/x-diff; name="0001-On-ltb-ob-max-ob-maxima.el-add-headers-and-custs.patch", Size: 8185 bytes --]
diff --git a/lisp/ob-maxima.el b/lisp/ob-maxima.el
index d1d7c7424..ab166bfd4 100644
--- a/lisp/ob-maxima.el
+++ b/lisp/ob-maxima.el
@@ -48,29 +48,44 @@
:group 'org-babel
:type 'string)
+(defvar org-babel-maxima-command-arguments
+ "--very-quiet"
+ "A string containing the command-line arguments used when calling the Maxima executable. See `org-babel-maxima-command', `org-babel-maxima-batch/load' and `org-babel-execute:maxima'.")
+
+(defvar org-babel-maxima-graphic-package-options
+ '((plot . "(set_plot_option ('[gnuplot_term, %s]), set_plot_option ('[gnuplot_out_file, %S]))$")
+ (draw . "(load(draw), set_draw_defaults(terminal='%s,file_name=%S))$"))
+ "An alist, each element of the form (PACKAGE-NAME . FORMAT-STRING). The format string contains the Maxima code to set the graphic file terminal and name. It must contain `%s' to set the terminal and `%S' to set the filename. The default package is `plot'. See `org-babel-maxima-expand'.")
+
+(defvar org-babel-maxima-default-epilogue
+ "gnuplot_close ()$"
+ "A string with the final Maxima code executed. See `org-babel-maxima-expand'.")
+
(defun org-babel-maxima-expand (body params)
"Expand a block of Maxima code according to its header arguments."
- (let ((vars (org-babel--get-vars params))
- (epilogue (cdr (assq :epilogue params)))
- (prologue (cdr (assq :prologue params))))
+ (let* ((vars (org-babel--get-vars params))
+ (graphic-file (ignore-errors (org-babel-graphical-output-file params)))
+ (epilogue (cdr (assq :epilogue params)))
+ (prologue (cdr (assq :prologue params))))
(mapconcat 'identity
- (list
- ;; Any code from the specified prologue at the start.
- prologue
- ;; graphic output
- (let ((graphic-file (ignore-errors (org-babel-graphical-output-file params))))
- (if graphic-file
- (format
- "set_plot_option ([gnuplot_term, png]); set_plot_option ([gnuplot_out_file, %S]);"
- graphic-file)
- ""))
- ;; variables
- (mapconcat 'org-babel-maxima-var-to-maxima vars "\n")
- ;; body
- body
- ;; Any code from the specified epilogue at the end.
- epilogue
- "gnuplot_close ()$")
+ (delq nil
+ (list
+ ;; Any code from the specified prologue at the start.
+ prologue
+ ;; graphic output
+ (if graphic-file
+ (let ((graphics-pkg (intern (or (cdr (assq :graphics-pkg params)) "plot")))
+ (graphic-format-string (cdr (assq graphics-pkg org-babel-maxima-graphic-package-options)))
+ (graphic-terminal (file-name-extension graphic-file))
+ (graphic-file (if (eq graphics-pkg 'plot) graphic-file (file-name-sans-extension graphic-file))))
+ (format graphic-format-string graphic-terminal graphic-file)))
+ ;; variables
+ (mapconcat 'org-babel-maxima-var-to-maxima vars "\n")
+ ;; body
+ body
+ ;; Any code from the specified epilogue at the end.
+ epilogue
+ (if graphic-file org-babel-maxima-default-epilogue)))
"\n")))
(defun org-babel-execute:maxima (body params)
@@ -80,11 +95,18 @@ This function is called by `org-babel-execute-src-block'."
(let ((result-params (split-string (or (cdr (assq :results params)) "")))
(result
(let* ((cmdline (or (cdr (assq :cmdline params)) ""))
+ (batch/load (or (cdr (assq :batch params)) "batchload"))
+ (cmdline (if (or (equal cmdline "") (equal batch/load "batchload"))
+ ;; legacy behaviour:
+ ;; ensure that --very-quiet is on command-line by default
+ (concat cmdline " " org-babel-maxima-command-arguments)
+ ;; if using an alternate loader, :cmdline overwrites default
+ cmdline))
(in-file (org-babel-temp-file "maxima-" ".max"))
- (cmd (format "%s --very-quiet -r %s %s"
+ (cmd (format "%s -r %s %s"
org-babel-maxima-command
(shell-quote-argument
- (format "batchload(%S)$" in-file))
+ (format "(linenum:0, %s(%S))$" batch/load in-file))
cmdline)))
(with-temp-file in-file (insert (org-babel-maxima-expand body params)))
(message cmd)
@@ -97,6 +119,8 @@ This function is called by `org-babel-execute-src-block'."
(unless (or (string-match "batch" line)
(string-match "^rat: replaced .*$" line)
(string-match "^;;; Loading #P" line)
+ (string-match "^read and interpret" line)
+ (string-match "^(%\\([io]-?[0-9]+\\))[ ]+$" line)
(= 0 (length line)))
line))
(split-string raw "[\r\n]"))) "\n")))))
diff --git a/testing/examples/ob-maxima-test.org b/testing/examples/ob-maxima-test.org
index b83114a4f..2b88a65a5 100644
--- a/testing/examples/ob-maxima-test.org
+++ b/testing/examples/ob-maxima-test.org
@@ -23,6 +23,13 @@ plot2d(sin(a*x), [x, 0, 2*%pi])$
#+begin_src maxima :results graphics :file maxima-test-3d.png
plot3d (2^(-u^2 + v^2), [u, -3, 3], [v, -2, 2])$
#+end_src
+
+** Use the ~draw~ package
+This test exercises the ~:graphics-pkg~ header argument.
+#+begin_src maxima :var a=0.5 :results graphics file :file maxima-test-cos.png :graphics-pkg draw
+draw2d(explicit(cos(a*x), x, -%pi, %pi))$
+#+end_src
+
* Output to a file
Output to a file
#+begin_src maxima :file maxima-test-ouput.out
@@ -89,3 +96,18 @@ tex(ratsimp(diff(%e^(a*x), x)));
#+BEGIN_LaTeX
$$a\,e^{a\,x}$$
#+END_LaTeX
+
+* Batch
+Exercise the ~:batch~ header argument. These tests are also defined in ~testing/lisp/test-ob-maxima.el~. The test name is name of the ~ert~ test.
+
+#+name: ob-maxima/batch+verbatim
+#+begin_src maxima :exports both :results verbatim :batch batch
+(assume(z>0),
+integrate(exp(-t)*t^z, t, 0, inf));
+#+end_src
+
+#+name: ob-maxima/batch+verbatim+quiet
+#+begin_src maxima :exports both :results verbatim :batch batch :cmdline --quiet
+(assume(z>0),
+integrate(exp(-t)*t^z, t, 0, inf));
+#+end_src
diff --git a/testing/lisp/test-ob-maxima.el b/testing/lisp/test-ob-maxima.el
index e2433d232..1f6a1737a 100644
--- a/testing/lisp/test-ob-maxima.el
+++ b/testing/lisp/test-ob-maxima.el
@@ -69,6 +69,28 @@
(equal
'((1 2 3) (2 3 4) (3 4 5)) (org-babel-execute-src-block)))))
+(ert-deftest ob-maxima/batch+verbatim ()
+ "Exercise the `:batch' header argument: use Maxima `batch' command to execute src block. Since `--very-quiet' is set on command-line, the ground input and formatted output are printed (without input/output labels)."
+ (unwind-protect
+ (org-test-with-temp-text
+ (format "#+begin_src maxima :results verbatim :batch batch
+(assume(z>0),
+integrate(exp(-t)*t^z, t, 0, inf));
+#+end_src")
+ (should (equal (org-babel-execute-src-block)
+ "(assume(z > 0),integrate(exp(-t)*t^z,t,0,inf))\n gamma(z + 1)")))))
+
+(ert-deftest ob-maxima/batch+verbatim+quiet ()
+ "Exercise the `:batch' header argument: use Maxima `batch' command to execute src block. Since `--quiet' is set by `:cmdline' header, the ground input and formatted output are printed with input/output labels."
+ (unwind-protect
+ (org-test-with-temp-text
+ (format "#+begin_src maxima :results verbatim :batch batch :cmdline --quiet
+(assume(z>0),
+integrate(exp(-t)*t^z, t, 0, inf));
+#+end_src")
+ (should (equal (org-babel-execute-src-block)
+ "(%i1) (assume(z > 0),integrate(exp(-t)*t^z,t,0,inf))\n(%o1) gamma(z + 1)")))))
+
(provide 'test-ob-maxima)
;;; test-ob-maxima.el ends here
next prev parent reply other threads:[~2023-09-12 21:10 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-01 4:35 [BUG] Consider replacing bachload with batch in ob-maxima. [9.6.6 (release_9.6.6 @ /usr/share/emacs/30.0.50/lisp/org/)] Lockywolf
2023-09-01 18:33 ` Leo Butler
2023-09-02 7:19 ` Ihor Radchenko
2023-09-02 18:12 ` Leo Butler
2023-09-05 10:57 ` [MAINTENANCE] On how much we can expose internals into defcustom (was: [BUG] Consider replacing bachload with batch in ob-maxima. [9.6.6 (release_9.6.6 @ /usr/share/emacs/30.0.50/lisp/org/)]) Ihor Radchenko
2023-09-06 19:39 ` [MAINTENANCE] On how much we can expose internals into defcustom Leo Butler
2023-09-07 11:35 ` Ihor Radchenko
2023-09-12 21:09 ` Leo Butler [this message]
2023-09-15 9:41 ` [PATCH] ob-maxima.el, etc. (was Re: [MAINTENANCE] On how much we can expose internals into defcustom) Ihor Radchenko
2023-09-15 15:13 ` Leo Butler
2023-09-16 9:04 ` Ihor Radchenko
2023-09-19 19:25 ` Leo Butler
2023-09-20 9:17 ` Ihor Radchenko
2023-09-20 15:02 ` Leo Butler
2023-09-21 9:18 ` Ihor Radchenko
2023-09-21 14:03 ` Leo Butler
2023-09-22 9:43 ` Ihor Radchenko
2023-10-02 16:01 ` Leo Butler
2023-10-04 8:38 ` Ihor Radchenko
2023-10-04 13:07 ` Leo Butler
2023-09-02 7:06 ` [BUG] Consider replacing bachload with batch in ob-maxima. [9.6.6 (release_9.6.6 @ /usr/share/emacs/30.0.50/lisp/org/)] Ihor Radchenko
2023-09-02 18:20 ` Leo Butler
2023-09-03 5:25 ` Vladimir Nikishkin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.orgmode.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87y1hb5cb4.fsf_-_@t14.reltub.ca \
--to=leo.butler@umanitoba.ca \
--cc=bzg@gnu.org \
--cc=emacs-orgmode@gnu.org \
--cc=for_org-bugs_2023-09-01@lockywolf.net \
--cc=yantar92@posteo.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).