mirror of
https://github.com/logos-co/logos-libp2p-module.git
synced 2026-08-31 01:41:12 +00:00
254 lines
7.0 KiB
Bash
Executable File
254 lines
7.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# generate_markdown.sh
|
|
#
|
|
# Extracts embedded documentation from tutorial C++ source files
|
|
# and generates standalone Markdown files into tutorial/docs/.
|
|
#
|
|
# Conventions:
|
|
# - Lines starting with `///` (column 0) = documentation (Markdown)
|
|
# - All other lines = C++ code
|
|
#
|
|
# Navigation: prev/next links are auto-appended at the bottom of each
|
|
# generated Markdown file, using the tutorial's own title (from the
|
|
# `/// # Tutorial N: Title` first line) as link text.
|
|
#
|
|
# Usage:
|
|
# ./generate_markdown.sh # generate all .md files
|
|
# ./generate_markdown.sh tutorial_1.cpp # generate a single file
|
|
#
|
|
# Output: tutorial/docs/tutorial_<name>.md for each input file
|
|
#
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
|
OUTPUT_DIR="${SCRIPT_DIR}/docs"
|
|
SRC_DIR="${SCRIPT_DIR}"
|
|
|
|
# --- discover tutorials dynamically ---
|
|
|
|
# Returns lines of "number|stem|title" sorted by number, e.g.:
|
|
# 1|tutorial_1_node_lifecycle|Creating and Starting a libp2p Node
|
|
discover_tutorials() {
|
|
local dir="$1"
|
|
for f in "$dir"/tutorial_*.cpp; do
|
|
[[ -f "$f" ]] || continue
|
|
local base
|
|
base="$(basename "$f" .cpp)"
|
|
|
|
# Extract number: the first number after "tutorial_"
|
|
local num
|
|
num="${base#tutorial_}"
|
|
num="${num%%[!0-9]*}"
|
|
|
|
# Extract title from the first line: "/// # Tutorial N: Title"
|
|
local first_line
|
|
local title
|
|
IFS= read -r first_line < "$f" || first_line=""
|
|
if [[ "$first_line" == "/// # Tutorial "*": "* ]]; then
|
|
title="${first_line#*: }"
|
|
else
|
|
title="$first_line"
|
|
fi
|
|
title="${title#"${title%%[![:space:]]*}"}"
|
|
title="${title%"${title##*[![:space:]]}"}"
|
|
if [[ -z "$title" ]]; then
|
|
# Fallback: derive from filename stem
|
|
local stem
|
|
stem="${base#tutorial_${num}_}"
|
|
stem="${stem//_/ }"
|
|
title=""
|
|
local word
|
|
local first
|
|
for word in $stem; do
|
|
first="${word:0:1}"
|
|
title+="${first^^}${word:1} "
|
|
done
|
|
title="${title% }"
|
|
fi
|
|
|
|
printf '%s|%s|%s\n' "$num" "$base" "$title"
|
|
done | sort -t'|' -k1 -n
|
|
}
|
|
|
|
# Build arrays by reading discovered tutorials
|
|
TUTORIAL_STEMS=()
|
|
TUTORIAL_NAMES=()
|
|
TUTORIAL_NUMBERS=()
|
|
|
|
populate_tutorials() {
|
|
local idx=0
|
|
while IFS='|' read -r num stem title; do
|
|
TUTORIAL_NUMBERS[$idx]="$num"
|
|
TUTORIAL_STEMS[$idx]="$stem"
|
|
TUTORIAL_NAMES[$idx]="$title"
|
|
idx=$((idx + 1))
|
|
done < <(discover_tutorials "$SRC_DIR")
|
|
}
|
|
|
|
# --- helpers ---
|
|
|
|
# Get index in the ordered array for a given filename
|
|
tutorial_index() {
|
|
local src="$1"
|
|
local base
|
|
base="$(basename "$src" .cpp)"
|
|
local num
|
|
num="${base#tutorial_}"
|
|
num="${num%%[!0-9]*}"
|
|
|
|
for i in "${!TUTORIAL_NUMBERS[@]}"; do
|
|
if [[ "${TUTORIAL_NUMBERS[$i]}" == "$num" ]]; then
|
|
printf '%s\n' "$i"
|
|
return 0
|
|
fi
|
|
done
|
|
printf '%s\n' "-1"
|
|
return 1
|
|
}
|
|
|
|
# Convert a tutorial filename to its markdown name
|
|
md_name() {
|
|
local base
|
|
base="$(basename "$1" .cpp)"
|
|
printf '%s.md\n' "$base"
|
|
}
|
|
|
|
# --- generate a single tutorial ---
|
|
generate() {
|
|
local src="$1"
|
|
local base_name
|
|
base_name="$(basename "$src")"
|
|
local md="${OUTPUT_DIR}/$(md_name "$src")"
|
|
|
|
mkdir -p "${OUTPUT_DIR}"
|
|
printf ' -> %s -> docs/%s\n' "$base_name" "$(basename "${md}")"
|
|
|
|
# Determine nav links from ordered list
|
|
local idx
|
|
idx="$(tutorial_index "$src")"
|
|
local prev_link=""
|
|
local next_link=""
|
|
local prev_title=""
|
|
local next_title=""
|
|
|
|
if [[ "$idx" -gt 0 ]]; then
|
|
local prev_i=$((idx - 1))
|
|
prev_link="${TUTORIAL_STEMS[$prev_i]}.md"
|
|
prev_title="${TUTORIAL_NAMES[$prev_i]}"
|
|
fi
|
|
|
|
if [[ "$idx" -lt "$(( ${#TUTORIAL_NUMBERS[@]} - 1 ))" ]]; then
|
|
local next_i=$((idx + 1))
|
|
next_link="${TUTORIAL_STEMS[$next_i]}.md"
|
|
next_title="${TUTORIAL_NAMES[$next_i]}"
|
|
fi
|
|
|
|
# State machine: DOC (/// at col 0) or CODE
|
|
local state="DOC"
|
|
local code_content=""
|
|
|
|
flush_code() {
|
|
if [[ -n "$code_content" ]]; then
|
|
printf '```cpp\n'
|
|
printf '%s' "$code_content"
|
|
printf '```\n\n'
|
|
code_content=""
|
|
fi
|
|
}
|
|
|
|
nav_text() {
|
|
local href="$2"
|
|
local text="$3"
|
|
|
|
if [[ -n "$href" ]]; then
|
|
printf '<a href="%s">%s</a>' "$href" "$text"
|
|
fi
|
|
}
|
|
|
|
{
|
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
# Doc comment: /// at column 0
|
|
if [[ "$line" == ///* ]]; then
|
|
if [[ "$state" == "CODE" ]] || [[ "$state" == "CODE_BLANK" ]]; then
|
|
flush_code
|
|
fi
|
|
state="DOC"
|
|
|
|
local md_line
|
|
md_line="${line#///}"
|
|
md_line="${md_line# }"
|
|
printf '%s\n' "$md_line"
|
|
|
|
# Blank line
|
|
elif [[ "$line" =~ ^[[:space:]]*$ ]]; then
|
|
if [[ "$state" == "CODE" ]]; then
|
|
state="CODE_BLANK"
|
|
code_content+="${line}"$'\n'
|
|
elif [[ "$state" == "CODE_BLANK" ]]; then
|
|
code_content+="${line}"$'\n'
|
|
elif [[ "$state" == "DOC" ]]; then
|
|
printf '\n'
|
|
fi
|
|
|
|
# Code line
|
|
else
|
|
if [[ "$state" == "DOC" ]]; then
|
|
flush_code
|
|
state="CODE"
|
|
elif [[ "$state" == "CODE_BLANK" ]]; then
|
|
state="CODE"
|
|
fi
|
|
code_content+="${line}"$'\n'
|
|
fi
|
|
done < "$src"
|
|
|
|
# Flush any remaining code at EOF
|
|
if [[ "$state" == "CODE" ]] || [[ "$state" == "CODE_BLANK" ]]; then
|
|
flush_code
|
|
fi
|
|
|
|
# Append navigation links
|
|
printf '%s\n\n' "---"
|
|
if [[ -n "$prev_link" ]] || [[ -n "$next_link" ]]; then
|
|
printf '<p align="center">'
|
|
nav_text "left" "$prev_link" "← ${prev_title}"
|
|
if [[ -n "$prev_link" ]] && [[ -n "$next_link" ]]; then
|
|
printf ' | '
|
|
fi
|
|
nav_text "right" "$next_link" "${next_title} →"
|
|
printf '</p>\n'
|
|
fi
|
|
|
|
} > "$md"
|
|
}
|
|
|
|
# --- main ---
|
|
|
|
# Discover tutorials dynamically
|
|
populate_tutorials
|
|
|
|
printf 'Discovered %s tutorials:\n' "${#TUTORIAL_NUMBERS[@]}"
|
|
for i in "${!TUTORIAL_NUMBERS[@]}"; do
|
|
printf ' %s: %s\n' "${TUTORIAL_NUMBERS[$i]}" "${TUTORIAL_NAMES[$i]}"
|
|
done
|
|
printf '\n'
|
|
|
|
if [[ $# -eq 0 ]]; then
|
|
printf '%s\n\n' "Generating markdown from all tutorials..."
|
|
for src in "${SRC_DIR}"/tutorial_*.cpp; do
|
|
[[ -f "$src" ]] && generate "$src"
|
|
done
|
|
printf '\nDone. Markdown files in: %s/\n' "$OUTPUT_DIR"
|
|
ls -1 "${OUTPUT_DIR}/"
|
|
else
|
|
for src in "$@"; do
|
|
if [[ -f "$src" ]]; then
|
|
generate "$src"
|
|
else
|
|
printf 'File not found: %s\n' "$src" >&2
|
|
fi
|
|
done
|
|
fi
|