ob-svgbob/ob-svgbob.el

135 lines
4.7 KiB
EmacsLisp

;;; ob-svgbob.el --- Babel Functions for SVGBob -*- lexical-binding: t; -*-
;; Copyright (C) 2021 Free Software Foundation, Inc.
;; Authors: Steven vanZyl <rushsteve1@rushsteve1.us>
;; TEC <tec@tecosaur.net>
;; Maintainer: Timothy <tec@tecosaur.net>
;; Keywords: literate programming, reproducible research
;; Homepage: https://git.tecosaur.net/tec/ob-svgbob
;; This file is not part of GNU Emacs.
;; ob-svgbob 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.
;; ob-svgbob 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 ob-svgbob. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Org-Babel support for evaluating and SVGBob diagrams.
;; https://github.com/ivanceras/svgbob
;; This is very similar to ob-dot.el with a similar list of caveats:
;; * There are no sessions
;; * We are generally only going to return results of type "file graphics"
;; * The "file" header argument is required
;; * SVGBob has no definite syntax
;; This file also includes some additional utility functions and a simple
;; derived major-mode for SVGBob
;;; Code:
(require 'ob)
(eval-when-compile
(require 'cl-lib))
(defcustom org-svgbob-executable "svgbob"
"The path to the SVGBob binary.
This can be installed from source using `cargo install svgbob_cli'"
:group 'org-babel
:type 'file)
(defcustom org-svgbob-buffer-name "*svgbob-output*"
"The name of the buffer that SVGBob will output to."
:group 'org-babel
:type 'string)
(defconst org-babel-svgbob--parameters
'(:background :fill-color :font-family :font-size :scale :stroke-width)
"Recognised SVGBob parameter keys.")
;; So `org-edit-special' works.
(unless (fboundp 'svgbob-mode)
(add-to-list 'org-src-lang-modes (cons "svgbob" 'fundamental)))
(defun ob-svgbob-string-to-svg (str &optional parameters)
"Convert STR to SVG text and return a string of that.
PARAMETERS should be a plist of svgbob parameters, and only keys
that are members of `org-babel-svgbob--parameters' will be used."
(with-temp-buffer
(insert
(org-babel-eval
(concat org-svgbob-executable
(cl-loop for (key . val)
in parameters
when (memq key org-babel-svgbob--parameters)
concat (format " --%s %S"
(substring (symbol-name key) 1)
val)))
str))
(when-let ((stroke-color (alist-get :stroke-color parameters)))
(goto-char (point-min))
(re-search-forward "^[ \t]*stroke: \\(black\\);\n")
(replace-match stroke-color t t nil 1))
(when-let ((text-color (alist-get :text-color parameters)))
(goto-char (point-min))
(search-forward "text {")
(re-search-forward "^[ \t]*fill: \\(black\\);\n")
(replace-match text-color t t nil 1))
(when-let ((file (alist-get :file parameters)))
(write-region nil nil file))
(buffer-string)))
(defun ob-svgbob-region-to-svg (start end)
"Convert a region to SVG text in a new buffer.
The region is given by the range START to END."
(interactive "r")
(let ((str (ob-svgbob-string-to-svg (buffer-substring-no-properties start end))))
(with-current-buffer (get-buffer-create org-svgbob-buffer-name)
(read-only-mode 0) ; Disable read-only
(fundamental-mode) ; Required to erase the buffer
(erase-buffer)
(insert str)
(image-mode)
(read-only-mode)
(display-buffer-in-side-window (current-buffer) '((side . right))))))
(defun ob-svgbob-buffer-to-svg ()
"Convert a buffer to SVG text in a new buffer.
See `svgbob-region-to-svg' for more"
(interactive)
(ob-svgbob-region-to-svg (point-min) (point-max)))
(defvar org-babel-default-header-args:svgbob
'((:results . "file graphics")
(:exports . "results")
(:background . "transparent"))
"Default arguments to use when evaluating a dot source block.")
(defun org-babel-execute:svgbob (body params)
"Execute a block of svgbob with org-babel.
Specifically, svgbob is called on BODY with PARAMS."
(if (alist-get :file params)
(ob-svgbob-string-to-svg body params)
(user-error "You need to specify a :file parameter")))
(defun org-babel-prep-session:svgbob (_session _params)
"Return an error because SVGBob does not support sessions."
(user-error "SVGBob does not support sessions"))
(provide 'ob-svgbob)
;;; ob-svgbob.el ends here