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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
| | #+Title: Org-Docco
#+Author: Eric Schulte
#+Style: <link rel="stylesheet" href="docco.css" type="text/css">
#+Property: tangle yes
The =docco= tool (see http://jashkenas.github.com/docco/) generates
HTML from JavaScript source code providing an attractive side-by-side
display of source code and comments. This file (see [[https://orgmode.org/cgit.cgi/org-mode.git/plain/contrib/scripts/org-docco.org][org-docco.org]])
generates the same type of output from Org-mode documents with code
embedded in code blocks.
The way this works is an Org-mode document with embedded code blocks
is exported to html using the standard Org-mode export functions.
This file defines a new function named =org-docco-buffer= which, when
added to the =org-export-html-final-hook=, will be run automatically
as part of the Org-mod export process doccoizing your Org-mode
document.
A pure source code file can be extracted (or "/tangled/") from the
Org-mode document using the normal =org-babel-tangle= function. See
[[https://orgmode.org/manual/Working-With-Source-Code.html][Working With Source Code]] chapter of the Org-mode manual for more
information on using code blocks in Org-mode files.
*Disclaimer*: this currently only works on /very/ simple Org-mode
files which have no headings but rather are just a collection of
alternating text and code blocks. It wouldn't be difficult to
generalize the following code so that it could be run in particular
sub-trees but I simply don't have the time to do so myself, and this
version perfectly satisfies my own limit needs. I make no promises to
support this code moving forward. /Caveat Emptor/
#+begin_src emacs-lisp :padline no
;;; org-docco.el --- docco type html generation from Org-mode
;; Copyright (C) 2012 Eric Schulte
;; Author: Eric Schulte
;; Keywords: org-mode, literate programming, html
;; Homepage: https://orgmode.org/worg/org-contrib/org-mime.php
;; Version: 0.01
;; This file is not part of GNU Emacs.
;;; 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.
;;; Commentary:
;; <- look over there
#+end_src
The =cl= package provides all of the state-changing functions used
below e.g., =push= and =incf=. It looks like a namespace-safe version
of =cl= may soon be permissible for use in official Emacs packages.
#+begin_src emacs-lisp
;;; Code:
(require 'cl-lib)
#+end_src
This is a function which returns the buffer positions of matching
regular expressions. It has two special features...
1. It only counts matched instances of =beg-re= and =end-re= which are
properly nested, so for example if =beg-re= and =end-re= are set to
=(= and =)= respectively and we run this against the following,
: 1 2 3 4 5 6
: | | | | | |
: v v v v v v
: (foo (bar baz) (qux) quux)
it will return 1 and 6 rather than 1 and 3.
2. It uses [[www.gnu.org/s/emacs/manual/html_node/elisp/Markers.html][markers]] which save their position in a buffer even as the
buffer is changed (e.g., by me adding in extra HTML text).
#+begin_src emacs-lisp
(defun org-docco-balanced-re (beg-re end-re)
"Return the beginning and of a balanced regexp."
(save-excursion
(save-match-data
(let ((both-re (concat "\\(" beg-re "\\|" end-re "\\)"))
(beg-count 0) (end-count 0)
beg end)
(when (re-search-forward beg-re nil t)
(goto-char (match-beginning 0))
(setq beg (point-marker))
(cl-incf beg-count)
(goto-char (match-end 0))
(while (and (not end) (re-search-forward both-re nil t))
(goto-char (match-beginning 0))
(cond ((looking-at beg-re) (cl-incf beg-count))
((looking-at end-re) (cl-incf end-count))
(:otherwise (error "miss-matched")))
(goto-char (match-end 0))
(when (= beg-count end-count) (setq end (point-marker))))
(when end (cons beg end)))))))
#+end_src
This ugly large function does the actual conversion. It wraps the
entire main content =div= of the exported Org-mode html into a single
large table. Each row of the table has documentation on the left side
and code on the right side. This function has two parts.
1. We use =(org-docco-balanced-re "<div" "</div>")= to find the
beginning and end of the main content div. We then break up this
div at =<pre></pre>= boundaries with multiple calls to
=(org-docco-balanced-re "<pre class\"src" "</pre>")=.
2. With all documentation/code boundaries in hand we step through the
buffer inserting the table html code at boundary locations.
#+begin_src emacs-lisp
(defun org-docco-buffer ()
"Call from within an HTML buffer to doccoize it."
(interactive)
(let ((table-start "<table>\n")
(doc-row-start "<tr><th class=\"docs\">\n") (doc-row-end "</th>\n")
(code-row-start " <td class=\"code\">\n") (code-row-end "</td></tr>\n")
(table-end "</table>" )
pair transition-points next)
(save-excursion
(save-match-data
(goto-char (point-min))
(when (re-search-forward "<div id=\"content\">" nil t)
(goto-char (match-end 0))
(push (point-marker) transition-points)
(goto-char (match-beginning 0))
(setq pair (org-docco-balanced-re "<div" "</div>"))
(while (setq next (org-docco-balanced-re "<pre class=\"src" "</pre>"))
(goto-char (cdr next))
(push (car next) transition-points)
(push (cdr next) transition-points))
(goto-char (cdr pair))
(push (and (re-search-backward "</div>" nil t) (point-marker))
transition-points)
;; collected transitions, so build the table
(setq transition-points (nreverse transition-points))
(goto-char (pop transition-points))
(insert table-start doc-row-start)
(while (> (length transition-points) 1)
(goto-char (pop transition-points))
(insert doc-row-end code-row-start)
(goto-char (pop transition-points))
(insert code-row-end doc-row-start))
(goto-char (pop transition-points))
(insert code-row-end table-end)
(unless (null transition-points)
(error "leftover points")))))))
#+end_src
We'll use Emacs [[http://www.gnu.org/software/emacs/manual/html_node/emacs/Specifying-File-Variables.html][File Local Variables]] and the
=org-export-html-final-hook= to control which buffers have
=org-docco-buffer= run as part of their export process.
#+begin_src emacs-lisp
(defvar org-docco-doccoize-me nil
"File local variable controlling if html export should be doccoized.")
(make-local-variable 'org-docco-doccoize-me)
#+end_src
A simple function will conditionally process HTML output based on the
value of this variable.
#+begin_src emacs-lisp
(defun org-docco-buffer-maybe ()
(when org-docco-doccoize-me (org-docco-buffer)))
#+end_src
Finally this function is added to the =org-export-html-final-hook=.
#+begin_src emacs-lisp
(add-hook 'org-export-html-final-hook #'org-docco-buffer-maybe)
#+end_src
That's it. To use this simply;
1. Checkout this file from https://github.com/eschulte/org-docco,
: git clone git://github.com/eschulte/org-docco.git
and open it using Emacs.
2. Tangle =org-docco.el= out of this file by calling
=org-babel-tangle= or =C-c C-v t=.
3. Load the resulting Emacs Lisp file.
4. Execute the following in any Org-mode buffer to add file local
variable declarations which will enable post-processed with
=org-docco-buffer=.
: (add-file-local-variable 'org-export-html-postamble nil)
: (add-file-local-variable 'org-export-html-style-include-default nil)
: (add-file-local-variable 'org-docco-doccoize-me t)
And add the following style declaration to make use of the
=docco.css= style sheet taken directly from
https://github.com/jashkenas/docco.
: #+Style: <link rel="stylesheet" href="docco.css" type="text/css">
#+begin_src emacs-lisp
(provide 'org-docco)
;;; org-docco.el ends here
#+end_src
# Local Variables:
# org-export-html-postamble: nil
# org-export-html-style-include-default: nil
# org-docco-doccoize-me: t
# End:
|