#!/usr/bin/env bash
################################
# This script can be used to read a markdown file and generate a table of contents using Github.
#
# USAGE: generate_table_of_contents [file]
#
# Place <!--ts--> where you want the table of contents to start.
# Place <!--te--> where you want the table of contents to end.
#
################################
# Converts local md file into html by GitHub
gh_toc_md2html() {
local gh_file_md=$1
URL=https://api.github.com/markdown/raw
OUTPUT="$(curl -s --data-binary @"$gh_file_md" -H "Content-Type:text/plain" $URL)"
if [ "$?" != "0" ]; then
echo "XXNetworkErrorXX"
fi
if [ "$(echo "${OUTPUT}" | awk '/API rate limit exceeded/')" != "" ]; then
echo "XXRateLimitXX"
else
echo "${OUTPUT}"
fi
}
# TOC generator
gh_toc(){
local gh_src=$1
local gh_src_copy=$1
local gh_ttl_docs=$2
if [ "$gh_src" = "" ]; then
echo "Please, enter URL or local path for a README.md"
return
fi
local rawhtml=$(gh_toc_md2html "$gh_src")
if [ "$rawhtml" == "XXNetworkErrorXX" ]; then
echo "Parsing local markdown file requires access to github API"
echo "Please make sure curl is installed and check your network connectivity"
return
fi
if [ "$rawhtml" == "XXRateLimitXX" ]; then
echo "Parsing local markdown file requires access to github API"
echo "Error: You exceeded the hourly limit. See: https://developer.github.com/v3/#rate-limiting"
return
fi
local toc=`echo "$rawhtml" | gh_toc_grab "$gh_src_copy"`
if grep -Fxq "<!--ts-->" $gh_src && grep -Fxq "<!--te-->" $gh_src; then
:
else
echo "You don't have <!--ts--> or <!--te--> in your file...exiting"
return
fi
local ts="<\!--ts-->"
local te="<\!--te-->"
local dt=`date +'%F_%H%M%S'`
local ext=".orig.${dt}"
local toc_path="${gh_src}.toc.${dt}"
sed -i${ext} "/${ts}/,/${te}/{//!d;}" "$gh_src" # clear old TOC
echo "${toc}" > "${toc_path}" # create toc file
if [[ "`uname`" == "Darwin" ]]; then # insert toc file
sed -i "" "/${ts}/r ${toc_path}" "$gh_src"
else
sed -i "/${ts}/r ${toc_path}" "$gh_src"
fi
rm "${gh_src}${ext}"
rm "${toc_path}"
}
# Gets the TOC from the rendered html
gh_toc_grab() {
# if closed <h[1-6]> is on the new line, then move it on the prev line
# for example:
# was: The command <code>foo1</code>
# </h1>
# became: The command <code>foo1</code></h1>
sed -e ':a' -e 'N' -e '$!ba' -e 's/\n<\/h/<\/h/g' |
grep -E -o '<a.*id="user-content-[^"]*".*</h[2-6]' | # find strings that corresponds to template
sed 's/<code>//g' | sed 's/<\/code>//g' | # remove code tags
# now all rows are like:
# <a id="user-content-..." href="..."><span ...></span></a> ... </h1
# format result line
# * $0 — whole string
# * last element of each row: "</hN" where N in (1,2,3,...)
echo "$(awk -v "gh_url=$1" '{
level = substr($0, length($0), 1)-2
text = substr($0, match($0, /a>.*<\/h/)+2, RLENGTH-5)
href = substr($0, match($0, "href=\"[^\"]+?\"")+6, RLENGTH-7)
print sprintf("%*s", level*2, "") "* [" text "](" href ")" }' |
sed 'y/+/ /; s/%/\\x/g')"
}
main() {
for md in "$@"
do
gh_toc "$md" "$#"
done
}
main "$@"