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)
#+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))
(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) (incf beg-count))
((looking-at end-re) (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:
|