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:
parent
3f427d92c8
commit
66ae794a66
|
@ -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 */
|
|
@ -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:
|
Loading…
Reference in New Issue