///| Plugin system for markdown renderers
///| Allows custom code block highlighters
///| 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 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_string()
if trimmed.is_empty() {
return { lang: "", filename: "", meta: "" }
}
// Find meta section (starts with space + {)
let trimmed_len = trimmed.iter().count()
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_len)
.trim(chars=" \t\n\r")
.to_string()
(main, meta_str)
}
None => (trimmed, "")
}
// Split lang:filename
let main_len = main_part.iter().count()
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_len)
{ 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)
}),
}
}