;;; ob-svgbob.el --- Babel Functions for SVGBob -*- lexical-binding: t; -*- ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Authors: Steven vanZyl ;; TEC ;; Maintainer: Timothy ;; 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 . ;;; 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