1#! /usr/bin/env modernish
2#! use safe -k
3#! use sys/cmd/harden
4#! use var/string
5
6# Markdown table of contents generator. Reads a Markdown file and based on
7# the headers generates a table of contents in Markdown.
8#
9# Unfortunately, anchor tags are not standardised in Markdown. The default
10# Markdown program does not generate anchor tags at all, making links
11# inoperable. Multimarkdown and the Github website do support anchor tags,
12# but each use their own style. The Multimarkdown style is the default for
13# this program; the Github style is activated using the -g option.
14
15# die if these utilities fail; use those installed in default system PATH
16harden -p printf
17harden -p sed
18
19# parse options
20showusage() {
21	putln "Usage: $ME [ -g ] [ FILENAME ]"
22	putln "${CCt}-g: generate github-style anchors (default: multimarkdown)"
23} >&2
24unset -v opt_g
25while getopts g opt; do
26	case $opt in
27	( \? )	exit -u 1 ;;
28	( g )	opt_g=1 ;;
29	esac
30done
31shift $((OPTIND-1))
32
33# process options
34if isset opt_g; then
35	# github-style anchor tags
36	sed_mkanchor='s/^/user-content-/; s/[[:space:]]/-/g; s/[^[:alnum:]-]//g'
37else
38	# default: multimarkdown-style anchor tags
39	sed_mkanchor='s/[^[:alnum:]]//g'
40fi
41
42# parse arguments
43case $# in
44( 0 )	if is onterminal 0; then
45		exec < README.md || exit 1 "Cannot find README.md;" \
46			"provide file name argument or redirect standard input"
47	fi ;;
48( 1 )	exec < $1 || exit 1 "Cannot find $1" ;;
49( * )	exit 1 "Max 1 argument accepted" ;;
50esac
51
52# begin main program
53putln "## Table of contents ##" ""
54
55while read -r line; do
56
57	case $line in
58	( '## Table of contents'* )
59			continue ;;
60	( '######'* )	hdlevel=4 ;;
61	( '#####'* )	hdlevel=3 ;;
62	( '####'* )	hdlevel=2 ;;
63	( '###'* )	hdlevel=1 ;;
64	( '##'* )	hdlevel=0 ;;
65	( * )		continue ;;
66	esac
67
68	# trim leading and trailing '#' and whitespace characters
69	# (the trim function comes from the var/string module)
70	trim line \#$WHITESPACE
71
72	# convert the trimmed heading into an anchor string
73	anchor=$(putln $line | sed $sed_mkanchor)
74	tolower anchor
75
76	# print ToC entry with Markdown list indentation and anchor link
77	let "numspaces = 4 * hdlevel + 1"
78	printf "%${numspaces}s [%s](#%s)\n" '*' $line $anchor
79
80done
81