Show the terse control list when the help block is collapsed

This commit is contained in:
Gmer4Lfe
2026-08-05 17:58:29 -04:00
parent 2ad3a1bfed
commit aeb8c01370
2 changed files with 90 additions and 22 deletions
+74 -17
View File
@@ -106,6 +106,79 @@ function vv_docs_render(string $rel, array $vars, ?callable $keep = null): strin
// 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.
// Inline formatting for one line of markdown. Standalone rather than a closure because both the
// full renderer and the brief list below use it — two copies would drift, and the whole point of
// these docs is that the panel and the assistant cannot disagree.
//
// Escape first, then format: the only HTML in the output is HTML this function put there.
function vv_docs_inline(string $s, array $vars): string {
$s = htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
// `$VAR` → the live conf value. Unresolved names render in their own class rather than
// silently reading as prose, so a stale reference in a doc is visible as a defect.
$s = preg_replace_callback('/`\$([A-Z0-9_]+)`/', function ($m) use ($vars) {
return isset($vars[$m[1]])
? '<code class="vv-live-var">' . htmlspecialchars($vars[$m[1]]) . '</code>'
: '<code class="vv-unknown-var">$' . $m[1] . '</code>';
}, $s);
$s = preg_replace('/`([^`]+)`/', '<code>$1</code>', $s);
$s = preg_replace('/\*\*([^*]+)\*\*/', '<strong>$1</strong>', $s);
$s = preg_replace('/(?<![\w*])\*([^*]+)\*(?![\w*])/', '<em>$1</em>', $s);
// Links are restricted to http/https and relative paths — a doc is trusted, but these files
// sync between hosts, so javascript: must not be reachable through one.
$s = preg_replace('/\[([^\]]+)\]\((https?:\/\/[^\s)]+|[^\s):]+)\)/', '<a href="$2">$1</a>', $s);
return $s;
}
// Terse one-line-per-control list — the shape this help had before it became a document.
// Reads the same markdown as the full render, so the collapsed and expanded views cannot drift.
//
// Only table rows and bullets survive. Paragraphs are dropped on purpose: a list you sweep with
// your eye stops working the moment there is prose between the rows, and that is precisely what
// made the original comb well. Section titles become the full-width divider the old list used.
function vv_docs_brief(string $rel, array $vars, ?callable $keep = null): string {
$base = realpath(SCRIPTS_DIR);
$path = realpath(SCRIPTS_DIR . '/' . $rel);
if ($base === false || $path === false) return '';
if (!str_starts_with($path, $base . '/')) return '';
if (strtolower(pathinfo($path, PATHINFO_EXTENSION)) !== 'md') return '';
$out = '';
$skip = $keep !== null && !$keep(null);
$rowN = 0; // per-table row counter — row 0 is the header, not content
foreach (explode("\n", str_replace("\r\n", "\n", (string)@file_get_contents($path))) as $line) {
$t = trim($line);
if (preg_match('/^(#{1,6})\s+(.*)$/', $t, $m)) {
$rowN = 0;
$skip = $keep !== null && !$keep(strlen($m[1]) === 1 ? null : $m[2]);
// "Reference — the controls on a job row" reads as "the controls on a job row" once
// the whole list is reference material.
if (!$skip && strlen($m[1]) > 1) {
$h = preg_replace('/^Reference\s*—\s*/u', '', $m[2]);
$out .= '<li class="vv-info-sep">' . vv_docs_inline($h, $vars) . "</li>\n";
}
continue;
}
if ($skip || $t === '') { if ($t === '') $rowN = 0; continue; }
if (preg_match('/^[-*]\s+(.*)$/', $t, $m)) {
$out .= '<li>' . vv_docs_inline($m[1], $vars) . "</li>\n";
continue;
}
if (strpos($t, '|') !== false && substr_count($t, '|') >= 2) {
if (preg_match('/^\|?[\s:-]*-[\s|:-]*\|/', $t)) continue; // the --- separator
$cells = array_map('trim', explode('|', trim($t, '| ')));
if ($rowN++ === 0) continue; // header row
$term = array_shift($cells);
$out .= '<li><strong>' . vv_docs_inline($term, $vars) . '</strong> — '
. vv_docs_inline(implode(' · ', array_filter($cells)), $vars) . "</li>\n";
}
}
return $out;
}
function vv_docs_markdown(string $md, array $vars, ?callable $keep = null): string {
if (file_exists(PARSEDOWN_PATH)) {
require_once PARSEDOWN_PATH;
@@ -114,23 +187,7 @@ function vv_docs_markdown(string $md, array $vars, ?callable $keep = null): stri
return $pd->text($md);
}
$inline = function (string $s) use ($vars): string {
$s = htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
// `$VAR` → the live conf value. Unresolved names render in their own class rather than
// silently reading as prose, so a stale reference in a doc is visible as a defect.
$s = preg_replace_callback('/`\$([A-Z0-9_]+)`/', function ($m) use ($vars) {
return isset($vars[$m[1]])
? '<code class="vv-live-var">' . htmlspecialchars($vars[$m[1]]) . '</code>'
: '<code class="vv-unknown-var">$' . $m[1] . '</code>';
}, $s);
$s = preg_replace('/`([^`]+)`/', '<code>$1</code>', $s);
$s = preg_replace('/\*\*([^*]+)\*\*/', '<strong>$1</strong>', $s);
$s = preg_replace('/(?<![\w*])\*([^*]+)\*(?![\w*])/', '<em>$1</em>', $s);
// Links are restricted to http/https and relative paths — a doc is trusted, but these
// files sync between hosts, so javascript: must not be reachable through one.
$s = preg_replace('/\[([^\]]+)\]\((https?:\/\/[^\s)]+|[^\s):]+)\)/', '<a href="$2">$1</a>', $s);
return $s;
};
$inline = fn(string $s): string => vv_docs_inline($s, $vars);
$out = '';
$list = null; // 'ul' | 'ol' | null