contrib/org-docco.org -- docco side-by-side HTML export of annotated source code

for an example of the code output see
  http://eschulte.github.com/org-docco/org-docco.html
This commit is contained in:
Eric Schulte 2012-04-20 12:21:50 -04:00
parent 3f427d92c8
commit 66ae794a66
2 changed files with 391 additions and 0 deletions

185
contrib/scripts/docco.css Normal file
View File

@ -0,0 +1,185 @@
/*--------------------- Layout and Typography ----------------------------*/
body {
font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
font-size: 15px;
line-height: 22px;
color: #252519;
margin: 0; padding: 0;
}
a {
color: #261a3b;
}
a:visited {
color: #261a3b;
}
p {
margin: 0 0 15px 0;
}
h1, h2, h3, h4, h5, h6 {
margin: 0px 0 15px 0;
}
h1 {
margin-top: 40px;
}
#container {
position: relative;
}
#background {
position: fixed;
top: 0; left: 525px; right: 0; bottom: 0;
background: #f5f5ff;
border-left: 1px solid #e5e5ee;
z-index: -1;
}
#jump_to, #jump_page {
background: white;
-webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
-webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
font: 10px Arial;
text-transform: uppercase;
cursor: pointer;
text-align: right;
}
#jump_to, #jump_wrapper {
position: fixed;
right: 0; top: 0;
padding: 5px 10px;
}
#jump_wrapper {
padding: 0;
display: none;
}
#jump_to:hover #jump_wrapper {
display: block;
}
#jump_page {
padding: 5px 0 3px;
margin: 0 0 25px 25px;
}
#jump_page .source {
display: block;
padding: 5px 10px;
text-decoration: none;
border-top: 1px solid #eee;
}
#jump_page .source:hover {
background: #f5f5ff;
}
#jump_page .source:first-child {
}
table td {
border: 0;
outline: 0;
}
td.docs, th.docs {
max-width: 450px;
min-width: 450px;
min-height: 5px;
padding: 10px 25px 1px 50px;
overflow-x: hidden;
vertical-align: top;
text-align: left;
}
.docs pre {
margin: 15px 0 15px;
padding-left: 15px;
}
.docs p tt, .docs p code {
background: #f8f8ff;
border: 1px solid #dedede;
font-size: 12px;
padding: 0 0.2em;
}
.pilwrap {
position: relative;
}
.pilcrow {
font: 12px Arial;
text-decoration: none;
color: #454545;
position: absolute;
top: 3px; left: -20px;
padding: 1px 2px;
opacity: 0;
-webkit-transition: opacity 0.2s linear;
}
td.docs:hover .pilcrow {
opacity: 1;
}
td.code, th.code {
padding: 14px 15px 16px 25px;
width: 100%;
vertical-align: top;
border-left: 1px solid #e5e5ee;
}
pre, tt, code {
font-size: 12px; line-height: 18px;
font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
margin: 0; padding: 0;
}
/*---------------------- Syntax Highlighting -----------------------------*/
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
body .hll { background-color: #ffffcc }
body .c { color: #408080; font-style: italic } /* Comment */
body .err { border: 1px solid #FF0000 } /* Error */
body .k { color: #954121 } /* Keyword */
body .o { color: #666666 } /* Operator */
body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
body .cp { color: #BC7A00 } /* Comment.Preproc */
body .c1 { color: #408080; font-style: italic } /* Comment.Single */
body .cs { color: #408080; font-style: italic } /* Comment.Special */
body .gd { color: #A00000 } /* Generic.Deleted */
body .ge { font-style: italic } /* Generic.Emph */
body .gr { color: #FF0000 } /* Generic.Error */
body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
body .gi { color: #00A000 } /* Generic.Inserted */
body .go { color: #808080 } /* Generic.Output */
body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
body .gs { font-weight: bold } /* Generic.Strong */
body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
body .gt { color: #0040D0 } /* Generic.Traceback */
body .kc { color: #954121 } /* Keyword.Constant */
body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
body .kp { color: #954121 } /* Keyword.Pseudo */
body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
body .kt { color: #B00040 } /* Keyword.Type */
body .m { color: #666666 } /* Literal.Number */
body .s { color: #219161 } /* Literal.String */
body .na { color: #7D9029 } /* Name.Attribute */
body .nb { color: #954121 } /* Name.Builtin */
body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
body .no { color: #880000 } /* Name.Constant */
body .nd { color: #AA22FF } /* Name.Decorator */
body .ni { color: #999999; font-weight: bold } /* Name.Entity */
body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
body .nf { color: #0000FF } /* Name.Function */
body .nl { color: #A0A000 } /* Name.Label */
body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
body .nt { color: #954121; font-weight: bold } /* Name.Tag */
body .nv { color: #19469D } /* Name.Variable */
body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
body .w { color: #bbbbbb } /* Text.Whitespace */
body .mf { color: #666666 } /* Literal.Number.Float */
body .mh { color: #666666 } /* Literal.Number.Hex */
body .mi { color: #666666 } /* Literal.Number.Integer */
body .mo { color: #666666 } /* Literal.Number.Oct */
body .sb { color: #219161 } /* Literal.String.Backtick */
body .sc { color: #219161 } /* Literal.String.Char */
body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
body .s2 { color: #219161 } /* Literal.String.Double */
body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
body .sh { color: #219161 } /* Literal.String.Heredoc */
body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
body .sx { color: #954121 } /* Literal.String.Other */
body .sr { color: #BB6688 } /* Literal.String.Regex */
body .s1 { color: #219161 } /* Literal.String.Single */
body .ss { color: #19469D } /* Literal.String.Symbol */
body .bp { color: #954121 } /* Name.Builtin.Pseudo */
body .vc { color: #19469D } /* Name.Variable.Class */
body .vg { color: #19469D } /* Name.Variable.Global */
body .vi { color: #19469D } /* Name.Variable.Instance */
body .il { color: #666666 } /* Literal.Number.Integer.Long */

View File

@ -0,0 +1,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 [[http://orgmode.org/w/?p=org-mode.git;a=blob_plain;f=contrib/scripts/org-docco.org;hb=HEAD][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
[[http://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: http://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: