package main import "core:fmt" import "core:strings" import "core:unicode" escape_html :: proc(s: string, allocator := context.temp_allocator) -> string { escaped := decode_escapes(s, allocator) b := strings.builder_make(allocator) for ch in escaped { switch ch { case '&': strings.write_string(&b, "&") case '<': strings.write_string(&b, "<") case '>': strings.write_string(&b, ">") case '"': strings.write_string(&b, """) case: strings.write_rune(&b, ch) } } return strings.to_string(b) } get_text_content :: proc(token: ^Token, b: ^strings.Builder) { if token.type == .Text { if v, ok := token.value.(string); ok { strings.write_string(b, v) } } for child in token.children { get_text_content(child, b) } } check_only_var_defs :: proc(token: ^Token) -> bool { for child in token.children { if child.type == .VariableDef || child.type == .BreakLine { continue } if child.type == .Text { if child.value != nil { if v, ok := child.value.(string); ok && v != "" { return false } } has_non_var_def := false for gc in child.children { if gc.type != .VariableDef { has_non_var_def = true break } } if has_non_var_def { return false } continue } return false } return true } slugifyifyifyify :: proc(text: string) -> string { b := strings.builder_make(context.temp_allocator) for ch in text { lower_ch := unicode.to_lower(ch) if unicode.is_letter(lower_ch) || unicode.is_digit(lower_ch) { strings.write_rune(&b, lower_ch) } else if lower_ch == ' ' || lower_ch == '_' || lower_ch == '-' { strings.write_rune(&b, '-') } } res := strings.to_string(b) for { new_res, replaced := strings.replace_all(res, "--", "-", context.temp_allocator) if !replaced { break } res = new_res } res = strings.trim(res, "-") return res } print_html :: proc(token: ^Token) { switch token.type { case TokenType.Root: has_footnotes := false for child in token.children { if child.type == .FootnoteDef && !has_footnotes { fmt.print("
") for child in token.children { print_html(child) } fmt.print("
\n") } else { for child in token.children { if child.type != .BreakLine { print_html(child) } } } case TokenType.Blockquote: fmt.print("\n") for child in token.children { print_html(child) } fmt.print("\n") case TokenType.UnorderedList: fmt.print("
", lang)
} else {
fmt.print("")
}
for i := 0; i < len(token.children); i += 1 {
print_html(token.children[i])
if i + 1 < len(token.children) {
fmt.print("\n")
}
}
fmt.print("\n
\n")
case TokenType.InlineCode:
if code, ok := token.value.(string); ok {
fmt.printf("%s", escape_html(code))
}
case TokenType.HorizontalRule:
fmt.print("
\n")
case TokenType.Underline:
fmt.print("")
for child in token.children {
print_html(child)
}
fmt.print("")
case TokenType.Superscript:
fmt.print("")
for child in token.children {
print_html(child)
}
fmt.print("")
case TokenType.Subscript:
fmt.print("")
for child in token.children {
print_html(child)
}
fmt.print("")
case TokenType.HeaderLink:
if target, ok := token.value.(string); ok {
slug := slugifyifyifyify(target)
fmt.printf("", escape_html(slug))
for child in token.children {
print_html(child)
}
fmt.print("")
}
case TokenType.Link:
if url, ok := token.value.(string); ok {
fmt.printf("", escape_html(url))
for child in token.children {
print_html(child)
}
fmt.print("")
}
case TokenType.Image:
if url, ok := token.value.(string); ok {
b := strings.builder_make(context.temp_allocator)
for child in token.children {
get_text_content(child, &b)
}
alt_text := strings.to_string(b)
fmt.printf("
", escape_html(url), escape_html(alt_text))
}
case TokenType.Audio:
if url, ok := token.value.(string); ok {
mime := detect_mime_type(url)
b := strings.builder_make(context.temp_allocator)
for child in token.children {
get_text_content(child, &b)
}
alt_text := strings.to_string(b)
if alt_text == "" {
alt_text = url
}
fmt.printf("\n")
}
case TokenType.Video:
if url, ok := token.value.(string); ok {
mime := detect_mime_type(url)
b := strings.builder_make(context.temp_allocator)
for child in token.children {
get_text_content(child, &b)
}
alt_text := strings.to_string(b)
if alt_text == "" {
alt_text = url
}
fmt.printf("\n")
}
case TokenType.Iframe:
if url, ok := token.value.(string); ok {
fmt.printf("", escape_html(url))
}
case TokenType.Script:
if url, ok := token.value.(string); ok {
fmt.printf("", escape_html(url))
}
case TokenType.ScriptBlock:
if content, ok := token.value.(string); ok {
fmt.printf("", content)
}
case TokenType.Variable:
if name, ok := token.value.(string); ok {
fmt.printf("", escape_html(name))
for child in token.children {
print_html(child)
}
fmt.print("")
}
case TokenType.VariableDef:
if name, ok := token.value.(string); ok {
b := strings.builder_make(context.temp_allocator)
for child in token.children {
get_text_content(child, &b)
}
val := strings.to_string(b)
fmt.printf(
"",
escape_html(name),
escape_html(val),
)
}
case TokenType.BreakLine:
fmt.print("
\n")
case TokenType.Text:
if v, ok := token.value.(string); ok {
fmt.print(escape_html(v))
}
for child in token.children {
print_html(child)
}
}
}