#!/usr/bin/env dash # FAKE_COMPAT # NOTE: a lot of boilerplate code is pulled from the pure sh bible: # https://github.com/dylanaraps/pure-sh-bible document2() { local c=0 # line count local d="#""#""#" # marker/delimiter, written this way to avoid self-matching # NOTE: since the marker corresponds to a

in markdown, it's used there too. local e="${f#sh/}" # function name to expect local f="$1" # file local o=1 # when one, previous line was a one-liner (@- token). [ "$f" != "$e" ] || e="" # only expect function names for stuff in sh/ while IFS= read -r line; do : $((c+=1)) $((o+=1)) # we only care about lines with our docstring marker in them: case "$line" in *"$d"*) :;; *) continue;; esac # split by the marker: local code="${line%%$d*}" docs="${line#*$d}" code="${code#${code%%[! ]*}}" # ltrim docs="${docs# }" # ltrim a single space local s=' ' n='' # using a space to signify unset case "$docs" in @-*) s="$code" n="${s%%[!a-zA-Z0-9_-]*}" # substr first word (might not be one) while [ -z "$n" -o "$n" = function -o "$n" = alias ]; do [ -n "$s" ] || break s="${s#${s%%[!a-zA-Z0-9_-]*}}" # lstrip to end of word s="${s#*[!a-zA-Z0-9_-]}" # lstrip to next word n="${s%%[!a-zA-Z0-9_-]*}" # substr that word done s="${docs#@-}" # substr the stuff after the hyphen s="${s#${s%%[! ]*}}" # ltrim [ -z "$s" ] || o=0 ;; @*-*) # split by the hyphen: n="${docs%%-*}" s="${docs#*-}" n="${n#@}" # substr the stuff after the at n="${n#${n%%[! ]*}}" # ltrim n="${n%${n##*[! ]}}" # rtrim s="${s#${s%%[! ]*}}" # ltrim [ -z "$s" ] || o=0 ;; @*) n="${docs#@}" # substr the stuff after the at n="${n#${n%%[! ]*}}" # ltrim ;; *) s="$docs" # leave whitespace intact ;; esac if [ -n "$n" ]; then local url= # different subdirs need to be handled differently: [ "$f" != "${f#sh/}" ] && url="/sh/${f#sh/}#L$c" || url="/home/${f#.}#L$c" if [ "$n" = "$e" ]; then # function name matches the filename. printf '\n%s [%s](%s)\n\n' "$d" "$n" "$url" || return 5 else # this file contains some other function, so include the filename. printf '\n%s [%s](%s)\n\n' "$d" "$n (${f#.})" "$url" || return 5 #printf '\n%s %s\n\n* defined in [%s](%s)\n\n' "%d" "$n" "$f" "$url" || return 5 fi fi if [ "$s" != ' ' ]; then # don't bother unless it was set to something if [ -z "$n" -o -n "$s" ]; then # might only be a name, check that # just pass the remaining comment through: if [ $o = 1 ]; then # ensure one-liners are their in their own paragraph. printf '\n' || return 5 fi printf '%s\n' "$s" || return 5 fi fi done < "$f" || return 4 } document1() { # NOTE: in the future, it'd be nice to support arbitary files through arguments. local in_='rc/README.md' local out='rc/README.md~' if [ $# -eq 0 ]; then cd || return 2 [ -d rc ] || return 3 # sanity check elif [ $# -eq 1 ]; then in_='README.md' out='README.md~' cd "$1" || return 2 else return 1 fi # sanity check: [ -d sh ] && [ -f .zshrc ] && [ -f .shrc ] && [ -f .bashrc ] || return 3 # create new output file (with a tilde as not to overwrite just yet): : > "$out" || return 4 local line= if [ -f "$in_" ]; then # copy existing lines up to (and including) the "DOCUMENT" marker: while IFS= read -r line; do printf '%s\n' "$line" >> "$out" || return 5 case "$line" in *DOCUMENT*) break;; esac done < "$in_" || return 4 fi # first section: printf '\n## %s\n' 'shell functions' >> "$out" || return 5 for f in sh/*; do [ -e "$f" ] || continue # make sure glob went through local fn="${f##*/}" # ignore some stuff: [ "$fn" = "${fn#_}" ] || continue # completion files [ "$fn" = "${fn%.bak}" ] || continue # backup files document2 "$f" >> "$out" || return done # second section: printf '\n## %s\n' 'miscellaneous' >> "$out" || return 5 document2 .zshrc >> "$out" || return document2 .bashrc >> "$out" || return document2 .shrc >> "$out" || return } document() { ### @- ### generate a markdown file out of docstrings in shell scripts. ### ### **TODO:** describe. i have a rough outline written in my scrap file. document1 "$@" local ret=$? case $ret in 0) return 0;; 1) printf '%s\n' "$0: too many arguments" >&2 return 1;; 2) printf '%s\n' "$0: failed to change directory" >&2 return 1;; 3) printf '%s\n' "$0: essential files are missing" >&2 return 1;; 4) printf '%s\n' "$0: failed to open file" >&2 return 1;; 5) printf '%s\n' "$0: failed to read line" >&2 return 1;; *) printf '%s\n' "$0: unknown error occurred" >&2 return 1;; esac } [ -n "${preload+-}" ] || document "$@"