bat-extras/mdroff.sh

279 lines
5.4 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# -----------------------------------------------------------------------------
# bat-extras | Copyright (C) 2020 eth-p | MIT License
#
# Repository: https://github.com/eth-p/bat-extras
# Issues: https://github.com/eth-p/bat-extras/issues
# -----------------------------------------------------------------------------
printf_msg() {
printf "$@" 1>&2
}
printf_err() {
printf "$@" 1>&2
}
# -----------------------------------------------------------------------------
# MDroff:
# -----------------------------------------------------------------------------
mdroff:emit:h1() {
printf '.TH "%s" 1\n' "$1"
}
mdroff:emit:h2() {
printf '.SH "%s"\n' "$1"
}
mdroff:emit:h3() {
echo "$1"
}
mdroff:emit:h4() {
echo "$1"
}
mdroff:emit:h5() {
echo "$1"
}
mdroff:emit:line() {
if "$MDROFF_PARAGRAPH"; then
MDROFF_PARAGRAPH=false
printf ".P\n%s\n" "$1"
else
printf ".br\n%s\n" "$1"
fi
}
mdroff:emit:attr() {
printf '\\fR'
if "$MDROFF_ATTR_STRONG"; then
printf '\\fB'
fi
if "$MDROFF_ATTR_EMPHASIS"; then
printf '\\fI'
fi
}
mdroff:emit:link() {
printf "%s" "$1"
}
mdroff:emit:table_heading() {
printf '.P\n\\fB'
printf '%s ' "$@"
printf '\\fR\n'
# Emit separator.
printf '.br\n'
local cell
for cell in "$@"; do
printf "%$(wc -c <<< "$cell")s" '' | tr ' ' '-'
printf " "
done
printf "\n"
}
mdroff:emit:table_row() {
printf '.br\n'
printf '%s ' "$@"
printf '\n'
}
mdroff:emit() {
local type="$1"
local data="$2"
if type "mdroff:rewrite:${type}" &>/dev/null; then
data="$("mdroff:rewrite:${type}" "${@:2}")"
fi
if type "mdroff:emit_hook:${type}" &>/dev/null; then
"mdroff:emit_hook:${type}" "$data" "${@:3}"
return
fi
"mdroff:emit:${type}" "$data" "${@:3}"
}
mdroff:parseln() {
MDROFF_ATTR_STRONG=false
MDROFF_ATTR_EMPHASIS=false
local buffer="$1"
local before
local found
local pos
while [[ "${#buffer}" -gt 0 ]]; do
[[ "$buffer" =~ \*{1,3}|\[([^\]]+)\]\(([^\)]+)\) ]] || {
printf "%s\n" "$buffer"
return
}
found="${BASH_REMATCH[0]}"
pos="$(awk -v search="$found" '{print index($0,search) - 1}' <<< "$buffer")"
before="${buffer:0:$pos}"
buffer="${buffer:$(($pos + ${#found}))}"
printf "%s" "$before"
case "$found" in
'***')
if "$MDROFF_ATTR_STRONG" && "$MDROFF_ATTR_EMPHASIS"; then
MDROFF_ATTR_STRONG=false
MDROFF_ATTR_EMPHASIS=false
else
MDROFF_ATTR_STRONG=true
MDROFF_ATTR_EMPHASIS=true
fi
mdroff:emit attr
;;
'**')
if "$MDROFF_ATTR_STRONG"; then
MDROFF_ATTR_STRONG=false
else
MDROFF_ATTR_STRONG=true
fi
mdroff:emit attr
;;
'*')
if "$MDROFF_ATTR_EMPHASIS"; then
MDROFF_ATTR_EMPHASIS=false
else
MDROFF_ATTR_EMPHASIS=true
fi
mdroff:emit attr
;;
'['*)
mdroff:emit link "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
esac
done
}
mdroff() {
MDROFF_HEADING_LEVEL=0
MDROFF_HEADING=''
MDROFF_ATTR_STRONG=false
MDROFF_ATTR_EMPHASIS=false
MDROFF_IN_TABLE=false
MDROFF_PARAGRAPH=false
local line
local empty=0
local empty_continue=0
while IFS='' read -r line; do
line="$(mdroff:parseln "$line")"
# Empty
if [[ "$line" =~ ^[[:space:]]*$ ]]; then
((empty_continue++)) || true
MDROFF_PARAGRAPH=true
MDROFF_IN_TABLE=false
continue
fi
empty="$empty_continue"
empty_continue=0
# Headings
if [[ "$line" =~ ^(#{1,})[[:space:]]{1,}(.*)$ ]]; then
local level="${#BASH_REMATCH[1]}"
local text="${BASH_REMATCH[2]}"
MDROFF_HEADING_LEVEL="$level"
MDROFF_HEADING="$text"
mdroff:emit "h${level}" "$text"
MDROFF_PARAGRAPH=true
continue
fi
# Tables (Partially Supported)
if [[ "$line" =~ ^[[:space:]]*\| ]]; then
local cells=()
line="$(sed 's/^[[:space:]]*|//; s/|[[:space:]]*$//' <<< "$line")"
# shellcheck disable=SC2206
IFS='|' cells=($line)
if [[ "${cells[0]}" =~ ^[[:space:]]*-+[[:space:]]*$ ]]; then
continue
fi
if ! "$MDROFF_IN_TABLE"; then
MDROFF_IN_TABLE=true
mdroff:emit table_heading "${cells[@]}"
else
mdroff:emit table_row "${cells[@]}"
fi
MDROFF_PARAGRAPH=true
continue
fi
mdroff:emit line "$line"
done < <(sed 's/<br *\/?>//')
}
# -----------------------------------------------------------------------------
# bat-extras:
# -----------------------------------------------------------------------------
mdroff:rewrite:h1() {
emitted_name=false
emitted_description=false
sed 's/^bat-extras: //' <<< "$1" | tr '[[:lower:]]' '[[:upper:]]'
}
mdroff:emit_hook:h2() {
case "$MDROFF_HEADING" in
"Installation") return ;;
"Issues?") return ;;
esac
mdroff:emit:h2 "$(tr '[[:lower:]]' '[[:upper:]]' <<< "$1")"
}
mdroff:emit_hook:line() {
if [[ "$MDROFF_HEADING_LEVEL" = "1" ]] && [[ "$emitted_name" != true ]]; then
emitted_name=true
printf ".SH NAME\n%s - %s\n" "$(sed 's/^bat-extras: //' <<< "$MDROFF_HEADING" | tr '[[:upper:]]' '[[:lower:]]')" "$1"
printf ".SH DESCRIPTION\n"
return
fi
case "$MDROFF_HEADING" in
"Installation") return ;;
"Issues?") return ;;
esac
mdroff:emit:line "$@"
}
# -----------------------------------------------------------------------------
# Main:
# -----------------------------------------------------------------------------
if [[ "${#BASH_SOURCE[@]}" -eq 1 ]]; then
case "$1" in
"") mdroff ;;
*) {
if ! [ -f "$1" ]; then
printf_err "%s: cannot find or read file %s\n" "$0" "$1"
exit 1;
fi
mdroff < "$1"
} ;;
esac
fi