raspiblitz/toc.sh
2022-02-10 22:08:46 +01:00

71 lines
3.0 KiB
Bash
Executable File

#!/usr/bin/env sh
## Updated version maintained on https://github.com/nyxnor/scripts/blob/master/toc.sh
## Produces Table of Contents (ToC) for simple markdown files
## Requirement: header is set by hashtag '#'
## $1 = FILE.md
red="\033[31m"
#nocolor="\033[0m"
error_msg(){ printf %s"${red}ERROR: ${1}\n" >&2; exit 1; }
test -f "${1}" || error_msg "file '${1}' doesn't exist"
trap 'rm -f toc.tmp' EXIT INT
line_count=0
while IFS="$(printf '\n')" read -r line; do
line_count=$((line_count+1))
## extract code blocks
code="${code:-0}"
[ "${code}" -eq 0 ] && printf '%s\n' "${line_count}:${line}" | grep "^${line_count}:.*# "
case "${line}" in
*\`\`\`*)
case "${code}" in
1) code=0;;
0|*) code=1;;
esac
;;
esac
done < "${1}" > toc.tmp
while IFS="$(printf '\n')" read -r line; do
## get line number
line_number="$(printf '%s\n' "${line}" | cut -d ":" -f1)"
## remove hashtag from line to be compared later if it is repeated
line_clean="$(printf '%s\n' "${line}" | sed "s/.*\# //")"
## save header to cache to check later if it was already printed
# shellcheck disable=SC2030
line_cache="$(printf '%s\n%s\n' "${line_cache}" "${line}")"
## check if header was already printed before and if positive, save all repeated headers
## if positive, insert link index
line_repeated="$(printf '%s\n' "${line_cache}" | grep -c -- ".*# ${line_clean}$")"
line_repeated_index=""
## first line does not have '-n', just the first repeated line (second occurence), starting with '-1'. So we consider the occurrence-1.
[ "${line_repeated}" -ge 2 ] && line_repeated_index="-$((line_repeated-1))"
## if it is the second time line has repeated, save first and second occurrence
if [ "${line_repeated}" -eq 2 ]; then
line_first_occurrence="$(printf '%s\n' "${line_cache}" | grep -- ".*# ${line_clean}$" | head -n 1)"
line_repeated_cache="$(printf '%s\n%s\n' "${line_first_occurrence}" "${line}")"
## if it is the third or greater time line has repeated, save lines from before (1st and 2nd occurrence) plus add current lines
elif [ "${line_repeated}" -gt 2 ]; then
line_repeated_cache="$(printf '%s\n%s\n' "${line_repeated_cache}" "${line}")"
fi
## clean header that have link reference
line_md="$(printf '%s\n' "${line}" | sed "s/${line_number}://;s|](.*||;s|\[||;s/\]//g")"
## set header indentation
line_md="$(printf '%s\n' "${line_md}" | sed "s|######| -|;s|#####| -|;s|####| -|;s|###| -|;s|##| -|;s|#|-|")"
## set link content
line_content="$(printf '%s\n' "${line_md}" | sed "s/.*- /#/;s| |-|g;s|'||g;s|]||g;s/|/-/g" | tr "[:upper:]" "[:lower:]" | tr -cd "[:alnum:]-._")"
## set link reference
line_md="$(printf '%s\n' "${line_md}" | sed "s|- |- [|;s|$|](#${line_content}${line_repeated_index})|")"
## print header
printf '%s\n' "${line_md}"
done < toc.tmp
[ -n "${line_repeated_cache}" ] &&
printf %s"\n\nWARN: Some headers are repeated, the hiperlinks are correctly indexed. If you think this is an error, review these lines:headers:\n${line_repeated_cache}\n"