///| Code block info string parsing.
///|
///| Parses the language tag of a fenced code block, e.g. "js:app.js {meta}".
///|
/// Parsed info string from code block fence.
///
/// Format: `"lang:filename {meta}"`
///
/// Examples:
/// - `"javascript"` → `{ lang: "javascript", filename: "", meta: "" }`
/// - `"js:app.js"` → `{ lang: "js", filename: "app.js", meta: "" }`
/// - `"ts:index.ts {highlight=[1,3]}"` →
/// `{ lang: "ts", filename: "index.ts", meta: "{highlight=[1,3]}" }`
pub(all) struct CodeBlockInfo {
lang : String
filename : String
meta : String
}
///|
/// Parse code block info string into components
pub fn parse_code_block_info(info : String) -> CodeBlockInfo {
let trimmed = info.trim(chars=" \t\n\r").to_owned()
if trimmed.is_empty() {
return { lang: "", filename: "", meta: "" }
}
// Find meta section (starts with space + {)
let (main_part, meta) = match trimmed.find(" {") {
Some(idx) => {
let main = trimmed.unsafe_substring(start=0, end=idx)
let meta_str = trimmed
.unsafe_substring(start=idx + 1, end=trimmed.length())
.trim(chars=" \t\n\r")
.to_owned()
(main, meta_str)
}
None => (trimmed, "")
}
// Split lang:filename
match main_part.find(":") {
Some(idx) => {
let lang = main_part.unsafe_substring(start=0, end=idx)
let filename = main_part.unsafe_substring(
start=idx + 1,
end=main_part.length(),
)
{ lang, filename, meta }
}
None => { lang: main_part, filename: "", meta }
}
}
///|
/// Render options with plugin support
pub struct RenderOptions {
/// Custom code block highlighter
code_highlighter : ((CodeBlockInfo, String) -> String)?
}
///|
/// Create default render options
pub fn RenderOptions::default() -> RenderOptions {
{ code_highlighter: None }
}
///|
/// Create render options with code highlighter
pub fn RenderOptions::with_highlighter(
highlighter : (CodeBlockInfo, String) -> String,
) -> RenderOptions {
{ code_highlighter: Some(highlighter) }
}
///|
/// Create render options with simple highlighter (lang, code) -> String
pub fn RenderOptions::with_simple_highlighter(
highlighter : (String, String) -> String,
) -> RenderOptions {
{
code_highlighter: Some(fn(info : CodeBlockInfo, code : String) -> String {
highlighter(info.lang, code)
}),
}
}