Hello again.

I noticed a minor error (in the definition of the obsolete variable) in
my 2nd version of the patch. Hopefully the one below is closer to
perfection.

All the best,

Jarmo

>From 690c4370c63d375fb4dbeb67063611b222fda39b Mon Sep 17 00:00:00 2001
From: Jarmo Hurri <jarmo.hu...@iki.fi>
Date: Fri, 1 Aug 2025 14:21:03 +0300
Subject: [PATCH] * lisp/ob-ditaa.el (org-babel-default-header-args:ditaa)
 Include new header arg `:encoding`. (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 old
 variable as an obsolete alias. (org-ditaa-ensure-jar-file): Write a small
 helper function checking existence of jar file. (org-babel-execute:ditaa):
 Determine output file type correctly from header arguments. Add support for
 ditaa executable. Add support for SVG output. * 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 (=ob-ditaa=:
 output type control, ditaa executable, SVG output, and chararacter encoding):
 Document breaking change and new features.

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 now deduced correctly as specified in Babel documentation (from header arguments `:file` or `:file-ext`).

Character encoding of ditaa source code blocks was passed via Java, while the encoding can be specified directly as a parameter to ditaa. Character encoding is now passed directly to ditaa, with a corresponding header argument `:encoding`.
---
 doc/org-manual.org |   3 +-
 etc/ORG-NEWS       |  22 ++++++
 lisp/ob-ditaa.el   | 165 +++++++++++++++++++++++++++++++--------------
 3 files changed, 138 insertions(+), 52 deletions(-)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index e4be10a3b..460b8be59 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.
+  that is 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 5b5908629..41dd57366 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -133,6 +133,28 @@ to your configuration.
 The new behaviour follows general babel backend rules (auto-detecting
 result type), but may affect the existing usage.
 
+*** =ob-ditaa=: output type control, ditaa executable, SVG output, and chararacter encoding
+
+Output file type is determined as specified in Babel documentation:
+the suffix of =:file= is the primary determinant, and =:file-ext=
+secondary.  There is no default type.  Previously available header
+arguments =:png=, =:eps= and =:pdf= are now deprecated.
+
+In order to use an 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.
+
+Character encoding is passed directly to ditaa (earlier to Java) and
+can be controlled by new header argument =:encoding=.
+
+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.
+
 ** New features
 
 # We list the most important features, and the features that may
diff --git a/lisp/ob-ditaa.el b/lisp/ob-ditaa.el
index 77eadd6c2..a3178c235 100644
--- a/lisp/ob-ditaa.el
+++ b/lisp/ob-ditaa.el
@@ -2,7 +2,8 @@
 
 ;; Copyright (C) 2009-2025 Free Software Foundation, Inc.
 
-;; Author: Eric Schulte
+;; Authors: Eric Schulte, Jarmo Hurri
+;; Maintainer: Jarmo Hurri <jarmo.hu...@iki.fi>
 ;; Keywords: literate programming, reproducible research
 ;; URL: https://orgmode.org
 
@@ -25,15 +26,53 @@
 
 ;; 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"
+;; - there is no "output", so source code blocks always export "results"
 ;;
-;; 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' |
+;;
+;; - the following header arguments are added:
+;;   "cmdline" : command line parameters passed to ditaa
+;;   "encoding" : character encoding (default UTF-8)
+;;   "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:
 
@@ -46,9 +85,34 @@
 (defvar org-babel-default-header-args:ditaa
   '((:results . "file")
     (:exports . "results")
-    (:java . "-Dfile.encoding=UTF-8"))
+    (:encoding . "UTF-8"))
   "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 'symbol
+  :options '(ditaa jar))
+
+(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.7.34")
+(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 +122,63 @@
 				  (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)
+  "Small internal helper function returning file if it exists and signalling 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
+                       (org-babel-graphical-output-file params)))
+         (out-file-suffix (file-name-extension out-file))
+         (svg (string= out-file-suffix "svg"))
+         (eps (string= out-file-suffix "eps"))
+         (pdf (string= out-file-suffix "pdf"))
+         (png (string= out-file-suffix "png")))
+    (when (not (or svg eps pdf png))
+      (error "(ob-ditaa) Output file type can not be determined."))
+    (let* ((ditaa-options (cdr (assq :cmdline params)))
+           (ditaa-encoding (cdr (assq :encoding 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)))
+	   (cmd (concat exec-form
+                        (when ditaa-options (concat " " ditaa-options))
+                        (when svg (concat " " "--svg"))
+                        (when ditaa-encoding (concat " " "-e " ditaa-encoding))
+                        " " in-file " " ditaa-out-file)))
+      (with-temp-file in-file (insert body))
+      (shell-command cmd)
+      (when pdf
+        (let ((pdf-cmd (concat "epstopdf" " " ditaa-out-file " "
+		               "-o=" (org-babel-process-file-name out-file))))
+          (shell-command pdf-cmd)))
+      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

Reply via email to