123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- #!/bin/sh
- #shellcheck disable=SC2039
-
- #
- # mdfmt - Markdown formatted output from your shell scripts
- #
- # These functions allow you to easily output a valid Markdown
- # from your script.
- #
-
- #
- # Default text width
- #
- # Most paragraph text will be re-formatted to not exceed this width.
- #
- MDFMT_WIDTH=${MDFMT_WIDTH:-75}
-
- _mdfmt__fmttype() {
- #
- # Format fragments $@ as type $Elem
- #
- case $Elem in
- h1)
- local hdr
- hdr=$(_mdfmt__join "$@")
- echo
- echo
- echo "$hdr"
- echo "$hdr" | tr -c '\n' =
- ;;
- h2)
- local hdr
- hdr=$(_mdfmt__join "$@")
- echo
- echo
- echo "$hdr"
- echo "$hdr" | tr -c '\n' -
- ;;
- h3)
- local hdr
- hdr=$(_mdfmt__join "$@")
- echo
- echo
- echo "### $hdr ###"
- ;;
- p)
- echo
- _mdfmt__join "$@" \
- | fmt -w "$(_mdfmt__width)"
- ;;
- ul)
- printf '\n * '
- _mdfmt__join "$@" \
- | fmt -t -w "$(_mdfmt__width)" \
- | sed -e 's/^ / /'
- ;;
- ol)
- printf '\n 1. '
- _mdfmt__join "$@" \
- | fmt -t -w "$(_mdfmt__width)" \
- | sed -e 's/^ / /'
- ;;
- pre)
- echo
- _mdfmt__join "$@" \
- | sed -e 's/^/ /'
- ;;
- esac
- }
-
- _mdfmt__indent() {
- #
- # Indent as many spaces as needed
- #
- local pfx
- test "$Nest" -eq 0 && { cat; return; }
- test "$Elem" == h1 && { cat; return; }
- test "$Elem" == h2 && { cat; return; }
- test "$Elem" == h3 && { cat; return; }
- pfx=$(
- #shellcheck disable=SC2034
- for n in $(seq 1 "$Nest"); do
- printf ' '
- done
- )
- sed "s/^/$pfx/"
- }
-
- _mdfmt__join() {
- #
- # Properly join text fragments $@
- #
- case $Elem in
- pre) printf '%s\n' "$@" ;;
- h*) echo "$1" ;;
- *) echo "$@" ;;
- esac
- }
-
- _mdfmt__quote() {
- #
- # Quote if needed
- #
- local pfx
- $Quoted || { cat; return; }
- test "$Elem" == h1 && { cat; return; }
- test "$Elem" == h2 && { cat; return; }
- test "$Elem" == h3 && { cat; return; }
- sed 's/^/> /'
- }
-
- _mdfmt__width() {
- #
- # Calculate width
- #
- echo "$((MDFMT_WIDTH - Nest * 4))"
- }
-
- mdfmt() {
- #
- # Format text as Markdown element $1
- #
- # Usage:
- # mdfmt [-n|--nest LEVEL] [-q|--quote] ELEM FRAG [FRAG..]
- #
- # Take text passed as one or more FRAGs and output it formatted in
- # Markdown as ELEM. Passing higher LEVEL than previous item causes
- # items to nest.
- #
- # When multiple FRAGs are provided, the text is simply joined together
- # (and in most cases re-formatted to fit $MDFMT_WIDTH). This allows
- # you to pass long texts and keep your code tidy by breaking the text
- # into several pieces and using line continuation character `\`.
- #
- # Additional character-level formatting is achieved using standard
- # Markdown motation, i.e. asterisk for emphasis, double asterisk
- # for strong emphasis and backtick for verbatim text.
- #
- # Options:
- #
- # * `-n LEVEL`, `--nest LEVEL` Causes item to be indented so that
- # it will be nested into the previous item, if the LEVEL is higher
- # than the previous one. Default value is zero.
- #
- # This can be used to e.g. include unordered items or code examples
- # inside ordered items, or multiple paragraphs per (un)ordered
- # item.
- #
- # * `-q`, `--quote` Causes item to appear blockquoted.
- #
- # Following values are available for ELEM (names are inspired by
- # HTML elements):
- #
- # * `h1`, `h2`, `h3` - headings of respective weight. Ignores
- # nesting. Accepts only single FRAG.
- #
- # * `p` - a paragraph.
- #
- # * `ul`, `ol` - unordered list item (bullet) or ordered (numbered)
- # list item.
- #
- # * `pre` - pre-formatted code. Multiple FRAGs are treated as lines
- # and spaces are preserved.
- #
- # Examples:
- #
- # mdfmt h1 "how to boil an egg"
- #
- # mdfmt p "this tutorial shows you how to boil an egg" \
- # "the best way possible"
- #
- # mdfmt h2 "variant 1"
- #
- # mdfmt ol "take egg"
- # mdfmt ol "put it in a pot full of water"
- # mdfmt ol "place pot onto stove"
- # mdfmt ol "turn on stove"
- # mdfmt ol "wait"
- # mdfmt --nest 1 ul "for hard-boiled, wait 10 minutes"
- # mdfmt --nest 1 ul "for soft-boiled, wait 3 minutes"
- # mdfmt ol "turn off the stove"
- # mdfmt ol "replace water with cold water "
- # mdfmt ol "break and replace shell from the egg"
- #
- # mdfmt h2 "variant 1"
- #
- # mdfmt ol "start your favorite browser"
- # mdfmt ol "open youtube:"
- # mdfmt --nest 1 pre "https://www.youtube.com/"
- # mdfmt ol "enter following text in Search box:"
- # mdfmt --nest 1 pre "how to boil an egg"
- # mdfmt ol "watch at least 5 videos"
- # mdfmt ol "go to the closest restaurant and ask for" \
- # "a boiled egg"
- #
- # mdfmt h2 "conclusion"
- #
- # mdfmt p "We hope you enjoy the egg. Seriously."
- #
- local Nest=0
- local Elem
- local Quoted=false
- local usage="usage: mdfmt [-n|--nest LVL] ELEM FRAG [FRAG..]"
- while true; do case $1 in
- -n|--nest)
- Nest=$2
- shift 2 || {
- echo "$usage" >&2
- return 2
- }
- ;;
- -q|--quote)
- Quoted=true
- shift
- ;;
- -*)
- echo "$usage" >&2
- return 2
- ;;
- *)
- break
- ;;
- esac done
- Elem=$1; shift
- case $Elem in
- h1|h2|h3|p|ol|ul|pre)
- true
- ;;
- *)
- echo "$usage" >&2
- return 2
- ;;
- esac
- _mdfmt__fmttype "$@" \
- | _mdfmt__quote \
- | _mdfmt__indent
- }
|