#!/bin/bash
# dev/docs/ref - package source reference support

set -e

lib_load 'dev/docs/rst'


######
# Source Line Processing

is_docs_marker() {
	is_docs_arg "$1" || is_docs_symbol || is_docs_section "$1"
}
is_docs_section() { [ "$1" = '#####' ]; }
is_docs_symbol() { [ "${1/ - /}" != "$1" ]; }
is_docs_arg() { [ "${1/\$[0-9\@] - /}" != "$1" -o "${1#... - }" != "$1" ]; }

# docs_readline() - Reads a line into the named var ($1)
# $1 - Variable name to receive line of documentation
docs_readline() {
	local var=$1
	local -n value=$var
	while true; do
		read $var || return

		value=${value##[ \t]}
		[ "$value" ] || continue

		if [ "${value#\#}" != "$value" ]; then
			value=${value#\#}
		elif echo "$value" | grep -q '^[a-z0-9_]+() '; then
			value="${value%%()*}()"
		elif echo "$value" | grep -q '^[a-z0-9_]+='; then
			value="\$${value%%=*}"
		else
			continue
		fi
		value=${value##[ \t\n]}
		break
	done
}

docs_gen_lines() {
	[ ${#docs_lines[*]} -gt 0 ] || return 0
	local IFS=$'\n'
	echo "${docs_lines[*]}"
	echo
	docs_lines=()
}


######
# Package Reference Documentation

package_docs_ref_clean() { run rm -rf "$package_docs_refdir"; }

docs_gen_files() {
	local -a files=( "$@" )
	[ "$*" ] || docs_file_list files src conf libs

	run_mkdir "$package_docs_refdir"
	for_each docs_gen_file "${files[@]}"
}

docs_gen_file() {
	local file=$1
	local base=${name%.in}

	local out=$(docs_filename "$package_docs_refdir" "$file" rst)
	file_mkdir "$out"

	local ext=''
	[ "${file/conf\//}" != "$file" ] || ext='.sh'

	local in="$package_gendir/${file/src\//bin\/}$ext"

	local name=${file#*/}
	info "$name: generating documentation..."
	if ! docs_gen_file_body "$file" <"$in" >"$out"; then
		error "$name: error generating documentation"
	fi
}


######
# Source File Processing

docs_gen_file_body() {
	local file=$1
	local name=${file#*/}

	local line
	docs_readline line

	if [ "!/bin/bash" = "$line" ]; then
		# discard shebang line, read next
		docs_readline line
	else
		warn "$name: $line: first line should be a shebang"
	fi
	docs_gen_file_title "$line"

	local docs_cur_state=sec
	local -a docs_lines

	docs_gen_file_header "$name"
	docs_gen_file_deps "$file"
	docs_gen_file_sections "$name"
}

docs_gen_file_title() {
	local line=$1
	local title=${line% - *}
	local desc=${line#* - }
	rst_title "$name" "$desc"
}

docs_gen_file_header() {
	local name=$1

	local line
	while docs_readline line; do
		if ! is_docs_section "$line"; then
			docs_lines+=( "$line" )
			continue
		fi
		if [ "${docs_lines[*]}" ]; then
			rst_h1 "File Description"
			docs_gen_lines
		fi
		docs_cur_state='sec'
		break
	done
}

docs_gen_file_deps() {
	local file=$1
	local dotfile=$(docs_filename "$package_docs_refdir" "$file" deps.svg)
#	[ -s "$dotfile" ] || return 0

	local name=${file#*/}

	local base=${file##*/}
	local dot="$base.deps.dot"
	local svg="$base.deps.svg"
	local pdf="$base.deps.pdf"
	local rst="$base.rst"
	local raw="$base.raw.html"

	cat <<DEPS
.. figure:: $svg
   :align: right
   :alt: Dependency Graph
   :width: 100%

   $(rst_literal "$name"): Library Dependencies

DEPS
	if [ -s "$dotfile" ]; then
		cat <<GRAPH
   View the full-size SVG (svg_) or PDF (pdf_) image or
   graphviz source (dot_)

   .. _svg: $svg
   .. _pdf: $pdf
   .. _dot: $dot

GRAPH
	fi

	cat <<RST
   View color source code (raw_) for this file

   .. _raw: $raw

   View reStructuredText (rst_) source code for this page

   .. _rst: $rst

RST
}


######
# Sections/Symbols/Arguments

docs_gen_file_sections() {
	local name=$1

	local docs_cur_section
	local docs_cur_symbol

	local line
	while docs_readline line; do
		case "$docs_cur_state" in
		(top)
			docs_gen_lines
			if is_docs_section "$line"; then
				docs_cur_section=''
				docs_cur_symbol=''
				docs_cur_state='sec'
			elif is_docs_arg "$line"; then
				docs_gen_file_sym_arg "$line"
			elif is_docs_symbol "$line"; then
				docs_gen_file_sym "$line"
				docs_cur_symbol="$line"
			elif [ "$docs_cur_section" ]; then
				line=$(rst_trim "$line")
				docs_lines+=( "$line" )
			elif [ "$line" ]; then
				warn "ignoring: $line"
			fi
			;;
		(sec)
			line=$(rst_trim "$line")
			docs_gen_file_section 2 "$line"
			docs_cur_section=$line
			docs_cur_state='top'
			;;
		(*)
			error "$state: unknown generator state"
			;;
		esac
	done
}

docs_gen_file_section() {
	min_args 2 "$@"
	local level=$1
	local title=$2
	local desc=$3

	title=$(rst_trim "$title")
	rst_header_n $level "$title"
	desc=$(rst_trim "$desc")
	if [ "$desc" ]; then
		rst_reflow "$desc"
		echo
	fi
}

docs_gen_file_sym() { docs_gen_file_section 3 "${1%% - *}" "${1#* - }"; }
docs_gen_file_sym_arg() {
	echo "- **${1%% - *}** ${1#* - }"
	echo
}


######
# HTML Documentation

docs_gen_html_files() {
	local -a files=( "$@" )
	[ "$*" ] || docs_file_list files libs src conf
	for_each docs_gen_html_file "${files[@]}"
}

docs_gen_html_file() {
	local file=$1
	local base=${file%.sh}
	local rst=$(docs_filename "$package_docs_refdir" "$base" rst)

	local tmp
	tmp=$(cmd_tempfile)
	{
		docs_rst_to_html "$rst"
		echo

		docs_gen_html_ref_footer
	} >"$tmp"

	local html=$(docs_filename "$package_docs_refdir" "$base" html)
	run mv "$tmp" "$html"
}

View the Script Reference Index


Generated on Tue Apr 25 21:20:28 PDT 2017 by mcsh i7 v0.18.0.