Browse Source

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
Eric Schulte 7 years ago
parent
commit
66ae794a66
2 changed files with 391 additions and 0 deletions
  1. 185 0
      contrib/scripts/docco.css
  2. 206 0
      contrib/scripts/org-docco.org

+ 185 - 0
contrib/scripts/docco.css

@@ -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 */

+ 206 - 0
contrib/scripts/org-docco.org

@@ -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: