-
Notifications
You must be signed in to change notification settings - Fork 1
/
ob-napkin.el
151 lines (126 loc) · 5.99 KB
/
ob-napkin.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
;;; ob-napkin.el --- Babel functions for Napkin -*- lexical-binding: t -*-
;; Copyright (C) Hans Jang
;; Author: Hans Jang
;; Keywords: tools, literate programming, reproducible research, napkin, plantuml
;; Homepage: https://github.com/pinetr2e/ob-napkin
;; Version: 0.10
;; Package-Requires: ((emacs "26.1"))
;;; License:
;; This program 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, or (at your option)
;; any later version.
;;
;; This program 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;; This file is not part of GNU Emacs.
;;; Commentary:
;; Org-Babel support for evaluating Napkin script, a Python based DSL to write
;; sequence diagrams.
;;; Requirements:
;;
;; pip install napkin plantuml
;;
;; See https://github.com/pinetr2e/napkin
;;; Code:
(require 'ob)
(defcustom org-babel-napkin-command "napkin"
"Name of the command for running napkin tool command line."
:group 'org-babel
:type 'string)
(defcustom org-babel-napkin-plantuml-server-url ""
"Server URL to use in generating image file.
The empty string means to use the public server."
:group 'org-babel
:type 'string)
(defvar org-babel-default-header-args:napkin
'((:results . "file") (:exports . "results"))
"Default arguments for evaluating a napkin src block.")
(defvar org-babel-default-header-args:napkin-puml
'((:results . "file") (:exports . "results"))
"Default arguments for evaluating a napkin-puml src block.")
(defun org-babel-napkin-out-file (params)
"Return output file name from PARAMS."
(if (member "file" (cdr (assq :result-params params )))
(or (cdr (assq :file params))
(error "Napkin src block requires :file header argument for file type results"))
(org-babel-temp-file "napkin-" ".txt")))
(defun org-babel-expand-body:napkin (body out-file)
"Prepend import/decorator with file name coming from PARAMS with BODY."
(if (string-match (rx buffer-start (0+ blank) "def" (1+ blank) "seq_diagram" (0+ blank) "(") body)
(concat "import napkin\n"
(format "@napkin.seq_diagram('%s')\n" (file-name-base (org-babel-process-file-name out-file)))
body)
(error "Napkin src block requires def seq_diagram() as the first line of the contents")))
;;;###autoload
(defun org-babel-execute:napkin (body params)
"Execute a block of napkin code with BODY and PARAMS with Babel.
napkin tool will be invoked to generate the image."
(let* ((out-file (org-babel-napkin-out-file params))
(img-type (file-name-extension out-file))
(in-file (org-babel-temp-file "napkin-" ".py"))
(verbatim (member "verbatim" (cdr (assq :result-params params ))))
(expanded-body (org-babel-expand-body:napkin body out-file))
(server-url org-babel-napkin-plantuml-server-url)
(tool-path org-babel-napkin-command)
(command (format "%s %s -o %s -f %s %s"
tool-path
(org-babel-process-file-name in-file)
(file-name-directory (org-babel-process-file-name out-file))
(concat "plantuml_" img-type)
(if (string-equal server-url "") "" (concat "--server-url " server-url)))))
(with-temp-file in-file (insert expanded-body))
(message "%s" command)
(org-babel-eval command "")
(if (and verbatim (string-equal img-type "txt"))
(with-temp-buffer
(insert-file-contents (org-babel-process-file-name out-file))
(buffer-substring-no-properties (point-min) (point-max))))))
(defun org-babel-expand-body:napkin-puml (body _params)
"Wrap BODY if it does not include @startuml. PARAMS are unused."
(if (string-match (rx buffer-start (0+ blank) "@startuml") body)
body
(concat "@startuml\n" body "@enduml")))
;;;###autoload
(defun org-babel-execute:napkin-puml (body params)
"Execute a block of plantuml code with BODY and PARAMS with Babel.
napkin_plantuml tool will be invoked to generate the image."
(let* ((out-file (org-babel-napkin-out-file params))
(img-type (file-name-extension out-file))
(in-file (org-babel-temp-file "napkin-" ".puml"))
(verbatim (member "verbatim" (cdr (assq :result-params params ))))
(expanded-body (org-babel-expand-body:napkin-puml body out-file))
(server-url org-babel-napkin-plantuml-server-url)
(tool-path (concat org-babel-napkin-command "_plantuml"))
(command (format "%s %s %s %s"
tool-path
(org-babel-process-file-name in-file)
(org-babel-process-file-name out-file)
(if (string-equal server-url "") "" (concat "--server-url " server-url)))))
(with-temp-file in-file (insert expanded-body))
(message "%s" command)
(org-babel-eval command "")
(if (and verbatim (string-equal img-type "txt"))
(with-temp-buffer
(insert-file-contents (org-babel-process-file-name out-file))
(buffer-substring-no-properties (point-min) (point-max))))))
(defun ob-napkin-unload-function ()
"Pre-cleanup when `unload-feature' is called."
(setq org-src-lang-modes
(remove '("napkin" . python)
(remove '("napkin-puml" . planuml)
org-src-lang-modes)))
;; return nil to continue standard unloading:
nil)
(add-to-list 'org-src-lang-modes '("napkin" . python))
(when (featurep 'plantuml-mode)
(add-to-list 'org-src-lang-modes '("napkin-puml" . plantuml)))
(provide 'ob-napkin)
;;; ob-napkin.el ends here