diff --git a/README.tlm b/README.tlm index 8c217c9..9df9e51 100644 --- a/README.tlm +++ b/README.tlm @@ -41,5 +41,11 @@ Text under a blockquote [#named] | table | row | with | | some | ***content*** | in | +```odin +main :: proc() { + fmt.println("Hello, World!") +} +``` + [&1] Ordered list item 2 not included [&named] This is the definition for a named footnote diff --git a/src/html.odin b/src/html.odin index 70081bf..a53ddbc 100644 --- a/src/html.odin +++ b/src/html.odin @@ -187,6 +187,29 @@ print_html :: proc(token: ^Token) { fmt.print("\n") } + case TokenType.CodeBlock: + lang := "" + if v, ok := token.value.(string); ok && v != "" { + lang = v + } + if lang != "" { + fmt.printf("
", 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", code)
+ }
+
case TokenType.BreakLine:
fmt.print("
\n")
diff --git a/src/main.odin b/src/main.odin
index 551e5f3..ee6a502 100644
--- a/src/main.odin
+++ b/src/main.odin
@@ -59,6 +59,10 @@ print_token :: proc(token: ^Token, depth: int = 0) {
type_str = "FootnoteDef"
case TokenType.FootnoteRef:
type_str = "FootnoteRef"
+ case TokenType.CodeBlock:
+ type_str = "CodeBlock"
+ case TokenType.InlineCode:
+ type_str = "InlineCode"
}
value_str := ""
diff --git a/src/parser.odin b/src/parser.odin
index 5f688c5..b567152 100644
--- a/src/parser.odin
+++ b/src/parser.odin
@@ -26,6 +26,8 @@ TokenType :: enum {
Middle,
FootnoteDef,
FootnoteRef,
+ CodeBlock,
+ InlineCode,
}
TokenValue :: union {
@@ -249,12 +251,61 @@ parse_inline_style :: proc(token: ^Token, symbol: byte, toggles: []StyleToggle)
}
pass_through_children :: proc(token: ^Token) {
+ if token.type == .CodeBlock || token.type == .InlineCode {
+ return
+ }
parse_inline_style(token, '*', []StyleToggle{{2, .Bold}, {1, .Italics}})
parse_inline_style(token, '~', []StyleToggle{{2, .Strikethrough}})
parse_inline_style(token, '-', []StyleToggle{{2, .Strikethrough}})
}
+parse_inline_code :: proc(token: ^Token) {
+ if token.type == .CodeBlock || token.type == .InlineCode {
+ return
+ }
+ if token.children != nil {
+ for i := 0; i < len(token.children); i += 1 {
+ parse_inline_code(token.children[i])
+ }
+ }
+
+ if token.type == .Text {
+ str, ok := token.value.(string)
+ if !ok {
+ return
+ }
+
+ start_idx := strings.index_byte(str, '`')
+ if start_idx == -1 {
+ return
+ }
+
+ end_idx := strings.index_byte(str[start_idx + 1:], '`')
+ if end_idx == -1 {
+ return
+ }
+ end_idx += start_idx + 1
+
+ code := str[start_idx + 1:end_idx]
+
+ token.value = nil
+
+ if start_idx > 0 {
+ push_token(token, .Text, str[:start_idx])
+ }
+ push_token(token, .InlineCode, code)
+
+ if end_idx + 1 < len(str) {
+ rem := push_token(token, .Text, str[end_idx + 1:])
+ parse_inline_code(rem)
+ }
+ }
+}
+
parse_inline_footnotes :: proc(token: ^Token) {
+ if token.type == .CodeBlock || token.type == .InlineCode {
+ return
+ }
if token.children != nil {
for i := 0; i < len(token.children); i += 1 {
parse_inline_footnotes(token.children[i])
@@ -295,6 +346,9 @@ parse_inline_footnotes :: proc(token: ^Token) {
}
add_breaklines :: proc(token: ^Token) {
+ if token.type == .CodeBlock {
+ return
+ }
if token.children == nil {
return
}
@@ -331,9 +385,28 @@ parse :: proc(lines: []string, allocator := context.allocator) -> Token {
// FIRST PASS
+ in_code_block := false
+
for untrimmed_line, line_index in lines {
line := strings.trim_space(untrimmed_line)
+ if in_code_block {
+ if strings.has_prefix(line, "```") {
+ in_code_block = false
+ current_token = &root
+ } else {
+ push_token(current_token, TokenType.Text, untrimmed_line)
+ }
+ continue
+ }
+
+ if strings.has_prefix(line, "```") {
+ lang := strings.trim_space(line[3:])
+ current_token = push_token(&root, TokenType.CodeBlock, lang)
+ in_code_block = true
+ continue
+ }
+
if len(line) == 0 {
current_token = &root
continue
@@ -441,6 +514,7 @@ parse :: proc(lines: []string, allocator := context.allocator) -> Token {
// THIRD PASS
for token in root.children {
+ parse_inline_code(token)
pass_through_children(token)
parse_inline_footnotes(token)
}