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