207 lines
8.7 KiB
Org Mode
207 lines
8.7 KiB
Org Mode
#+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:
|