3 #+Style: <link rel="stylesheet" href="docco.css" type="text/css">
6 The =docco= tool (see https://jashkenas.github.com/docco/) generates
7 HTML from JavaScript source code providing an attractive side-by-side
8 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]])
9 generates the same type of output from Org-mode documents with code
10 embedded in code blocks.
12 The way this works is an Org-mode document with embedded code blocks
13 is exported to html using the standard Org-mode export functions.
14 This file defines a new function named =org-docco-buffer= which, when
15 added to the =org-export-html-final-hook=, will be run automatically
16 as part of the Org-mod export process doccoizing your Org-mode
19 A pure source code file can be extracted (or "/tangled/") from the
20 Org-mode document using the normal =org-babel-tangle= function. See
21 [[https://orgmode.org/manual/Working-With-Source-Code.html][Working With Source Code]] chapter of the Org-mode manual for more
22 information on using code blocks in Org-mode files.
24 *Disclaimer*: this currently only works on /very/ simple Org-mode
25 files which have no headings but rather are just a collection of
26 alternating text and code blocks. It wouldn't be difficult to
27 generalize the following code so that it could be run in particular
28 sub-trees but I simply don't have the time to do so myself, and this
29 version perfectly satisfies my own limit needs. I make no promises to
30 support this code moving forward. /Caveat Emptor/
32 #+begin_src emacs-lisp :padline no
33 ;;; org-docco.el --- docco type html generation from Org-mode
35 ;; Copyright (C) 2012 Eric Schulte
37 ;; Author: Eric Schulte
38 ;; Keywords: org-mode, literate programming, html
39 ;; Homepage: https://orgmode.org/worg/org-contrib/org-mime.php
42 ;; This file is not part of GNU Emacs.
46 ;; This program is free software; you can redistribute it and/or modify
47 ;; it under the terms of the GNU General Public License as published by
48 ;; the Free Software Foundation; either version 3, or (at your option)
51 ;; This program is distributed in the hope that it will be useful,
52 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
53 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54 ;; GNU General Public License for more details.
56 ;; You should have received a copy of the GNU General Public License
57 ;; along with GNU Emacs; see the file COPYING. If not, write to the
58 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
59 ;; Boston, MA 02110-1301, USA.
66 The =cl= package provides all of the state-changing functions used
67 below e.g., =push= and =incf=. It looks like a namespace-safe version
68 of =cl= may soon be permissible for use in official Emacs packages.
69 #+begin_src emacs-lisp
74 This is a function which returns the buffer positions of matching
75 regular expressions. It has two special features...
76 1. It only counts matched instances of =beg-re= and =end-re= which are
77 properly nested, so for example if =beg-re= and =end-re= are set to
78 =(= and =)= respectively and we run this against the following,
82 : (foo (bar baz) (qux) quux)
83 it will return 1 and 6 rather than 1 and 3.
84 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
85 buffer is changed (e.g., by me adding in extra HTML text).
86 #+begin_src emacs-lisp
87 (defun org-docco-balanced-re (beg-re end-re)
88 "Return the beginning and of a balanced regexp."
91 (let ((both-re (concat "\\(" beg-re "\\|" end-re "\\)"))
92 (beg-count 0) (end-count 0)
94 (when (re-search-forward beg-re nil t)
95 (goto-char (match-beginning 0))
96 (setq beg (point-marker))
98 (goto-char (match-end 0))
99 (while (and (not end) (re-search-forward both-re nil t))
100 (goto-char (match-beginning 0))
101 (cond ((looking-at beg-re) (incf beg-count))
102 ((looking-at end-re) (incf end-count))
103 (:otherwise (error "miss-matched")))
104 (goto-char (match-end 0))
105 (when (= beg-count end-count) (setq end (point-marker))))
106 (when end (cons beg end)))))))
109 This ugly large function does the actual conversion. It wraps the
110 entire main content =div= of the exported Org-mode html into a single
111 large table. Each row of the table has documentation on the left side
112 and code on the right side. This function has two parts.
113 1. We use =(org-docco-balanced-re "<div" "</div>")= to find the
114 beginning and end of the main content div. We then break up this
115 div at =<pre></pre>= boundaries with multiple calls to
116 =(org-docco-balanced-re "<pre class\"src" "</pre>")=.
117 2. With all documentation/code boundaries in hand we step through the
118 buffer inserting the table html code at boundary locations.
119 #+begin_src emacs-lisp
120 (defun org-docco-buffer ()
121 "Call from within an HTML buffer to doccoize it."
123 (let ((table-start "<table>\n")
124 (doc-row-start "<tr><th class=\"docs\">\n") (doc-row-end "</th>\n")
125 (code-row-start " <td class=\"code\">\n") (code-row-end "</td></tr>\n")
126 (table-end "</table>" )
127 pair transition-points next)
130 (goto-char (point-min))
131 (when (re-search-forward "<div id=\"content\">" nil t)
132 (goto-char (match-end 0))
133 (push (point-marker) transition-points)
134 (goto-char (match-beginning 0))
135 (setq pair (org-docco-balanced-re "<div" "</div>"))
136 (while (setq next (org-docco-balanced-re "<pre class=\"src" "</pre>"))
137 (goto-char (cdr next))
138 (push (car next) transition-points)
139 (push (cdr next) transition-points))
140 (goto-char (cdr pair))
141 (push (and (re-search-backward "</div>" nil t) (point-marker))
143 ;; collected transitions, so build the table
144 (setq transition-points (nreverse transition-points))
145 (goto-char (pop transition-points))
146 (insert table-start doc-row-start)
147 (while (> (length transition-points) 1)
148 (goto-char (pop transition-points))
149 (insert doc-row-end code-row-start)
150 (goto-char (pop transition-points))
151 (insert code-row-end doc-row-start))
152 (goto-char (pop transition-points))
153 (insert code-row-end table-end)
154 (unless (null transition-points)
155 (error "leftover points")))))))
158 We'll use Emacs [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Specifying-File-Variables.html][File Local Variables]] and the
159 =org-export-html-final-hook= to control which buffers have
160 =org-docco-buffer= run as part of their export process.
161 #+begin_src emacs-lisp
162 (defvar org-docco-doccoize-me nil
163 "File local variable controlling if html export should be doccoized.")
164 (make-local-variable 'org-docco-doccoize-me)
167 A simple function will conditionally process HTML output based on the
168 value of this variable.
169 #+begin_src emacs-lisp
170 (defun org-docco-buffer-maybe ()
171 (when org-docco-doccoize-me (org-docco-buffer)))
174 Finally this function is added to the =org-export-html-final-hook=.
175 #+begin_src emacs-lisp
176 (add-hook 'org-export-html-final-hook #'org-docco-buffer-maybe)
179 That's it. To use this simply;
180 1. Checkout this file from https://github.com/eschulte/org-docco,
181 : git clone git://github.com/eschulte/org-docco.git
182 and open it using Emacs.
183 2. Tangle =org-docco.el= out of this file by calling
184 =org-babel-tangle= or =C-c C-v t=.
185 3. Load the resulting Emacs Lisp file.
186 4. Execute the following in any Org-mode buffer to add file local
187 variable declarations which will enable post-processed with
189 : (add-file-local-variable 'org-export-html-postamble nil)
190 : (add-file-local-variable 'org-export-html-style-include-default nil)
191 : (add-file-local-variable 'org-docco-doccoize-me t)
192 And add the following style declaration to make use of the
193 =docco.css= style sheet taken directly from
194 https://github.com/jashkenas/docco.
195 : #+Style: <link rel="stylesheet" href="docco.css" type="text/css">
197 #+begin_src emacs-lisp
199 ;;; org-docco.el ends here
203 # org-export-html-postamble: nil
204 # org-export-html-style-include-default: nil
205 # org-docco-doccoize-me: t