Show the reference tables collapsed and the task guide on expand, from one file

This commit is contained in:
Gmer4Lfe
2026-08-04 19:45:23 -04:00
parent 64a28acd64
commit 87fa2693f0
3 changed files with 49 additions and 15 deletions
+32 -13
View File
@@ -72,7 +72,11 @@ function vv_docs_tree(): array {
return $tree;
}
function vv_docs_render(string $rel, array $vars): string {
// $keep, when given, selects which `##` sections are rendered. It receives the section heading —
// or null for the title and any preamble before the first one — and returns whether to include
// it. That is what lets one file drive both tiers of a disclosure without a second copy, and
// without inventing markdown syntax to mark the split: the section titles already carry it.
function vv_docs_render(string $rel, array $vars, ?callable $keep = null): string {
// Containment check — $rel is expected to come from a request parameter once this is
// wired to a page. Resolve it and require the result to stay inside SCRIPTS_DIR and to
// still be a .md file, so a traversal sequence cannot reach arbitrary files.
@@ -83,7 +87,7 @@ function vv_docs_render(string $rel, array $vars): string {
if (strtolower(pathinfo($path, PATHINFO_EXTENSION)) !== 'md') return '<p>File not found.</p>';
if (!is_file($path)) return '<p>File not found.</p>';
return vv_docs_markdown(file_get_contents($path), $vars);
return vv_docs_markdown(file_get_contents($path), $vars, $keep);
}
// Markdown → HTML for the subset these docs actually use: headings, paragraphs, bullet and
@@ -102,7 +106,7 @@ function vv_docs_render(string $rel, array $vars): string {
// here, after escaping. Injecting <code> into the markdown before rendering, as this file used to
// do, meant both Parsedown's safe mode and the <pre> fallback escaped the tags and printed them
// as literal text. The feature never worked; nothing called it, so nothing reported it.
function vv_docs_markdown(string $md, array $vars): string {
function vv_docs_markdown(string $md, array $vars, ?callable $keep = null): string {
if (file_exists(PARSEDOWN_PATH)) {
require_once PARSEDOWN_PATH;
$pd = new Parsedown();
@@ -161,17 +165,39 @@ function vv_docs_markdown(string $md, array $vars): string {
if ($inTable) { $out .= "</tbody></table>\n"; $inTable = false; }
};
// Content before the first heading belongs to the same null-headed group as the title.
$skip = $keep !== null && !$keep(null);
foreach (explode("\n", str_replace("\r\n", "\n", $md)) as $line) {
// Fence state is tracked even inside a skipped section, or a ``` that is being dropped
// would leave the parser convinced every following line is code.
if (preg_match('/^```/', $line)) {
$flushPara(); $closeList(); $closeTable();
$out .= $inCode ? "</code></pre>\n" : '<pre class="vv-doc-code"><code>';
if (!$skip) {
$flushPara(); $closeList(); $closeTable();
$out .= $inCode ? "</code></pre>\n" : '<pre class="vv-doc-code"><code>';
}
$inCode = !$inCode;
continue;
}
if ($inCode) { $out .= htmlspecialchars($line, ENT_QUOTES, 'UTF-8') . "\n"; continue; }
if ($inCode) {
if (!$skip) $out .= htmlspecialchars($line, ENT_QUOTES, 'UTF-8') . "\n";
continue;
}
$t = trim($line);
// Headings are resolved before the skip test, because a heading is what changes it.
if (preg_match('/^(#{1,6})\s+(.*)$/', $t, $m)) {
$flushQuote(); $flushPara(); $closeList(); $closeTable();
$n = strlen($m[1]);
// A level-1 heading is the document title, not a section — it and the preamble that
// follows are offered to $keep as null so a caller can take or leave them as a unit.
$skip = $keep !== null && !$keep($n === 1 ? null : $m[2]);
if (!$skip) $out .= "<h$n>" . $inline($m[2]) . "</h$n>\n";
continue;
}
if ($skip) continue;
// One guard rather than a flush in every branch: the quote ends the moment a line is
// not a quote line, whatever that next line turns out to be.
if ($quote && !str_starts_with($t, '>')) $flushQuote();
@@ -179,13 +205,6 @@ function vv_docs_markdown(string $md, array $vars): string {
if ($t === '') { $flushPara(); $closeList(); $closeTable(); continue; }
if (preg_match('/^(---+|\*\*\*+)$/', $t)) { $flushPara(); $closeList(); $closeTable(); $out .= "<hr>\n"; continue; }
if (preg_match('/^(#{1,6})\s+(.*)$/', $t, $m)) {
$flushPara(); $closeList(); $closeTable();
$n = strlen($m[1]);
$out .= "<h$n>" . $inline($m[2]) . "</h$n>\n";
continue;
}
// Consecutive > lines are one quote, not one per line — same wrapping convention as
// paragraphs, which is how they are written.
if (preg_match('/^>\s?(.*)$/', $t, $m)) {