///| Inline serialization (text, emphasis, links, images, code spans, ...).
///|
///| Split from serializer.mbt to keep that file focused on block-level
///| serialization. Table-cell variants and wikilink escaping live here
///| because they are part of the same inline-rendering surface.
///|
/// Serialize inline content
fn serialize_inlines(inlines : Array[Inline], buf : StringBuilder) -> Unit {
for inline in inlines {
serialize_inline(inline, buf)
}
}
///|
/// Serialize table cell inline content (escapes pipes)
fn serialize_table_cell_inlines(
inlines : Array[Inline],
buf : StringBuilder,
) -> Unit {
for inline in inlines {
serialize_table_cell_inline(inline, buf)
}
}
///|
/// Serialize a single inline element for table cells (escapes pipes in text)
fn serialize_table_cell_inline(inline : Inline, buf : StringBuilder) -> Unit {
match inline {
Inline::Text(content~, ..) =>
// Escape pipe characters in table cells
for c in content {
if c == '|' {
buf.write_string("\\|")
} else {
buf.write_char(c)
}
}
// For other inline types, delegate to regular serialization
_ => serialize_inline(inline, buf)
}
}
///|
/// Escape characters that would terminate or split a wiki link.
fn serialize_wikilink_part(value : String, buf : StringBuilder) -> Unit {
for c in value {
match c {
'\\' | '|' | ']' => {
buf.write_char('\\')
buf.write_char(c)
}
_ => buf.write_char(c)
}
}
}
///|
fn serialize_wikilink_destination(target : String, fragment : String) -> String {
if fragment.is_empty() {
target
} else {
target + "#" + fragment
}
}
///|
/// Serialize a single inline element
fn serialize_inline(inline : Inline, buf : StringBuilder) -> Unit {
match inline {
Inline::Text(content~, ..) => buf.write_string(content)
Inline::SoftBreak(..) => buf.write_char('\n')
Inline::HardBreak(..) =>
// remark uses backslash style by default
buf.write_string("\\\n")
Inline::Emphasis(children~, ..) => {
// Always use * for GFM compatibility (remark default)
buf.write_char('*')
serialize_inlines(children, buf)
buf.write_char('*')
}
Inline::Strong(children~, ..) => {
// Always use ** for GFM compatibility (remark default)
buf.write_string("**")
serialize_inlines(children, buf)
buf.write_string("**")
}
Inline::Strikethrough(children~, ..) => {
buf.write_string("~~")
serialize_inlines(children, buf)
buf.write_string("~~")
}
Inline::Code(content~, ..) => {
// Calculate minimum backticks needed (must not match any run in content)
let backticks = calc_code_span_backticks(content)
write_chars(buf, '`', backticks)
// Add padding space if content starts/ends with backtick
// (Spaces at both ends need padding only if NOT all spaces, to prevent trimming)
let needs_padding = content.length() > 0 &&
({
let first = content.get_char(0)
let last = content.get_char(content.length() - 1)
first == Some('`') || last == Some('`')
})
if needs_padding {
buf.write_char(' ')
}
buf.write_string(content)
if needs_padding {
buf.write_char(' ')
}
write_chars(buf, '`', backticks)
}
Inline::WikiLink(target~, label~, fragment~, ..) => {
let destination = serialize_wikilink_destination(target, fragment)
buf.write_string("[[")
serialize_wikilink_part(destination, buf)
if !label.is_empty() {
buf.write_char('|')
serialize_wikilink_part(label, buf)
}
buf.write_string("]]")
}
Inline::Link(children~, url~, title~, ..) => {
buf.write_char('[')
serialize_inlines(children, buf)
buf.write_string("](")
buf.write_string(url)
if !title.is_empty() {
buf.write_string(" \"")
buf.write_string(title)
buf.write_char('"')
}
buf.write_char(')')
}
Inline::RefLink(children~, label~, ..) => {
buf.write_char('[')
serialize_inlines(children, buf)
buf.write_string("][")
buf.write_string(label)
buf.write_char(']')
}
Inline::Autolink(url~, ..) => {
buf.write_char('<')
buf.write_string(url)
buf.write_char('>')
}
Inline::Image(alt~, url~, title~, ..) => {
buf.write_string("
buf.write_string(url)
if !title.is_empty() {
buf.write_string(" \"")
buf.write_string(title)
buf.write_char('"')
}
buf.write_char(')')
}
Inline::RefImage(alt~, label~, ..) => {
buf.write_string("![")
buf.write_string(alt)
buf.write_string("][")
buf.write_string(label)
buf.write_char(']')
}
Inline::HtmlInline(html~, ..) => buf.write_string(html)
Inline::FootnoteReference(label~, ..) => {
buf.write_string("[^")
buf.write_string(label)
buf.write_char(']')
}
}
}