132 lines
2.8 KiB
Bash
Executable File
132 lines
2.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
printf 'Usage: %s INPUT_DIR [OUTPUT_DIR]\n' "$(basename "$0")" >&2
|
|
exit 2
|
|
}
|
|
|
|
[[ $# -ge 1 && $# -le 2 ]] || usage
|
|
|
|
input_dir=${1%/}
|
|
[[ -d "$input_dir" ]] || {
|
|
printf 'error: input is not a directory: %s\n' "$input_dir" >&2
|
|
exit 1
|
|
}
|
|
|
|
parent_dir=$(dirname "$input_dir")
|
|
input_base=$(basename "$input_dir")
|
|
output_dir=${2:-"$parent_dir/${input_base}-markdown"}
|
|
output_dir=${output_dir%/}
|
|
|
|
lang_for_file() {
|
|
local file=$1
|
|
local base ext shebang
|
|
|
|
base=$(basename "$file")
|
|
|
|
case "$base" in
|
|
flake.lock) echo json; return ;;
|
|
Dockerfile|Containerfile) echo dockerfile; return ;;
|
|
Makefile) echo makefile; return ;;
|
|
esac
|
|
|
|
ext="${base##*.}"
|
|
|
|
case "$ext" in
|
|
nix) echo nix ;;
|
|
sh|bash) echo bash ;;
|
|
zsh) echo zsh ;;
|
|
fish) echo fish ;;
|
|
py) echo python ;;
|
|
js|mjs|cjs) echo javascript ;;
|
|
ts|mts|cts) echo typescript ;;
|
|
json) echo json ;;
|
|
jsonc) echo jsonc ;;
|
|
yaml|yml) echo yaml ;;
|
|
toml) echo toml ;;
|
|
md|markdown) echo markdown ;;
|
|
lua) echo lua ;;
|
|
vim) echo vim ;;
|
|
conf|cfg|ini) echo ini ;;
|
|
service|timer|socket|mount|target) echo systemd ;;
|
|
env) echo dotenv ;;
|
|
css) echo css ;;
|
|
html|htm) echo html ;;
|
|
rs) echo rust ;;
|
|
go) echo go ;;
|
|
c) echo c ;;
|
|
h) echo c ;;
|
|
cpp|cc|cxx|hpp|hh|hxx) echo cpp ;;
|
|
java) echo java ;;
|
|
sql) echo sql ;;
|
|
xml) echo xml ;;
|
|
*)
|
|
if IFS= read -r shebang < "$file" && [[ "$shebang" == '#!'* ]]; then
|
|
case "$shebang" in
|
|
*bash*) echo bash ;;
|
|
*zsh*) echo zsh ;;
|
|
*sh*) echo sh ;;
|
|
*python*) echo python ;;
|
|
*node*) echo javascript ;;
|
|
*) echo text ;;
|
|
esac
|
|
else
|
|
echo text
|
|
fi
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Pick a fence longer than any run of backticks in the file.
|
|
fence_for_file() {
|
|
local file=$1
|
|
local max_ticks=2
|
|
|
|
# Finds all runs of backticks, sorts by length, returns longest length.
|
|
local longest
|
|
longest=$(
|
|
grep -ao '`*' "$file" 2>/dev/null \
|
|
| awk '{ print length }' \
|
|
| sort -nr \
|
|
| head -n1
|
|
)
|
|
|
|
if [[ -n "${longest:-}" && "$longest" -gt "$max_ticks" ]]; then
|
|
max_ticks=$longest
|
|
fi
|
|
|
|
printf '%*s' "$((max_ticks + 1))" '' | tr ' ' '`'
|
|
}
|
|
|
|
mkdir -p "$output_dir"
|
|
|
|
find "$input_dir" -type f -print0 |
|
|
while IFS= read -r -d '' src; do
|
|
rel=${src#"$input_dir"/}
|
|
dest="$output_dir/$rel.md"
|
|
dest_dir=$(dirname "$dest")
|
|
|
|
mkdir -p "$dest_dir"
|
|
|
|
# Skip likely-binary files.
|
|
if ! grep -Iq . "$src"; then
|
|
printf 'skip binary: %s\n' "$rel" >&2
|
|
continue
|
|
fi
|
|
|
|
lang=$(lang_for_file "$src")
|
|
fence=$(fence_for_file "$src")
|
|
|
|
# Backticks are forbidden in CommonMark info strings.
|
|
safe_rel=${rel//\`/\'}
|
|
|
|
{
|
|
printf '%s%s %s\n' "$fence" "$lang" "$safe_rel"
|
|
cat "$src"
|
|
printf '\n%s\n' "$fence"
|
|
} > "$dest"
|
|
|
|
printf 'wrote: %s\n' "$dest"
|
|
done
|