ob-processing.el 6.8 KB

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