Ihor Radchenko <yanta...@posteo.net> writes: > See a couple of suggestions in the attached diff.
Incorporated. I included your error condition in case no output type is specified, but added a comment that it should never happen (default png is set if no other type is specified). >>> I am wondering if it makes sense to pass arbitrary encoding >>> here. AFAIU, the encoding specifies input encoding and that's what >>> Org mode controls, not user. In fact, we can even explicitly >>> specific utf-8 in (with-temp-file in-file (insert body)) by >>> let-binding `coding-system-for-write' around. I suspect that users >>> will never use :encoding parameter and if they do, they will run >>> into problems as they can't easily control the encoding ob-ditaa >>> uses to write the file. (Is it even useful to have custom encoding?) >> >> Good question, I have never used it. >> >> The current version specifies encoding via :java in default header args, >> so it is possible for the user to change it. I wanted to provide the >> same functionality, but instead of java pass encoding directly to ditaa >> so that it would be available regardless of whether ditaa is run via the >> ditaa executable or java and jar. >> >> Let me know if you want this functionality to be changed. > > IMHO, the right thing to do will be > 1. Forcing utf-8 when saving the temporary ditaa input file > 2. Passing UTF-8 as default encoding to ditaa > > I see no reason why users would need to change this setting. Agreed. Implemented now, except I used set-buffer-file-coding-system in the body of with-temp-file, which seems to accomplish the same thing (as let'ing coding-system-for-write). New patch version below. All the best, Jarmo
>From 2241d9d86233bc13f8989747285d403de52dcfb9 Mon Sep 17 00:00:00 2001 From: Jarmo Hurri <jarmo.hu...@iki.fi> Date: Sat, 16 Aug 2025 14:35:45 +0300 Subject: [PATCH] ob-ditaa.el: ditaa executable, SVG output, and output type control * lisp/ob-ditaa.el (org-babel-default-header-args:ditaa) Add graphics to default value of :results. Add png as default value of header arg :file-ext. (org-ditaa-default-exec-mode): Define new customizable variable for controlling ditaa execution via jar or executable. (org-ditaa-exec): Define new customizable variable for controlling path to ditaa executable. (org-ditaa-java-exec): Rename old customizable variable to conform to ditaa variable naming (not containing word babel). Provide an obsolete alias for backwards-compatibility. (org-ditaa--ensure-jar-file): Write a small helper function checking existence of jar file. (org-babel-execute:ditaa): Use standard `org-babel-graphical-output-file' to determine output file and type. Add support for ditaa executable. Add support for SVG output. Clarify code structure and local variable naming. Provide backwards-compatibility for :eps and :pdf header arguments. * doc/org-manual.org (List of contributors): Remove reference to non-existing location of ditaa.jar in org contrib, refer to ditaa github page instead. * etc/ORG-NEWS: Document new features, new options and renamed variable. There was a mismatch between what ob-ditaa expected and what some operating systems provide. In particular, ob-ditaa expected a JAR executable via java -jar, while some operating systems provide a shell script which executes the JAR in a more complicated manner. Therefore support for executing ditaa source code blocks directly via an executable was added. Newer versions of ditaa can generate SVG output, which was not supported by ob-ditaa. This is now fixed. Output type is deduced automatically, and defaults to PNG. Legacy output-type controlling header arguments :eps and :pdf are still there for backwards-compatibility, and override output type determination from file type. --- doc/org-manual.org | 3 +- etc/ORG-NEWS | 23 ++++++ lisp/ob-ditaa.el | 179 +++++++++++++++++++++++++++++++-------------- 3 files changed, 151 insertions(+), 54 deletions(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index 5a4045271..f178b7416 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -23275,7 +23275,8 @@ community and the code. literal examples, and remote highlighting for referenced code lines. - Stathis Sideris wrote the =ditaa.jar= ASCII to PNG converter that is - now packaged into the [[https://git.sr.ht/~bzg/org-contrib][org-contrib]] repository. + available as a package in some operating systems or can be + downloaded from [[https://github.com/stathissideris/ditaa]]. - Daniel Sinder came up with the idea of internal archiving by locking subtrees. diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 1f7cb2cbc..29070a833 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -239,6 +239,15 @@ appropriate major mode is unavailable. When editing Dot source blocks, Org now uses Graphviz Dot mode, if installed. +*** =ob-ditaa=: ditaa executable, and SVG output + +In order to use a ditaa executable instead of a JAR file, you can set +=org-ditaa-default-exec-mode= to ='ditaa=. The location of the +executable can be configured via =org-ditaa-exec=. + +SVG output can now be generated; note, however, that this requires a +ditaa version of at least 0.11.0. + ** New and changed options # Changes dealing with changing default values of customizations, @@ -406,6 +415,13 @@ symbol ~attach~ or a string -- directory name. Now it can also be a function, which will be called with no arguments and its return value will be used as a directory to save the image to. +*** =ob-ditaa=: output type control + +Output file type is determined as specified in Babel documentation: +the suffix of =:file= is the primary determinant, and =:file-ext= +secondary. Header arguments =:pdf= and =:eps= are supported for +backwards compatibility. Default output type is still PNG. + ** New functions and changes in function arguments # This also includes changes in function behavior from Elisp perspective. @@ -540,6 +556,13 @@ capture ~:tree-type~ options]], the internal variable ~org-datetree-base-level~ has been removed, as well as the undocumented helper function ~org-datetree-insert-line~. +*** =ob-ditaa=: new name for variable controlling java + +To align with other customizable variable names, which do not contain +the word =babel=, variable =org-babel-ditaa-java-cmd= has been renamed +to =org-ditaa-java-exec=. The old variable =org-babel-ditaa-java-cmd= +is still available as an obsolete alias. + ** Miscellaneous *** ~org-capture~ target pointing to headline is now handled uniformly for =plain= entry type diff --git a/lisp/ob-ditaa.el b/lisp/ob-ditaa.el index 77eadd6c2..744c50d30 100644 --- a/lisp/ob-ditaa.el +++ b/lisp/ob-ditaa.el @@ -2,7 +2,7 @@ ;; Copyright (C) 2009-2025 Free Software Foundation, Inc. -;; Author: Eric Schulte +;; Authors: Eric Schulte, Jarmo Hurri ;; Keywords: literate programming, reproducible research ;; URL: https://orgmode.org @@ -25,15 +25,52 @@ ;; Org-Babel support for evaluating ditaa source code. ;; -;; This differs from most standard languages in that +;; Source code blocks of type ditaa have some special features: ;; -;; 1) there is no such thing as a "session" in ditaa +;; - there is no such thing as a "session" ;; -;; 2) we are generally only going to return results of type "file" +;; - :export results is the default ;; -;; 3) we are adding the "file" and "cmdline" header arguments +;; - only results of type "file" are returned ;; -;; 4) there are no variables (at least for now) +;; - there are no variables +;; +;; - three different variants of "ditaa" exist: a ditaa executable +;; (shell script), ditaa.jar Java archive and DitaaEPS.jar Java +;; archive; the third one is a fork generating eps output, and is +;; also a prerequisite for producing pdf output; ob-ditaa supports +;; all three of these; if ditaa.jar or DitaaEPS.jar is used, paths +;; to file(s) must be set; the following table summarizes which +;; variant is used in which case; column mode refers to +;; `org-ditaa-default-exec-mode' +;; +;; | mode | output | command | +;; |----------------+----------+-----------------------------------------------------| +;; | `ditaa' | png, svg | `org-ditaa-exec' | +;; | `jar' | png, svg | `org-ditaa-java-exec' -jar `org-ditaa-jar-path' | +;; | `ditaa', `jar' | eps | `org-ditaa-java-exec' -jar `org-ditaa-eps-jar-path' | +;; | `ditaa', `jar' | pdf | `org-ditaa-java-exec' -jar `org-ditaa-eps-jar-path' | +;; +;; - standard header argument "cmdline" controls command line parameters passed to ditaa +;; - the following header arguments are added: +;; "java" : additional parameters passed to java if ditaa run via a jar +;; + +;;; Requirements: + +;; at least one of the following: +;; +;; ditaa (executable) +;; - packaged in some distributions +;; - configurable via `org-ditaa-exec' +;; +;; ditaa.jar | when exec mode is `jar' +;; - `org-ditaa-jar-path' must point to this jar file +;; - see https://github.com/stathissideris/ditaa +;; +;; DitaaEps.jar | when generating eps or pdf output +;; - `org-ditaa-eps-jar-path' must point to this jar file +;; - see https://sourceforge.net/projects/ditaa-addons/files/DitaaEps/ ;;; Code: @@ -44,11 +81,36 @@ (require 'org-compat) (defvar org-babel-default-header-args:ditaa - '((:results . "file") + '((:results . "file graphics") (:exports . "results") - (:java . "-Dfile.encoding=UTF-8")) + (:file-ext . "png")) "Default arguments for evaluating a ditaa source block.") +(defcustom org-ditaa-default-exec-mode 'jar + "Method to use for ditaa diagram generation when generating png or svg output. +`jar' means to use java together with a JAR. +The JAR must be set via `org-ditaa-jar-path'. + +`ditaa' means to use the ditaa executable. +The executable can be configured via `org-ditaa-exec'." + + :group 'org-babel + :package-version '(Org . "9.8") + :type '(choice (const :tag "Use java together with a JAR file." jar) + (const :tag "Use ditaa executable." ditaa))) + +(defcustom org-ditaa-exec "ditaa" + "File name of the ditaa executable." + :group 'org-babel + :package-version '(Org . "9.8") + :type 'string) + +(define-obsolete-variable-alias 'org-babel-ditaa-java-cmd 'org-ditaa-java-exec "9.8") +(defcustom org-ditaa-java-exec "java" + "Java executable to use when evaluating ditaa blocks using a JAR." + :group 'org-babel + :type 'string) + (defcustom org-ditaa-jar-path (expand-file-name "ditaa.jar" (file-name-as-directory @@ -58,64 +120,75 @@ (expand-file-name "../contrib" (file-name-directory (org-find-library-dir "org"))))))) - "Path to the ditaa jar executable." - :group 'org-babel - :type 'string) - -(defcustom org-babel-ditaa-java-cmd "java" - "Java executable to use when evaluating ditaa blocks." + "Path to the ditaa.jar file." :group 'org-babel :type 'string) (defcustom org-ditaa-eps-jar-path (expand-file-name "DitaaEps.jar" (file-name-directory org-ditaa-jar-path)) - "Path to the DitaaEps.jar executable." + "Path to the DitaaEps.jar executable. +Used when generating eps or pdf output." :group 'org-babel :version "24.4" :package-version '(Org . "8.0") :type 'string) -(defcustom org-ditaa-jar-option "-jar" - "Option for the ditaa jar file. -Do not leave leading or trailing spaces in this string." - :group 'org-babel - :version "24.1" - :type 'string) +(defun ob-ditaa--ensure-jar-file (file) + "Return FILE if it exists, signal error otherwise." + (if (file-exists-p file) + file + (error "(ob-ditaa) Could not find jar file %s" file))) (defun org-babel-execute:ditaa (body params) - "Execute BODY of Ditaa code with org-babel according to PARAMS. + "Execute BODY of ditaa code with org-babel according to PARAMS. This function is called by `org-babel-execute-src-block'." - (let* ((out-file (or (cdr (assq :file params)) - (error - "Ditaa code block requires :file header argument"))) - (cmdline (cdr (assq :cmdline params))) - (java (cdr (assq :java params))) - (in-file (org-babel-temp-file "ditaa-")) - (eps (cdr (assq :eps params))) - (eps-file (when eps - (org-babel-process-file-name (concat in-file ".eps")))) - (pdf-cmd (when (and (or (string= (file-name-extension out-file) "pdf") - (cdr (assq :pdf params)))) - (concat - "epstopdf" - " " eps-file - " -o=" (org-babel-process-file-name out-file)))) - (cmd (concat org-babel-ditaa-java-cmd - " " java " " org-ditaa-jar-option " " - (shell-quote-argument - (expand-file-name - (if eps org-ditaa-eps-jar-path org-ditaa-jar-path))) - " " cmdline - " " (org-babel-process-file-name in-file) - " " (if pdf-cmd - eps-file - (org-babel-process-file-name out-file))))) - (unless (file-exists-p org-ditaa-jar-path) - (error "Could not find ditaa.jar at %s" org-ditaa-jar-path)) - (with-temp-file in-file (insert body)) - (shell-command cmd) - (when pdf-cmd (shell-command pdf-cmd)) - nil)) ;; signal that output has already been written to file + (let* ((out-file (org-babel-graphical-output-file params)) + (out-file-suffix (file-name-extension out-file)) + ;; backwards-compatibility of :eps and :pdf header arguments + ;; notice that these take precedence over file type (suffix) + (legacy-eps (cdr (assq :eps params))) + (legacy-pdf (cdr (assq :pdf params)))) + (when (and legacy-eps legacy-pdf) + (error "(ob-ditaa) Both :eps and :pdf legacy output types specified")) + (let* ((legacy-output-type (or legacy-eps legacy-pdf)) + (eps (or legacy-eps (string= out-file-suffix "eps"))) + (pdf (or legacy-pdf (string= out-file-suffix "pdf"))) + (svg (and (not legacy-output-type) (string= out-file-suffix "svg"))) + (png (and (not legacy-output-type) + (or (string= out-file-suffix "png") + (not (or svg pdf eps))))) ;; default output type is png + (ditaa-options (cdr (assq :cmdline params))) + (java-options (cdr (assq :java params))) + (use-eps-jar (or eps pdf)) + (exec-form (if (or (equal org-ditaa-default-exec-mode 'jar) use-eps-jar) + (concat org-ditaa-java-exec + (when java-options (concat " " java-options)) + " " "-jar" " " + (shell-quote-argument + (ob-ditaa--ensure-jar-file (if use-eps-jar org-ditaa-eps-jar-path + org-ditaa-jar-path)))) + org-ditaa-exec)) + (in-file (org-babel-temp-file "ditaa-")) + (ditaa-out-file (org-babel-process-file-name (if pdf (concat in-file ".eps") out-file))) + (ditaa-coding-system 'utf-8) + (cmd (concat exec-form + (when ditaa-options (concat " " ditaa-options)) + (when svg (concat " " "--svg")) + " " "-e" " " (symbol-name ditaa-coding-system) + " " in-file " " ditaa-out-file))) + ;; verify that output file type is specified - note that this + ;; error should in fact never happen, since default png type is + ;; set above if no other supported type is specified + (unless (or eps pdf svg png) + (error (concat "(ob-ditaa) Unknown output file extension: " out-file-suffix))) + (with-temp-file in-file + (set-buffer-file-coding-system ditaa-coding-system) + (insert body)) + (shell-command cmd) + (when pdf + (shell-command (concat "epstopdf" " " ditaa-out-file " " + "-o=" (org-babel-process-file-name out-file)))) + nil))) ;; signal that output has already been written to file (defun org-babel-prep-session:ditaa (_session _params) "Return an error because ditaa does not support sessions." -- 2.50.1