#+Title: Org-Docco #+Author: Eric Schulte #+Style: #+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-lib) #+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)) (cl-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) (cl-incf beg-count)) ((looking-at end-re) (cl-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 "")= to find the beginning and end of the main content div. We then break up this div at =
= boundaries with multiple calls to
   =(org-docco-balanced-re "
")=.
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 "\n")
        (doc-row-start  "\n")
        (code-row-start "    \n")
        (table-end "
\n") (doc-row-end "\n") (code-row-end "
" ) pair transition-points next) (save-excursion (save-match-data (goto-char (point-min)) (when (re-search-forward "
" nil t) (goto-char (match-end 0)) (push (point-marker) transition-points) (goto-char (match-beginning 0)) (setq pair (org-docco-balanced-re "")) (while (setq next (org-docco-balanced-re "
"))
            (goto-char (cdr next))
            (push (car next) transition-points)
            (push (cdr next) transition-points))
          (goto-char (cdr pair))
          (push (and (re-search-backward "
" 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: #+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: