diff --git a/src/main.odin b/src/main.odin index f7a1540..23b5932 100644 --- a/src/main.odin +++ b/src/main.odin @@ -138,6 +138,8 @@ HELP_TEXT :: `Usage: If there is no file provided, TypoML reads from stdin. Options: + --html Output HTML5 (default) + --html4, --html-4 Output HTML4 --title Set the HTML document title (default: "TypoML") --plain Don't wrap the output in , , and " + title := flags.title + if title == "" { + title = "TypoML" + } + + fmt.printf( + "%s\n%s%s%s\n\n", + doctype, + escape_html(title), + meta, + style, + ) + for child in root.children { + print_html5(child) + } + if !flags.no_js { + fmt.print("\n" + HTML5_TEMPLATE_PROXY_SCRIPT + "\n") + } + fmt.print("\n") +} + + +print_html5 :: proc(tok: ^token.Token) { + switch tok.type { + case token.TokenType.Root: + has_footnotes := false + for child in tok.children { + if child.type == .FootnoteDef && !has_footnotes { + fmt.print("
\n") + has_footnotes = true + } + print_html5(child) + } + + case token.TokenType.Header: + level := 1 + if v, ok := tok.value.(int); ok { + level = v + } + + b := strings.builder_make(context.temp_allocator) + for child in tok.children { + get_text_content(child, &b) + } + slug := slugifyifyifyify(strings.to_string(b)) + + fmt.printf("", level, escape_html(slug)) + for child in tok.children { + print_html5(child) + } + fmt.printf("\n", level) + + case token.TokenType.Paragraph: + only_var_defs := check_only_var_defs(tok) + if !only_var_defs { + fmt.print("

") + for child in tok.children { + print_html5(child) + } + fmt.print("

\n") + } else { + for child in tok.children { + if child.type != .BreakLine { + print_html5(child) + } + } + } + + case token.TokenType.Blockquote: + html5_render_container(tok, "blockquote") + + case token.TokenType.UnorderedList: + html5_render_container(tok, "ul") + + case token.TokenType.OrderedList: + html5_render_container(tok, "ol") + + case token.TokenType.ListItem: + fmt.print("
  • ") + for child in tok.children { + print_html5(child) + } + fmt.print("
  • \n") + + case token.TokenType.Bold: + html5_render_simple_wrapper(tok, "strong") + + case token.TokenType.Italics: + html5_render_simple_wrapper(tok, "em") + + case token.TokenType.Strikethrough: + html5_render_simple_wrapper(tok, "strike") + + case token.TokenType.Table: + html5_render_container(tok, "table") + + case token.TokenType.TableHeaderRow: + fmt.print("") + for child in tok.children { + html5_render_aligned_cell(child, "th") + } + fmt.print("\n") + + case token.TokenType.TableRow: + fmt.print("") + for child in tok.children { + print_html5(child) + } + fmt.print("\n") + + case token.TokenType.TableCell: + html5_render_aligned_cell(tok, "td") + + case token.TokenType.TableSeparator: + fmt.print("\n") + + case token.TokenType.Left: + html5_render_div_wrapper(tok, "left") + + case token.TokenType.Right: + html5_render_div_wrapper(tok, "right") + + case token.TokenType.Middle: + html5_render_div_wrapper(tok, "center") + + case token.TokenType.FootnoteRef: + if id, ok := tok.value.(string); ok { + fmt.printf( + "%s", + escape_html(id), + escape_html(id), + escape_html(id), + ) + } + + case token.TokenType.FootnoteDef: + if id, ok := tok.value.(string); ok { + fmt.printf( + "
    ^ ", + escape_html(id), + escape_html(id), + ) + for child in tok.children { + print_html5(child) + } + fmt.print("
    \n") + } + + case token.TokenType.CodeBlock: + lang := "" + if v, ok := tok.value.(string); ok && v != "" { + lang = v + } + if lang != "" { + fmt.printf("
    ", lang)
    +		} else {
    +			fmt.print("
    ")
    +		}
    +		for i := 0; i < len(tok.children); i += 1 {
    +			print_html5(tok.children[i])
    +			if i + 1 < len(tok.children) {
    +				fmt.print("\n")
    +			}
    +		}
    +		fmt.print("\n
    \n") + + case token.TokenType.InlineCode: + if code, ok := tok.value.(string); ok { + fmt.printf("%s", escape_html(code)) + } + + case token.TokenType.HorizontalRule: + fmt.print("
    \n") + + case token.TokenType.Underline: + fmt.print("") + for child in tok.children { + print_html5(child) + } + fmt.print("") + + case token.TokenType.Superscript: + fmt.print("") + for child in tok.children { + print_html5(child) + } + fmt.print("") + + case token.TokenType.Subscript: + fmt.print("") + for child in tok.children { + print_html5(child) + } + fmt.print("") + + case token.TokenType.HeaderLink: + if target, ok := tok.value.(string); ok { + slug := slugifyifyifyify(target) + fmt.printf("", escape_html(slug)) + for child in tok.children { + print_html5(child) + } + fmt.print("") + } + + case token.TokenType.Link: + if url, ok := tok.value.(string); ok { + fmt.printf("", escape_html(url)) + for child in tok.children { + print_html5(child) + } + fmt.print("") + } + + case token.TokenType.Image: + if url, ok := tok.value.(string); ok { + b := strings.builder_make(context.temp_allocator) + for child in tok.children { + get_text_content(child, &b) + } + alt_text := strings.to_string(b) + fmt.printf("\"%s\"", escape_html(url), escape_html(alt_text)) + } + + case token.TokenType.Audio: + if url, ok := tok.value.(string); ok { + fmt.printf("", escape_html(url)) + } + + case token.TokenType.Video: + if url, ok := tok.value.(string); ok { + fmt.printf("", escape_html(url)) + } + + case token.TokenType.Iframe: + if url, ok := tok.value.(string); ok { + fmt.printf("", escape_html(url)) + } + + case token.TokenType.Script: + if url, ok := tok.value.(string); ok { + fmt.printf("", escape_html(url)) + } + + case token.TokenType.ScriptBlock: + if content, ok := tok.value.(string); ok { + fmt.printf("", content) + } + + case token.TokenType.Variable: + if name, ok := tok.value.(string); ok { + fmt.printf("", escape_html(name)) + for child in tok.children { + print_html5(child) + } + fmt.print("") + } + + case token.TokenType.VariableDef: + if name, ok := tok.value.(string); ok { + b := strings.builder_make(context.temp_allocator) + for child in tok.children { + get_text_content(child, &b) + } + val := strings.to_string(b) + fmt.printf( + "", + escape_html(name), + escape_html(val), + ) + } + + case token.TokenType.BreakLine: + fmt.print("
    \n") + + case token.TokenType.Text: + if v, ok := tok.value.(string); ok { + fmt.print(escape_html(v)) + } + for child in tok.children { + print_html5(child) + } + } +} diff --git a/src/renderer/renderer.odin b/src/renderer/renderer.odin new file mode 100644 index 0000000..cd80ec6 --- /dev/null +++ b/src/renderer/renderer.odin @@ -0,0 +1,27 @@ +package renderer + +import "../token" +import "core:fmt" + +OutputMode :: enum { + HTML5, + HTML4, +} + +DocumentFlags :: struct { + plain: bool, + no_js: bool, + title: string, + print_tree: bool, + help: bool, + mode: OutputMode, +} + +print_document :: proc(root: ^token.Token, flags: DocumentFlags) { + switch flags.mode { + case .HTML5: + print_html5_document(root, flags) + case .HTML4: + print_html4_document(root, flags) + } +}