From ee133f6050a7dbfaa0577162d5873b237d78609e Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Sat, 30 May 2026 15:11:33 +0200 Subject: [PATCH 1/3] Fix mislabeled C/SAL block in API-Declarations. --- docs/Features/Advanced/API-Declarations.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/Features/Advanced/API-Declarations.md b/docs/Features/Advanced/API-Declarations.md index 9d6d43a9..f25ee339 100644 --- a/docs/Features/Advanced/API-Declarations.md +++ b/docs/Features/Advanced/API-Declarations.md @@ -101,11 +101,11 @@ With `cdecl` calling convention fully supported, twinBASIC can also handle varia Using the [given C/C++ prototype](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-wsprintfw): -```cpp +```c int WINAPIV wsprintfW( - [out] LPWSTR unnamedParam1, - [in] LPCWSTR unnamedParam2, - ... + /* [out] */ LPWSTR unnamedParam1, + /* [in] */ LPCWSTR unnamedParam2, + /* ... */ ); ``` From e18bd6da922e6d85e6b071b938c8de79c1f0e4c8 Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Sat, 30 May 2026 15:12:04 +0200 Subject: [PATCH 2/3] Curate Shiki grammar set, warn on unknown fence labels. --- builder/highlight.mjs | 46 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/builder/highlight.mjs b/builder/highlight.mjs index 4ef16347..0e47ca01 100644 --- a/builder/highlight.mjs +++ b/builder/highlight.mjs @@ -21,8 +21,27 @@ import { loadHighlightTheme } from "./highlight-theme.mjs"; // Fenced-info aliases that select the bundled tB grammar. const TB_ALIASES = new Set(["tb", "twinbasic", "vb", "vba"]); -const SHIKI_BUNDLED_LANGS = [ - "js", "json", "ruby", "html", "yaml", "xml", "sql", "sh", "cpp", "c", "liquid", + +// Fence labels that explicitly disclaim highlighting -- never warn for these. +// Empty info string lands as wrapperLang `plaintext` (see renderCodeBlock). +const SILENT_LANGS = new Set(["plaintext", "text", "txt", ""]); + +// Shiki grammars to load alongside the tB grammar. Restricted to labels +// actually used in docs/ -- the highlighter warns at build time for any +// unknown label, so adding a new fence language is a deliberate step: +// extend this list, run the build, verify no warning. Aliases are +// recognized automatically (shiki registers both canonical and alias +// names, so loading `js` accepts `javascript` too, `yaml` accepts `yml`, +// `batch` accepts `bat`). Counts from the last survey are noted. +const SHIKI_LANGS = [ + "js", // 56 blocks (CEF/WebView2 interop tutorials) + "yaml", // 13 blocks (config snippets) + "json", // 7 blocks + "c", // 3 blocks (Win32 API examples, comment style demos) + "html", // 2 blocks (transitively loads css + javascript) + "xml", // 1 block + "sql", // 1 block + "batch", // 1 block (Windows .bat examples) ]; // Phase 11 (B5) server-side copy-button: emitted inside the wrapper @@ -50,21 +69,32 @@ export async function initHighlighter({ copyButton = true } = {}) { const tbGrammar = JSON.parse(grammarText); shiki = await createHighlighter({ themes: [], - langs: [tbGrammar, ...SHIKI_BUNDLED_LANGS], + langs: [tbGrammar, ...SHIKI_LANGS], }); } catch (err) { if (err.code !== "ENOENT") throw err; } + // Dedup unknown-language warnings per init. SILENT_LANGS suppresses + // explicit plaintext intent (text, txt, plaintext) and empty fences. + const warned = new Set(); + const warn = (lang) => { + if (warned.has(lang)) return; + warned.add(lang); + console.warn( + `highlight: unknown fence language "${lang}" -- falling back to plain text. ` + + `Add it to highlight.mjs's SHIKI_LANGS to enable highlighting.`); + }; + const copyButtonHtml = copyButton ? COPY_BUTTON_HTML : ""; cached = { - render: (code, lang) => renderCodeBlock(shiki, theme, copyButtonHtml, code, lang), + render: (code, lang) => renderCodeBlock(shiki, theme, copyButtonHtml, code, lang, warn), themeCss: theme.css, }; return cached; } -function renderCodeBlock(shiki, theme, copyButtonHtml, code, lang) { +function renderCodeBlock(shiki, theme, copyButtonHtml, code, lang, warn) { const lower = (lang || "").toLowerCase(); const isTb = TB_ALIASES.has(lower); // The wrapper class is `language-`; keep `vb` / `vba` / @@ -82,6 +112,12 @@ function renderCodeBlock(shiki, theme, copyButtonHtml, code, lang) { } } + // Warn for non-silent fence labels that don't resolve to a loaded + // grammar. SILENT_LANGS covers explicit plaintext intent. + if (!shikiLang && !SILENT_LANGS.has(lower) && warn) { + warn(lower); + } + // The trailing \n inside matches the rouge / kramdown shape: // GFM strips the user's trailing newline; one is re-added here. const codeBody = code.endsWith("\n") ? code : code + "\n"; From 3106c3af4cc574ad7b0cbc746530401868613925 Mon Sep 17 00:00:00 2001 From: Kuba Sunderland-Ober Date: Sat, 30 May 2026 15:24:08 +0200 Subject: [PATCH 3/3] Drop the enable_copy_code_button config option. The button is always enabled. --- builder/highlight.mjs | 9 ++++----- builder/tbdocs.mjs | 4 +--- builder/template.mjs | 7 +++---- docs/Documentation/Pipeline-Stages.md | 4 ++-- docs/Documentation/Tools.md | 2 +- docs/_config.yml | 3 --- 6 files changed, 11 insertions(+), 18 deletions(-) diff --git a/builder/highlight.mjs b/builder/highlight.mjs index 0e47ca01..688014f8 100644 --- a/builder/highlight.mjs +++ b/builder/highlight.mjs @@ -57,7 +57,7 @@ const COPY_BUTTON_HTML = let cached = null; -export async function initHighlighter({ copyButton = true } = {}) { +export async function initHighlighter() { if (cached) return cached; const theme = await loadHighlightTheme(); @@ -86,15 +86,14 @@ export async function initHighlighter({ copyButton = true } = {}) { `Add it to highlight.mjs's SHIKI_LANGS to enable highlighting.`); }; - const copyButtonHtml = copyButton ? COPY_BUTTON_HTML : ""; cached = { - render: (code, lang) => renderCodeBlock(shiki, theme, copyButtonHtml, code, lang, warn), + render: (code, lang) => renderCodeBlock(shiki, theme, code, lang, warn), themeCss: theme.css, }; return cached; } -function renderCodeBlock(shiki, theme, copyButtonHtml, code, lang, warn) { +function renderCodeBlock(shiki, theme, code, lang, warn) { const lower = (lang || "").toLowerCase(); const isTb = TB_ALIASES.has(lower); // The wrapper class is `language-`; keep `vb` / `vba` / @@ -133,7 +132,7 @@ function renderCodeBlock(shiki, theme, copyButtonHtml, code, lang, warn) { tokenizedHtml = escapeHtml(codeBody); } - return `
${copyButtonHtml}
${tokenizedHtml}
`; + return `
${COPY_BUTTON_HTML}
${tokenizedHtml}
`; } // Shiki's `codeToTokensBase` with `includeExplanation` returns diff --git a/builder/tbdocs.mjs b/builder/tbdocs.mjs index 5dc3a14e..dbe45699 100644 --- a/builder/tbdocs.mjs +++ b/builder/tbdocs.mjs @@ -153,9 +153,7 @@ export async function runBuild(opts) { // Build the shared markdown-it instance up front so Phase 2's SEO // pass and Phase 3's body renderer use the same configured renderer. // initHighlighter overlaps with the running git shell-outs above. - const highlighter = await initHighlighter({ - copyButton: config.enable_copy_code_button !== false, - }); + const highlighter = await initHighlighter(); const linkTables = buildLinkTables(pages); const baseurl = String(config.baseurl || ""); const staticFileSet = new Set(staticFiles.map((s) => s.srcRel)); diff --git a/builder/template.mjs b/builder/template.mjs index c1bfa2ec..76491a77 100644 --- a/builder/template.mjs +++ b/builder/template.mjs @@ -270,11 +270,10 @@ const SVG_SYMBOLS_COPY = `