ob-processing.el (7073B)
1 ;;; ob-processing.el --- Babel functions for processing -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2015-2024 Free Software Foundation, Inc. 4 5 ;; Author: Jarmo Hurri (adapted from ob-asymptote.el written by Eric Schulte) 6 ;; Maintainer: Jarmo Hurri <jarmo.hurri@iki.fi> 7 ;; Keywords: literate programming, reproducible research 8 ;; URL: https://orgmode.org 9 10 ;; This file is part of GNU Emacs. 11 12 ;; GNU Emacs is free software: you can redistribute it and/or modify 13 ;; it under the terms of the GNU General Public License as published by 14 ;; the Free Software Foundation, either version 3 of the License, or 15 ;; (at your option) any later version. 16 17 ;; GNU Emacs is distributed in the hope that it will be useful, 18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 ;; GNU General Public License for more details. 21 22 ;; You should have received a copy of the GNU General Public License 23 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. 24 25 ;;; Commentary: 26 27 ;; Babel support for evaluating processing source code. 28 ;; 29 ;; This differs from most standard languages in that 30 ;; 31 ;; 1) there is no such thing as a "session" in processing 32 ;; 33 ;; 2) results can only be exported as html; in this case, the 34 ;; processing code is embedded via a file into a javascript block 35 ;; using the processing.js module; the script then draws the 36 ;; resulting output when the web page is viewed in a browser; note 37 ;; that the user is responsible for making sure that processing.js 38 ;; is available on the website 39 ;; 40 ;; 3) it is possible to interactively view the sketch of the 41 ;; Processing code block via Processing 2.0 Emacs mode, using 42 ;; `org-babel-processing-view-sketch'. You can bind this command 43 ;; to, e.g., C-c C-v C-k with 44 ;; 45 ;; (define-key org-babel-map (kbd "C-k") 'org-babel-processing-view-sketch) 46 47 48 ;;; Requirements: 49 50 ;; - processing2-emacs mode :: https://github.com/ptrv/processing2-emacs 51 ;; - Processing.js module :: https://processingjs.org/ 52 53 ;;; Code: 54 55 (require 'org-macs) 56 (org-assert-version) 57 58 (require 'ob) 59 (require 'sha1) 60 61 (declare-function processing-sketch-run "ext:processing-mode" ()) 62 63 (defvar org-babel-temporary-directory) 64 65 (defvar org-babel-tangle-lang-exts) 66 (add-to-list 'org-babel-tangle-lang-exts '("processing" . "pde")) 67 68 ;; Default header tags depend on whether exporting html or not; if not 69 ;; exporting html, then no results are produced; otherwise results are 70 ;; HTML. 71 (defvar org-babel-default-header-args:processing 72 '((:results . "html") (:exports . "results")) 73 "Default arguments when evaluating a Processing source block.") 74 75 (defvar org-babel-processing-processing-js-filename "processing.js" 76 "Filename of the processing.js file.") 77 78 (defun org-babel-processing-view-sketch () 79 "Show the sketch of the Processing block under point in an external viewer." 80 (interactive) 81 (org-require-package 'processing-mode) 82 (let ((info (org-babel-get-src-block-info))) 83 (if (string= (nth 0 info) "processing") 84 (let* ((body (nth 1 info)) 85 (params (org-babel-process-params (nth 2 info))) 86 (sketch-code 87 (org-babel-expand-body:generic 88 body 89 params 90 (org-babel-variable-assignments:processing params)))) 91 ;; Note: sketch filename can not contain a hyphen, since it 92 ;; has to be a valid java class name; for this reason 93 ;; make-temp-file is repeated until no hyphen is in the 94 ;; name; also sketch dir name must be the same as the 95 ;; basename of the sketch file. 96 (let* ((temporary-file-directory (org-babel-temp-directory)) 97 (sketch-dir 98 (let (sketch-dir-candidate) 99 (while 100 (progn 101 (setq sketch-dir-candidate 102 (make-temp-file "processing" t)) 103 (when (string-match-p 104 "-" 105 (file-name-nondirectory sketch-dir-candidate)) 106 (delete-directory sketch-dir-candidate) 107 t))) 108 sketch-dir-candidate)) 109 (sketch-filename 110 (concat sketch-dir 111 "/" 112 (file-name-nondirectory sketch-dir) 113 ".pde"))) 114 (with-temp-file sketch-filename (insert sketch-code)) 115 (find-file sketch-filename) 116 (processing-sketch-run) 117 (kill-buffer))) 118 (message "Not inside a Processing source block.")))) 119 120 (defun org-babel-execute:processing (body params) 121 "Execute Processing code BODY according to PARAMS. 122 This function is called by `org-babel-execute-src-block'." 123 (let ((sketch-code 124 (org-babel-expand-body:generic 125 body 126 params 127 (org-babel-variable-assignments:processing params)))) 128 ;; Results are HTML. 129 (let ((sketch-canvas-id (concat "ob-" (sha1 sketch-code)))) 130 (concat "<script src=\"" 131 org-babel-processing-processing-js-filename 132 "\"></script>\n <script type=\"text/processing\"" 133 " data-processing-target=\"" 134 sketch-canvas-id 135 "\">\n" 136 sketch-code 137 "\n</script> <canvas id=\"" 138 sketch-canvas-id 139 "\"></canvas>")))) 140 141 (defun org-babel-prep-session:processing (_session _params) 142 "Return an error if the :session header argument is set. 143 Processing does not support sessions." 144 (error "Processing does not support sessions")) 145 146 (defun org-babel-variable-assignments:processing (params) 147 "Return list of processing statements assigning the block's variables. 148 The variable assignments are defined in PARAMS." 149 (mapcar #'org-babel-processing-var-to-processing 150 (org-babel--get-vars params))) 151 152 (defun org-babel-processing-var-to-processing (pair) 153 "Convert an elisp value into a Processing variable. 154 The elisp value PAIR is converted into Processing code specifying 155 a variable of the same value." 156 (let ((var (car pair)) 157 (val (let ((v (cdr pair))) 158 (if (symbolp v) (symbol-name v) v)))) 159 (cond 160 ((integerp val) 161 (format "int %S=%S;" var val)) 162 ((floatp val) 163 (format "float %S=%S;" var val)) 164 ((stringp val) 165 (format "String %S=\"%s\";" var val)) 166 ((and (listp val) (not (listp (car val)))) 167 (let* ((type (org-babel-processing-define-type val)) 168 (fmt (if (eq 'String type) "\"%s\"" "%s")) 169 (vect (mapconcat (lambda (e) (format fmt e)) val ", "))) 170 (format "%s[] %S={%s};" type var vect))) 171 ((listp val) 172 (let* ((type (org-babel-processing-define-type val)) 173 (fmt (if (eq 'String type) "\"%s\"" "%s")) 174 (array (mapconcat (lambda (row) 175 (concat "{" 176 (mapconcat (lambda (e) (format fmt e)) 177 row ", ") 178 "}")) 179 val ","))) 180 (format "%S[][] %S={%s};" type var array)))))) 181 182 (defun org-babel-processing-define-type (data) 183 "Determine type of DATA. 184 185 DATA is a list. Return type as a symbol. 186 187 The type is `String' if any element in DATA is a string. 188 Otherwise, it is either `float', if some elements are floats, or 189 `int'." 190 (letrec ((type 'int) 191 (find-type 192 (lambda (row) 193 (dolist (e row type) 194 (cond ((listp e) (setq type (funcall find-type e))) 195 ((stringp e) (throw 'exit 'String)) 196 ((floatp e) (setq type 'float))))))) 197 (catch 'exit (funcall find-type data)))) 198 199 (provide 'ob-processing) 200 201 ;;; ob-processing.el ends here