mirror of
https://github.com/eth-p/bat-extras.git
synced 2025-01-06 13:18:51 +01:00
build: Add experimental support for generating manpages
This commit is contained in:
parent
85c4cfbfe8
commit
9f6e5c0164
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,3 +10,4 @@
|
||||
/.circleci/.config.yml
|
||||
.download
|
||||
bin
|
||||
man
|
||||
|
@ -86,6 +86,14 @@ If you only want to install a single script, you can run the build process and c
|
||||
|
||||
|
||||
|
||||
**Manuals:** (EXPERIMENTAL)
|
||||
|
||||
You can specify `--manuals` to have the build script generate a `man` page for each of the markdown documentation files.
|
||||
This is an experimental feature that uses a non-compliant Markdown "parser" written in Bash, and there is no guarantee
|
||||
as for the quality of the generated manual pages.
|
||||
|
||||
|
||||
|
||||
**Alternate Executable:**
|
||||
|
||||
Depending on the distribution, bat may have been renamed to avoid package conflicts.
|
||||
|
28
build.sh
28
build.sh
@ -8,6 +8,8 @@
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BIN="$HERE/bin"
|
||||
SRC="$HERE/src"
|
||||
MAN="$HERE/man"
|
||||
MAN_SRC="$HERE/doc"
|
||||
LIB="$HERE/lib"
|
||||
source "${LIB}/print.sh"
|
||||
source "${LIB}/opt.sh"
|
||||
@ -363,6 +365,7 @@ OPT_INSTALL=false
|
||||
OPT_COMPRESS=false
|
||||
OPT_VERIFY=true
|
||||
OPT_BANNER=true
|
||||
OPT_MANUALS=false
|
||||
OPT_MINIFY="lib"
|
||||
OPT_PREFIX="/usr/local"
|
||||
OPT_BAT="$(basename "$EXECUTABLE_BAT")"
|
||||
@ -375,6 +378,7 @@ while shiftopt; do
|
||||
case "$OPT" in
|
||||
--install) OPT_INSTALL=true ;;
|
||||
--compress) OPT_COMPRESS=true ;;
|
||||
--manuals) OPT_MANUALS=true ;;
|
||||
--no-verify) OPT_VERIFY=false ;;
|
||||
--no-banner) OPT_BANNER=false ;;
|
||||
--prefix) shiftval; OPT_PREFIX="$OPT_VAL" ;;
|
||||
@ -427,6 +431,30 @@ for file in "$SRC"/*.sh; do
|
||||
SOURCES+=("$file")
|
||||
done
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Build manuals.
|
||||
|
||||
if "$OPT_MANUALS"; then
|
||||
source "${HERE}/mdroff.sh"
|
||||
if ! [[ -d "$MAN" ]]; then
|
||||
mkdir -p "$MAN"
|
||||
fi
|
||||
|
||||
printc_msg "%{YELLOW}Building manuals...%{CLEAR}\n"
|
||||
for source in "${SOURCES[@]}"; do
|
||||
name="$(basename "$source" .sh)"
|
||||
doc="${MAN_SRC}/${name}.md"
|
||||
docout="${MAN}/${name}.1"
|
||||
if ! [[ -f "$doc" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
printc_msg " %{YELLOW} %{MAGENTA}%s%{CLEAR}\n" "$(basename "$docout")"
|
||||
(mdroff < "$doc" > "${MAN}/${name}.1")
|
||||
done
|
||||
printc_msg "\n"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Build files.
|
||||
|
||||
|
278
mdroff.sh
Executable file
278
mdroff.sh
Executable file
@ -0,0 +1,278 @@
|
||||
#!/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
|
Loading…
Reference in New Issue
Block a user