#!/bin/sh # **shocco** is a quick-and-dirty, literate-programming-style documentation # generator written for and in __POSIX shell__. It borrows liberally from # [Docco][do], the original Q&D literate-programming-style doc generator. # # `shocco(1)` reads shell scripts and produces annotated source documentation # in HTML format. Comments are formatted with Markdown and presented # alongside syntax highlighted code so as to give an annotation effect. This # page is the result of running `shocco` against [its own source file][sh]. # # shocco is built with `make(1)` and installs under `/usr/local` by default: # # git clone git://github.com/rtomayko/shocco.git # cd shocco # make # sudo make install # # or just copy 'shocco' wherever you need it # # Once installed, the `shocco` program can be used to generate documentation # for a shell script: # # shocco shocco.sh # # The generated HTML is written to `stdout`. # # [do]: http://jashkenas.github.com/docco/ # [sh]: https://github.com/rtomayko/shocco/blob/master/shocco.sh#commit # Usage and Prerequisites # ----------------------- # The most important line in any shell program. set -e # There's a lot of different ways to do usage messages in shell scripts. # This is my favorite: you write the usage message in a comment -- # typically right after the shebang line -- *BUT*, use a special comment prefix # like `#/` so that its easy to pull these lines out. # # This also illustrates one of shocco's corner features. Only comment lines # padded with a space are considered documentation. A `#` followed by any # other character is considered code. # #/ Usage: shocco [-t
` blocks. We add # these back in at each section when we build the output document. sed ' s/// s/^<\/pre><\/div>//' | # Again with the `csplit(1)`. Each code section is written to a separate # file, this time with a `codeXXX` prefix. There should be the same number # of `codeXXX` files as there are `docsXXX` files. ( DIVIDER='/# DIVIDER/' csplit -sk \ $CSPLITARGS \ -f code \ -n 4 - \ "$DIVIDER" '{9999}' \ 2>/dev/null || true ) # At this point, we have separate files for each docs section and separate # files for each code section. # HTML Template # ------------- # Create a function for apply the standard [Docco][do] HTML layout, using # [jashkenas][ja]'s gorgeous CSS for styles. Wrapping the layout in a function # lets us apply it elsewhere simply by piping in a body. # # [ja]: http://github.com/jashkenas/ # [do]: http://jashkenas.github.com/docco/ layout () { cat <$1 HTML } # Recombining # ----------- # Alright, we have separate files for each docs section and separate # files for each code section. We've defined a function to wrap the # results in the standard layout. All that's left to do now is put # everything back together. # Before starting the pipeline, decide the order in which to present the # files. If `code0000` is empty, it should appear first so the remaining # files are presented `docs0000`, `code0001`, `docs0001`, and so on. If # `code0000` is not empty, `docs0000` should appear first so the files # are presented `docs0000`, `code0000`, `docs0001`, `code0001` and so on. # # Ultimately, this means that if `code0000` is empty, the `-r` option # should not be provided with the final `-k` option group to `sort`(1) in # the pipeline below. if stat -c"%s" /dev/null >/dev/null 2>/dev/null ; then # GNU stat [ "$(stat -c"%s" "code0000")" = 0 ] && sortopt="" || sortopt="r" else # BSD stat [ "$(stat -f"%z" "code0000")" = 0 ] && sortopt="" || sortopt="r" fi # Start the pipeline with a simple list of split out temp filename. One file # per line. ls -1 docs[0-9]* code[0-9]* 2>/dev/null | # Now sort the list of files by the *number* first and then by the type. The # list will look something like this when `sort(1)` is done with it: # # docs0000 # code0000 # docs0001 # code0001 # docs0002 # code0002 # ... # sort -n -k"1.5" -k"1.1$sortopt" | # And if we pass those files to `cat(1)` in that order, it concatenates them # in exactly the way we need. `xargs(1)` reads from `stdin` and passes each # line of input as a separate argument to the program given. # # We could also have written this as: # # cat $(ls -1 docs* code* | sort -n -k1.5 -k1.1r) # # I like to keep things to a simple flat pipeline when possible, hence the # `xargs` approach. xargs cat | # Run a quick substitution on the embedded dividers to turn them into table # rows and cells. This also wraps each code block in a `
$1
$(cat) ` # so that the CSS kicks in properly. { DOCSDIVIDER='DIVIDER
' DOCSREPLACE='' CODEDIVIDER='# DIVIDER' CODEREPLACE=' ' sed " s@${DOCSDIVIDER}@${DOCSREPLACE}@ s@${CODEDIVIDER}@${CODEREPLACE}@ " } | # Pipe our recombined HTML into the layout and let it write the result to # `stdout`. layout "$title" # More # ---- # # **shocco** is the third tool in a growing family of quick-and-dirty, # literate-programming-style documentation generators: # # * [Docco][do] - The original. Written in CoffeeScript and generates # documentation for CoffeeScript, JavaScript, and Ruby. # * [Rocco][ro] - A port of Docco to Ruby. # # If you like this sort of thing, you may also find interesting Knuth's # massive body of work on literate programming: # # * [Knuth: Literate Programming][kn] # * [Literate Programming on Wikipedia][wi] # # [ro]: http://rtomayko.github.com/rocco/ # [do]: http://jashkenas.github.com/docco/ # [kn]: http://www-cs-faculty.stanford.edu/~knuth/lp.html # [wi]: http://en.wikipedia.org/wiki/Literate_programming # Copyright (C) [Ryan Tomayko](http://tomayko.com/about)
# This is Free Software distributed under the MIT license. :