Greetings again.

Patch version 6 below, with changes as discussed here.

I tried to also improve changelog by assigning all changes -
e.g. obsolete variable - to some function.

I have a test file I run through to try to make sure the features work
as expected. I should probably turn it into a test file within org
itself at some point.

(I can feel a request for version 7 in the horizon; at least I am
learning new things, like dealing with git-am patching when the previous
patch version no longer works.)

All the best,

Jarmo

>From c8f57fd313b11cad402a580541f6cb4a209efd45 Mon Sep 17 00:00:00 2001
From: Jarmo Hurri <[email protected]>
Date: Sun, 2 Nov 2025 13:58:41 +0200
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--ensure-jar-file): Write a small helper function checking
existence of jar file.
(org-babel-execute:ditaa): Add support for ditaa executable.  Add
support for SVG output.  Define new customizable variable
'org-ditaa-default-exec-mode' for controlling ditaa execution via jar
or executable.  Define new customizable variable 'org-ditaa-exec' for
controlling path to ditaa executable.  Rename old customizable
variable 'org-babel-ditaa-java-cmd' to 'org-ditaa-java-exec' to
conform to ditaa variable naming (not containing word babel); provide
an obsolete alias for backwards-compatibility.  Use standard
`org-babel-graphical-output-file' to determine output file and type.
Clarify code structure and local variable naming.  Provide
backwards-compatibility for :eps and :pdf header arguments.  Make
'org-ditaa-jar-option' obsolete.
* 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, renamed variable
and obsolete 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       |  27 +++++++
 lisp/ob-ditaa.el   | 186 ++++++++++++++++++++++++++++++++-------------
 3 files changed, 162 insertions(+), 54 deletions(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index ff5a569d4..02763f4ec 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -23276,7 +23276,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 df8060a33..db5f3f927 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -256,6 +256,15 @@ When editing Dot source blocks, Org now uses Graphviz Dot mode, if installed.
 
 Org now officially enables C# code block evaluation based on the .NET SDK.
 
+*** =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,
@@ -431,6 +440,13 @@ considered.  For example, setting ~org-refile-targets~ to ~((nil
 . t))~ will allow one to refile to any heading within the current
 buffer.
 
+*** =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.
@@ -582,6 +598,17 @@ 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=: =org-babel-ditaa-java-cmd= renamed and =org-ditaa-jar-option= made obsolete
+
+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.
+
+Variable =org-ditaa-jar-option= did not serve any sensible purpose and
+has been made obsolete. Its value is still used in place of default
+parameter -jar if the variable is defined.
+
 ** Miscellaneous
 *** Inline tasks in a clocktable will be indented to a level below their heading
 
diff --git a/lisp/ob-ditaa.el b/lisp/ob-ditaa.el
index 77eadd6c2..8b6c660b5 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
+;;
+;; - 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
 ;;
-;; 4) there are no variables (at least for now)
+
+;;; 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,82 @@
 				  (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)
+(make-obsolete-variable 'org-ditaa-jar-option
+                        "(ob-ditaa) variable org-ditaa-jar-option is obsolete"
+                        "9.8")
+
+(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))
+                                  " "
+                                  ;; use obsolete variable instead of default param if defined
+                                  (if (boundp 'org-ditaa-jar-option) org-ditaa-jar-option "-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.51.1

Reply via email to