Generate the documentation's figures from the listings they illustrate
Chapters 6 and 8 described what a verb draws in prose. Eight figures now show it, and each one is produced by running the BASIC listing printed immediately above it -- so a picture cannot drift away from the code beside it, which is the way a screenshot goes wrong and the way nothing notices. tools/screenshot.c is a second SDL host, much smaller than the frontend: dummy video driver, software renderer, run to completion, read the target back, write a PNG. It draws no text layer on purpose, so a READY in the corner is not noise in a figure about BOX and no font has to be resolved. tools/docs_screenshots.sh reads the new screenshot=NAME fence tag straight out of the markdown. size=WxH is the second tag, and SCALE's figure uses it: the point being made is a 320x200 listing filling a larger window, which cannot be made on a 320x200 surface. Two gates, answering different questions. docs_examples fails a tagged block with no image, in both configurations, so a figure cannot be added and forgotten. docs_screenshots -- a CTest, AKGL build only -- re-renders every figure and compares byte for byte, so a listing edited without regenerating fails. Only the second catches a stale picture. The PNGs are checked in because a reader on the forge has no build tree, and docs/images/README.md says loudly that they are generated. Regenerating is never part of a build: the target is run deliberately, so a make cannot put eight binary diffs in front of whoever ran it. Drawing the BOX figure caught a defect in TODO.md itself. Deviation 16 claimed in bold that BOX fills on a negative angle while its own paragraph said the fill was filed rather than implemented. BOX cannot fill, and filled_rect is reached by no verb as a result. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,8 @@
|
||||
# ```basic norun a fragment, shown but not run
|
||||
# ```basic requires=akgl only run in the -DAKBASIC_WITH_AKGL=ON build
|
||||
# ```basic requires=noakgl only run in the build with no devices attached
|
||||
# ```basic screenshot=N also the source of docs/images/N.png; checked to exist
|
||||
# ```basic size=WxH that figure's surface size, when it is not 320x200
|
||||
# ```output the exact stdout of the block above, byte for byte
|
||||
# ```c a translation unit: compile it with -fsyntax-only
|
||||
# ```c wrap=NAME the same, wrapped in tests/docs_preludes/NAME.pre/.post
|
||||
@@ -128,7 +130,7 @@ fi
|
||||
CC="${CC:-cc}"
|
||||
|
||||
FAILURES=0
|
||||
declare -A RAN=([basic]=0 [repl]=0 [output]=0 [c]=0 [excerpt]=0 [sh]=0)
|
||||
declare -A RAN=([basic]=0 [repl]=0 [output]=0 [c]=0 [excerpt]=0 [sh]=0 [screenshot]=0)
|
||||
declare -A SKIPPED=([norun]=0 [akgl]=0 [cmake]=0 [text]=0 [nocc]=0)
|
||||
|
||||
# Every failure names the file and line of the block, so the message points at
|
||||
@@ -475,6 +477,22 @@ for DOC in "${DOCS[@]}"; do
|
||||
# language does -- a verb refusing because no device was attached is the
|
||||
# clearest one -- so they run in one configuration and are skipped in the
|
||||
# other. Both directions are needed, and both are visible in the count.
|
||||
# A `screenshot=NAME` block is the source of docs/images/NAME.png, generated
|
||||
# by tools/docs_screenshots.sh. The image is checked in, because a reader on
|
||||
# the forge has no build tree -- so nothing would otherwise notice a figure
|
||||
# that was tagged and never generated, and the chapter would render a broken
|
||||
# image. Checked in *both* configurations and before the requires= filter,
|
||||
# because the file either exists or it does not and that has nothing to do
|
||||
# with whether SDL is present.
|
||||
SHOT="$(attr screenshot "${INFO}")"
|
||||
if [ -n "${SHOT}" ]; then
|
||||
if [ -r "docs/images/${SHOT}.png" ]; then
|
||||
RAN[screenshot]=$((RAN[screenshot] + 1))
|
||||
else
|
||||
fail "${WHERE}" "screenshot=${SHOT} has no docs/images/${SHOT}.png; run \`cmake --build <akgl build> --target docs_screenshots\`"
|
||||
fi
|
||||
fi
|
||||
|
||||
REQUIRES="$(attr requires "${INFO}")"
|
||||
if [ "${REQUIRES}" = "akgl" ] && [ "${WITH_AKGL}" -eq 0 ]; then
|
||||
SKIPPED[akgl]=$((SKIPPED[akgl] + 1))
|
||||
@@ -522,7 +540,7 @@ done
|
||||
# The count is part of the result, not decoration. A harness that passes because
|
||||
# a chapter stopped matching the extractor looks exactly like a harness that
|
||||
# passes because the documentation is correct, and this is what tells them apart.
|
||||
echo "ran: ${RAN[basic]} programs, ${RAN[repl]} transcripts, ${RAN[output]} output comparisons, ${RAN[c]} C snippets, ${RAN[excerpt]} excerpts, ${RAN[sh]} shell blocks"
|
||||
echo "ran: ${RAN[basic]} programs, ${RAN[repl]} transcripts, ${RAN[output]} output comparisons, ${RAN[c]} C snippets, ${RAN[excerpt]} excerpts, ${RAN[sh]} shell blocks, ${RAN[screenshot]} figures"
|
||||
echo "skipped: ${SKIPPED[norun]} norun, ${SKIPPED[akgl]} needing akgl, ${SKIPPED[cmake]} cmake, ${SKIPPED[text]} text, ${SKIPPED[nocc]} C (no compiler flags given)"
|
||||
|
||||
if [ "${FAILURES}" -eq 0 ]; then
|
||||
|
||||
Reference in New Issue
Block a user