diff --git a/help/C/org.udpscope.app/math.page b/help/C/org.udpscope.app/math.page index c2aecfa..0e207ec 100644 --- a/help/C/org.udpscope.app/math.page +++ b/help/C/org.udpscope.app/math.page @@ -89,8 +89,9 @@ are rebuilt whenever it changes.

- The math channel editor: nodes as boxes on a canvas, the orange dot marking the - output, and the selected node's parameters beside it. + The math channel editor + Nodes as boxes on a canvas, the orange dot marking the output, and the selected + node's parameters beside it.

A sine source wired through a gain into a filter, with the output on the last node.

diff --git a/help/C/org.udpscope.app/overview.page b/help/C/org.udpscope.app/overview.page index 5b6b6df..76da886 100644 --- a/help/C/org.udpscope.app/overview.page +++ b/help/C/org.udpscope.app/overview.page @@ -33,8 +33,9 @@ is still there when you need it — an export writes it as a second column.

- The udpscope window on a live source: the header bar above the plots, the side - panel on the right, and the status bar along the bottom. + The udpscope window + The header bar above the plots, the side panel on the right, and the status bar + along the bottom.

One figure of three rows with four signals enabled, the Measure tab open in the side panel, and the status bar reading live.

@@ -95,9 +96,9 @@
- A held capture: the trigger has latched, the state reads - <gui>event held</gui>, and the axis is pinned to the event rather than to the live - edge. + A held capture + The trigger has latched, the state reads event held, and the axis is + pinned to the event rather than to the live edge.

The trigger marker sits at x = 0 and the pre-trigger share of the window is drawn to its left.

diff --git a/help/C/org.udpscope.app/trigger.page b/help/C/org.udpscope.app/trigger.page index 47923e5..1a76622 100644 --- a/help/C/org.udpscope.app/trigger.page +++ b/help/C/org.udpscope.app/trigger.page @@ -41,8 +41,9 @@
- A held capture: <gui>event held</gui> in the status bar, the axis pinned to the - event, and the trigger marker at x = 0. + A held capture + event held in the status bar, the axis pinned to the event, and the + trigger marker at x = 0.

The pre-trigger share is drawn to the left of the marker.

diff --git a/tools/check_help.sh b/tools/check_help.sh index 7a41627..cbedb59 100755 --- a/tools/check_help.sh +++ b/tools/check_help.sh @@ -3,12 +3,26 @@ # SPDX-FileCopyrightText: 2026 Martino Ferrari # # The manual's check, the way tools/check_ui.py is the .ui files' check: it runs the four -# yelp-check subcommands that need no network, then renders the whole set to HTML with -# yelp-build so a page that only fails at the transform step is caught too. +# yelp-check subcommands that need no network, checks the structural rules below, then renders +# the whole set to HTML with yelp-build so a page that only fails at the transform step is +# caught too. # -# `yelp-check validate` is deliberately absent. It fetches the Mallard RelaxNG schema over -# the network and fails on an offline machine for that reason rather than for a fault in the -# pages -- links/media/orphans/ids are the offline checks. +# `yelp-check validate` is deliberately absent, and it is worth being exact about why: it +# builds the RelaxNG schema locally with `xsltproc` and `mal-rng.xsl`, but the schema it +# generates includes the base grammar over the network, so on a machine where fetching is +# blocked it fails for that reason rather than for a fault in the pages. +# +# What that leaves unverified is *structure*, and that is not a small gap: three pages +# carrying a `
` whose `` was a sentence and which had no `<desc>` opened in +# nothing, while links, media, orphans, ids and the HTML render all passed. So the rules this +# project has actually needed are checked here, with xmllint's XPath and no schema at all. +# Add a rule when a page *teaches* one -- and do not add one you have not seen broken: a rule +# that fails a legal page is worse than no rule. +# +# Every expression uses local-name() on purpose. A Mallard page declares +# `xmlns="http://projectmallard.org/1.0/"`, and XPath 1.0 has no default namespace, so +# `//figure` matches *nothing* and every rule below silently passes. Written naively, this +# check reported "ok" for the very defect it was written for. # # Exit status is nonzero on the first finding. set -eu @@ -27,6 +41,29 @@ for sub in links media orphans ids; do yelp-check "$sub" "$dir" >/dev/null done +failed=0 +for page in "$dir"/*.page; do + while IFS='|' read -r what expr; do + [ -n "$what" ] || continue + n=$(xmllint --xpath "$expr" "$page" 2>/dev/null || echo "?") + if [ "$n" != "0" ]; then + printf ' %s: %s (%s)\n' "$(basename "$page")" "$what" "$n" >&2 + failed=1 + fi + done <<'RULES' +a figure describes itself|count(//*[local-name()='figure'][not(*[local-name()='desc'])]) +a section has a title|count(//*[local-name()='section'][not(*[local-name()='title'])]) +info is the page's first child|count(/*[local-name()='page']/*[1][local-name()!='info']) +no text sits directly under page|count(/*[local-name()='page']/text()[normalize-space()]) +a media names its src|count(//*[local-name()='media'][not(@src)]) +RULES +done +if [ "$failed" != 0 ]; then + echo "check_help: structural findings above" >&2 + exit 1 +fi +printf 'structure %s: ok\n' "$dir" + mkdir -p "$tmp/html" yelp-build html -o "$tmp/html" "$dir" pages=$(find "$tmp/html" -maxdepth 1 -name '*.html' | wc -l)