config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

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