From d35abe824dc9c1d386d588157169275467a5451b Mon Sep 17 00:00:00 2001 From: Sudrut Date: Sat, 6 Dec 2025 00:16:41 +0800 Subject: [PATCH 1/9] feat: add expressive-code plugin for marks in code block --- src/plugins/expressive-code/cxx-mark.ts | 58 +++++++++++++++++++++++++ src/styles/custom.css | 3 ++ 2 files changed, 61 insertions(+) create mode 100644 src/plugins/expressive-code/cxx-mark.ts diff --git a/src/plugins/expressive-code/cxx-mark.ts b/src/plugins/expressive-code/cxx-mark.ts new file mode 100644 index 0000000..22fb14e --- /dev/null +++ b/src/plugins/expressive-code/cxx-mark.ts @@ -0,0 +1,58 @@ +import { definePlugin, InlineStyleAnnotation, type ExpressiveCodePlugin } from "@astrojs/starlight/expressive-code"; + +export function pluginCxxMark(): ExpressiveCodePlugin { + return definePlugin({ + name: "CXX mark", + hooks: { + postprocessAnalyzedCode: (context) => { + context.codeBlock.getLines().forEach((line) => { + if (context.codeBlock.meta.includes("cxx-mark")) { + const matches = [...line.text.matchAll(/\/\*\$(((?s)|(?expos)):[^\*]+|(?opt))\*\//g)].reverse() + matches.forEach((match) => { + const begin = match.index + const end = begin + match[0].length + if (match.groups?.syntax != undefined) { + line.addAnnotation( + new InlineStyleAnnotation({ + inlineRange: { + columnStart: begin, + columnEnd: end + }, + // color of syntax notation should be same with comments + italic: true + }) + ) + line.editText(begin, end, match[0].slice(5, -2)) + } else if (match.groups?.exposition != undefined) { + line.addAnnotation( + new InlineStyleAnnotation({ + inlineRange: { + columnStart: begin, + columnEnd: end + }, + color: "var(--cppdoc-color-cxx-mark-exposition)", + italic: true + }) + + ) + line.editText(begin + 2, begin + 9, "") + } else if (match.groups?.optional != undefined) { + const new_str = "(optional)" + line.editText(begin, end, new_str) + line.addAnnotation( + new InlineStyleAnnotation({ + inlineRange: { + columnStart: begin, + columnEnd: begin + new_str.length + }, + color: "var(--cppdoc-color-cxx-mark-optional)" + }) + ) + } + }) + } + }) + } + } + }) +} \ No newline at end of file diff --git a/src/styles/custom.css b/src/styles/custom.css index efbe066..aff9dbd 100644 --- a/src/styles/custom.css +++ b/src/styles/custom.css @@ -17,6 +17,9 @@ --cppdoc-color-ill-formed: var(--sl-color-red); --cppdoc-color-ifndr: var(--sl-color-red); + --cppdoc-color-cxx-mark-exposition: #ff0000; + --cppdoc-color-cxx-mark-optional: var(--sl-color-green); + --sl-sidebar-width: 22rem; } From f59050ff8fc72b08094e5ce921d19979f9837d14 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Sat, 6 Dec 2025 00:17:37 +0800 Subject: [PATCH 2/9] feat: load cxx-mark-plugin in astro config --- astro.config.mjs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/astro.config.mjs b/astro.config.mjs index eb77312..d65f7b3 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -6,6 +6,8 @@ import starlightUtils from "@lorenzo_lewis/starlight-utils"; import starlightAutoSidebar from "starlight-auto-sidebar"; import starlightHeadingBadges from "starlight-heading-badges"; +import { pluginCxxMark } from "./src/plugins/expressive-code/cxx-mark"; + // https://astro.build/config export default defineConfig({ site: process.env.CPPDOC_SITE, @@ -61,6 +63,9 @@ export default defineConfig({ }), ], customCss: ["./src/styles/custom.css"], + expressiveCode: { + plugins: [pluginCxxMark()], + }, }), ], }); From 539045998ba56223146783345cbeb2795b684730 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Sat, 6 Dec 2025 00:39:51 +0800 Subject: [PATCH 3/9] fix: remove redundant empty line --- src/plugins/expressive-code/cxx-mark.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/expressive-code/cxx-mark.ts b/src/plugins/expressive-code/cxx-mark.ts index 22fb14e..00738f1 100644 --- a/src/plugins/expressive-code/cxx-mark.ts +++ b/src/plugins/expressive-code/cxx-mark.ts @@ -33,7 +33,6 @@ export function pluginCxxMark(): ExpressiveCodePlugin { color: "var(--cppdoc-color-cxx-mark-exposition)", italic: true }) - ) line.editText(begin + 2, begin + 9, "") } else if (match.groups?.optional != undefined) { From 1732a257f3fa5cd11d926c59f98127d84b6c0986 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Sat, 6 Dec 2025 11:58:22 +0800 Subject: [PATCH 4/9] style: reformat code --- src/plugins/expressive-code/cxx-mark.ts | 54 ++++++++++++++----------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/plugins/expressive-code/cxx-mark.ts b/src/plugins/expressive-code/cxx-mark.ts index 00738f1..8ecc5d0 100644 --- a/src/plugins/expressive-code/cxx-mark.ts +++ b/src/plugins/expressive-code/cxx-mark.ts @@ -1,4 +1,8 @@ -import { definePlugin, InlineStyleAnnotation, type ExpressiveCodePlugin } from "@astrojs/starlight/expressive-code"; +import { + definePlugin, + InlineStyleAnnotation, + type ExpressiveCodePlugin, +} from "@astrojs/starlight/expressive-code"; export function pluginCxxMark(): ExpressiveCodePlugin { return definePlugin({ @@ -7,51 +11,55 @@ export function pluginCxxMark(): ExpressiveCodePlugin { postprocessAnalyzedCode: (context) => { context.codeBlock.getLines().forEach((line) => { if (context.codeBlock.meta.includes("cxx-mark")) { - const matches = [...line.text.matchAll(/\/\*\$(((?s)|(?expos)):[^\*]+|(?opt))\*\//g)].reverse() + const matches = [ + ...line.text.matchAll( + /\/\*\$(((?s)|(?expos)):[^\*]+|(?opt))\*\//g + ), + ].reverse(); matches.forEach((match) => { - const begin = match.index - const end = begin + match[0].length + const begin = match.index; + const end = begin + match[0].length; if (match.groups?.syntax != undefined) { line.addAnnotation( new InlineStyleAnnotation({ inlineRange: { columnStart: begin, - columnEnd: end + columnEnd: end, }, // color of syntax notation should be same with comments - italic: true + italic: true, }) - ) - line.editText(begin, end, match[0].slice(5, -2)) + ); + line.editText(begin, end, match[0].slice(5, -2)); } else if (match.groups?.exposition != undefined) { line.addAnnotation( new InlineStyleAnnotation({ inlineRange: { columnStart: begin, - columnEnd: end + columnEnd: end, }, color: "var(--cppdoc-color-cxx-mark-exposition)", - italic: true + italic: true, }) - ) - line.editText(begin + 2, begin + 9, "") + ); + line.editText(begin + 2, begin + 9, ""); } else if (match.groups?.optional != undefined) { - const new_str = "(optional)" - line.editText(begin, end, new_str) + const new_str = "(optional)"; + line.editText(begin, end, new_str); line.addAnnotation( new InlineStyleAnnotation({ inlineRange: { columnStart: begin, - columnEnd: begin + new_str.length + columnEnd: begin + new_str.length, }, - color: "var(--cppdoc-color-cxx-mark-optional)" + color: "var(--cppdoc-color-cxx-mark-optional)", }) - ) + ); } - }) + }); } - }) - } - } - }) -} \ No newline at end of file + }); + }, + }, + }); +} From 34a01dc54eea39bffba200f12f0fbd9004927187 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Sat, 6 Dec 2025 12:14:09 +0800 Subject: [PATCH 5/9] fix: move expressive-code options to ec.config.mjs --- astro.config.mjs | 5 ----- ec.config.mjs | 7 +++++++ 2 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 ec.config.mjs diff --git a/astro.config.mjs b/astro.config.mjs index d65f7b3..eb77312 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -6,8 +6,6 @@ import starlightUtils from "@lorenzo_lewis/starlight-utils"; import starlightAutoSidebar from "starlight-auto-sidebar"; import starlightHeadingBadges from "starlight-heading-badges"; -import { pluginCxxMark } from "./src/plugins/expressive-code/cxx-mark"; - // https://astro.build/config export default defineConfig({ site: process.env.CPPDOC_SITE, @@ -63,9 +61,6 @@ export default defineConfig({ }), ], customCss: ["./src/styles/custom.css"], - expressiveCode: { - plugins: [pluginCxxMark()], - }, }), ], }); diff --git a/ec.config.mjs b/ec.config.mjs new file mode 100644 index 0000000..05bdac5 --- /dev/null +++ b/ec.config.mjs @@ -0,0 +1,7 @@ +// @ts-check +import { pluginCxxMark } from "./src/plugins/expressive-code/cxx-mark.ts"; + +/** @type {import('@astrojs/starlight/expressive-code').StarlightExpressiveCodeOptions} */ +export default { + plugins: [pluginCxxMark()], +} \ No newline at end of file From 7d24ede670c991f17cf93c154b28d6655ef44d29 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Sat, 6 Dec 2025 12:14:56 +0800 Subject: [PATCH 6/9] style: reformat code --- ec.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ec.config.mjs b/ec.config.mjs index 05bdac5..c03eb5a 100644 --- a/ec.config.mjs +++ b/ec.config.mjs @@ -4,4 +4,4 @@ import { pluginCxxMark } from "./src/plugins/expressive-code/cxx-mark.ts"; /** @type {import('@astrojs/starlight/expressive-code').StarlightExpressiveCodeOptions} */ export default { plugins: [pluginCxxMark()], -} \ No newline at end of file +}; From 3150029ea7f7338780634650272832d52626b797 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Sat, 6 Dec 2025 15:14:59 +0800 Subject: [PATCH 7/9] fix: fix incorrect behavior when content contains '*' --- src/plugins/expressive-code/cxx-mark.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/plugins/expressive-code/cxx-mark.ts b/src/plugins/expressive-code/cxx-mark.ts index 8ecc5d0..f1a8962 100644 --- a/src/plugins/expressive-code/cxx-mark.ts +++ b/src/plugins/expressive-code/cxx-mark.ts @@ -12,14 +12,12 @@ export function pluginCxxMark(): ExpressiveCodePlugin { context.codeBlock.getLines().forEach((line) => { if (context.codeBlock.meta.includes("cxx-mark")) { const matches = [ - ...line.text.matchAll( - /\/\*\$(((?s)|(?expos)):[^\*]+|(?opt))\*\//g - ), + ...line.text.matchAll(/\/\*\$(.+?)\*\//g), ].reverse(); matches.forEach((match) => { const begin = match.index; const end = begin + match[0].length; - if (match.groups?.syntax != undefined) { + if (match[1].startsWith("s:")) { line.addAnnotation( new InlineStyleAnnotation({ inlineRange: { @@ -31,7 +29,7 @@ export function pluginCxxMark(): ExpressiveCodePlugin { }) ); line.editText(begin, end, match[0].slice(5, -2)); - } else if (match.groups?.exposition != undefined) { + } else if (match[1].startsWith("expos:")) { line.addAnnotation( new InlineStyleAnnotation({ inlineRange: { @@ -43,7 +41,7 @@ export function pluginCxxMark(): ExpressiveCodePlugin { }) ); line.editText(begin + 2, begin + 9, ""); - } else if (match.groups?.optional != undefined) { + } else if (match[1] == "opt") { const new_str = "(optional)"; line.editText(begin, end, new_str); line.addAnnotation( From 324e86136b515ff0390decd68f56a87b440b0d35 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Mon, 8 Dec 2025 16:57:10 +0800 Subject: [PATCH 8/9] style: use camelCase; rename expos to e, since we will possibly never add new markers --- src/plugins/expressive-code/cxx-mark.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/expressive-code/cxx-mark.ts b/src/plugins/expressive-code/cxx-mark.ts index f1a8962..5155d4f 100644 --- a/src/plugins/expressive-code/cxx-mark.ts +++ b/src/plugins/expressive-code/cxx-mark.ts @@ -29,7 +29,7 @@ export function pluginCxxMark(): ExpressiveCodePlugin { }) ); line.editText(begin, end, match[0].slice(5, -2)); - } else if (match[1].startsWith("expos:")) { + } else if (match[1].startsWith("e:")) { line.addAnnotation( new InlineStyleAnnotation({ inlineRange: { @@ -40,15 +40,15 @@ export function pluginCxxMark(): ExpressiveCodePlugin { italic: true, }) ); - line.editText(begin + 2, begin + 9, ""); + line.editText(begin + 2, begin + 5, ""); } else if (match[1] == "opt") { - const new_str = "(optional)"; - line.editText(begin, end, new_str); + const newStr = "(optional)"; + line.editText(begin, end, newStr); line.addAnnotation( new InlineStyleAnnotation({ inlineRange: { columnStart: begin, - columnEnd: begin + new_str.length, + columnEnd: begin + newStr.length, }, color: "var(--cppdoc-color-cxx-mark-optional)", }) From 98c57c219bb95723809be71dc4f9b81e8e5f58e5 Mon Sep 17 00:00:00 2001 From: Sudrut Date: Mon, 8 Dec 2025 22:30:43 +0800 Subject: [PATCH 9/9] feat: add doc for cxx mark feature --- .../examples/development/guide/cxx-mark-1.mdx | 8 +++ .../docs/development/guide/doc-everything.mdx | 69 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 src/assets/examples/development/guide/cxx-mark-1.mdx diff --git a/src/assets/examples/development/guide/cxx-mark-1.mdx b/src/assets/examples/development/guide/cxx-mark-1.mdx new file mode 100644 index 0000000..bbc0df8 --- /dev/null +++ b/src/assets/examples/development/guide/cxx-mark-1.mdx @@ -0,0 +1,8 @@ +```cpp cxx-mark +// syntax of for statement +/*$s:attr*//*$opt*/ for ( /*$s:init-statement*/ /*$s:condition*//*$opt*/ ; /*$s:expression*//*$opt*/ ) /*$s:statement*/ + +// exposition only alias template of conditionally const type +template< bool Const, class T > +using /*$e:maybe-const*/ = std::conditional_t; +``` \ No newline at end of file diff --git a/src/content/docs/development/guide/doc-everything.mdx b/src/content/docs/development/guide/doc-everything.mdx index d6e7f8d..edf6d31 100644 --- a/src/content/docs/development/guide/doc-everything.mdx +++ b/src/content/docs/development/guide/doc-everything.mdx @@ -139,6 +139,75 @@ import declDocExample3 from "@src/assets/examples/development/guide/decl-doc-3.m Don't forget the `autorevSince` attribute on the `DeclDoc` component! Presence of this attribute allows [autorev](./revision#autorev) to automatically show and hide the `DeclDoc` component according to the user-selected revision. +## Code block inline markers + +Special comments can be embedded within Markdown code blocks to specify part of codes has special meanings. Enable this feature by adding `cxx-mark` after the language name of code block's opening fence: + +import cxxMarkExample1 from "@src/assets/examples/development/guide/cxx-mark-1.mdx?raw"; + + + + + ```cpp cxx-mark + // syntax of for statement + /*$s:attr*//*$opt*/ for ( /*$s:init-statement*/ /*$s:condition*//*$opt*/ ; /*$s:expression*//*$opt*/ ) /*$s:statement*/ + + // exposition only alias template of conditionally const type + template< bool Const, class T > + using /*$e:maybe-const*/ = std::conditional_t; + ``` + + +Three kinds of markers are supported: + + + + ``` + /*$s:something*/ + ``` + + + Marks part of code to be a syntax notation. + + Rendered as: + + ```cpp cxx-mark + /*$s:something*/ + ``` + + + + + ``` + /*$e:something*/ + ``` + + + Marks part of code to be exposition only. + + Rendered as: + + ```cpp cxx-mark + /*$e:something*/ + ``` + + + + + ``` + something/*$opt*/ + ``` + + + Mark the previous part of code (often a syntax notation) to be optional. + + Rendered as: + + ```cpp cxx-mark + something/*$opt*/ + ``` + + ## Description list ### Basic Usage