Files
emacs-conf/lisp/org/ob-ditaa.el

210 lines
8.3 KiB
EmacsLisp

;;; ob-ditaa.el --- Babel Functions for ditaa -*- lexical-binding: t; -*-
;; Copyright (C) 2009-2026 Free Software Foundation, Inc.
;; Authors: Eric Schulte, Jarmo Hurri
;; Keywords: literate programming, reproducible research
;; URL: https://orgmode.org
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Org-Babel support for evaluating ditaa source code.
;;
;; Source code blocks of type ditaa have some special features:
;;
;; - there is no such thing as a "session"
;;
;; - :export results is the default
;;
;; - 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
;;
;;; 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:
(require 'org-macs)
(org-assert-version)
(require 'ob)
(require 'org-compat)
(defvar org-babel-default-header-args:ditaa
'((:results . "file graphics")
(:exports . "results")
(: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))
:safe (lambda (x) (memq x '(jar ditaa))))
(defcustom org-ditaa-exec "ditaa"
"File name of the ditaa executable."
:group 'org-babel
:package-version '(Org . "9.8")
:type 'string
:risky t)
(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
:risky t)
(defcustom org-ditaa-jar-path (expand-file-name
"ditaa.jar"
(file-name-as-directory
(expand-file-name
"scripts"
(file-name-as-directory
(expand-file-name
"../contrib"
(file-name-directory (org-find-library-dir "org")))))))
"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.
Used when generating eps or pdf output."
:group 'org-babel
:version "24.4"
:package-version '(Org . "8.0")
: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.
This function is called by `org-babel-execute-src-block'."
(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."
(error "Ditaa does not support sessions"))
(provide 'ob-ditaa)
;;; ob-ditaa.el ends here