diff --git a/README.tlm b/README.tlm
index 020e849..8c217c9 100644
--- a/README.tlm
+++ b/README.tlm
@@ -1,7 +1,7 @@
! Heading
!! Smolr heading
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam blandit dolor nibh, vitae tempor enim pretium non. Sed in condimentum turpis. Vivamus placerat molestie ullamcorper. Maecenas nec risus nibh. Nullam vel vestibulum sapien. Integer ante erat, aliquam id tellus in, malesuada finibus nunc. Sed porttitor ante orci, eget molestie nibh posuere nec.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam blandit dolor nibh, vitae tempor enim pretium non. Sed in condimentum turpis. Vivamus placerat molestie ullamcorper. Maecenas nec risus nibh. Nullam vel vestibulum sapien. Integer ante erat, aliquam id tellus in, malesuada finibus nunc. Sed porttitor ante orci, eget molestie nibh posuere nec.
#[Link on the right](http://example.com) >>
(http://example.com)[Example.com]# <<
@@ -26,12 +26,12 @@ The **VARIABLE** is $(variable)
- List item 1
. List item 2
-1. Ordered list item
+1. Ordered list item [#1]
> This is a sample blockquote
> Bon apetit!
-Text under a blockquote
+Text under a blockquote [#named]
**This *is* bold *and* italics *mixed** TOGETHER*
@@ -40,3 +40,6 @@ Text under a blockquote
| This << | is >> | a ^^ |
| table | row | with |
| some | ***content*** | in |
+
+[&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 7f29771..70081bf 100644
--- a/src/html.odin
+++ b/src/html.odin
@@ -5,7 +5,12 @@ import "core:fmt"
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("
\n")
+ has_footnotes = true
+ }
print_html(child)
}
@@ -168,6 +173,20 @@ print_html :: proc(token: ^Token) {
}
fmt.print("")
+ case TokenType.FootnoteRef:
+ if id, ok := token.value.(string); ok {
+ fmt.printf("%s", id, id, id)
+ }
+
+ case TokenType.FootnoteDef:
+ if id, ok := token.value.(string); ok {
+ fmt.printf("\n")
+ }
+
case TokenType.BreakLine:
fmt.print("
\n")
diff --git a/src/main.odin b/src/main.odin
index 735d58d..551e5f3 100644
--- a/src/main.odin
+++ b/src/main.odin
@@ -55,6 +55,10 @@ print_token :: proc(token: ^Token, depth: int = 0) {
type_str = "Right"
case TokenType.Middle:
type_str = "Middle"
+ case TokenType.FootnoteDef:
+ type_str = "FootnoteDef"
+ case TokenType.FootnoteRef:
+ type_str = "FootnoteRef"
}
value_str := ""
diff --git a/src/parser.odin b/src/parser.odin
index 4e03ac9..5f688c5 100644
--- a/src/parser.odin
+++ b/src/parser.odin
@@ -24,6 +24,8 @@ TokenType :: enum {
Left,
Right,
Middle,
+ FootnoteDef,
+ FootnoteRef,
}
TokenValue :: union {
@@ -141,6 +143,18 @@ parse_header :: proc(line: string) -> (int, string) {
return lvl, line[lvl + 1:]
}
+parse_footnote_def :: proc(line: string) -> (string, string, bool) {
+ if strings.has_prefix(line, "[&") {
+ idx := strings.index_byte(line, ']')
+ if idx != -1 {
+ id := line[2:idx]
+ text := strings.trim_space(line[idx + 1:])
+ return id, text, true
+ }
+ }
+ return "", "", false
+}
+
StyleToggle :: struct {
amount: int,
type: TokenType,
@@ -240,6 +254,46 @@ pass_through_children :: proc(token: ^Token) {
parse_inline_style(token, '-', []StyleToggle{{2, .Strikethrough}})
}
+parse_inline_footnotes :: proc(token: ^Token) {
+ if token.children != nil {
+ for i := 0; i < len(token.children); i += 1 {
+ parse_inline_footnotes(token.children[i])
+ }
+ }
+
+ if token.type == .Text {
+ str, ok := token.value.(string)
+ if !ok {
+ return
+ }
+
+ start_idx := strings.index(str, "[#")
+ if start_idx == -1 {
+ return
+ }
+
+ end_idx := strings.index_byte(str[start_idx:], ']')
+ if end_idx == -1 {
+ return
+ }
+ end_idx += start_idx
+
+ id := str[start_idx + 2:end_idx]
+
+ token.value = nil
+
+ if start_idx > 0 {
+ push_token(token, .Text, str[:start_idx])
+ }
+ push_token(token, .FootnoteRef, id)
+
+ if end_idx + 1 < len(str) {
+ rem := push_token(token, .Text, str[end_idx + 1:])
+ parse_inline_footnotes(rem)
+ }
+ }
+}
+
add_breaklines :: proc(token: ^Token) {
if token.children == nil {
return
@@ -293,6 +347,13 @@ parse :: proc(lines: []string, allocator := context.allocator) -> Token {
continue
}
+ if id, ftext, ok := parse_footnote_def(line); ok {
+ current_token = push_token(&root, TokenType.FootnoteDef, id)
+ push_text(current_token, ftext)
+ current_token = &root
+ continue
+ }
+
if strings.has_prefix(text, "> ") {
if current_token.type != TokenType.Blockquote {
current_token = push_token(&root, TokenType.Blockquote, nil)
@@ -381,7 +442,24 @@ parse :: proc(lines: []string, allocator := context.allocator) -> Token {
for token in root.children {
pass_through_children(token)
+ parse_inline_footnotes(token)
}
+ // FOURTH PASS
+
+ footnotes: [dynamic]^Token
+ new_root_children: [dynamic]^Token
+ for child in root.children {
+ if child.type == .FootnoteDef {
+ append(&footnotes, child)
+ } else {
+ append(&new_root_children, child)
+ }
+ }
+ for child in footnotes {
+ append(&new_root_children, child)
+ }
+ root.children = new_root_children
+
return root
}
diff --git a/styles.css b/styles.css
index ef745d6..0cfa1c8 100644
--- a/styles.css
+++ b/styles.css
@@ -59,3 +59,16 @@ tr.table-sep td {
padding: 0;
height: 0;
}
+hr.footnotes-sep {
+ border: 0;
+ border-top: 1px solid #444;
+ margin: 2em 0 1em 0;
+}
+.footnote {
+ font-size: 14px;
+ color: #a0a0a0;
+ margin-bottom: 0.5em;
+}
+.footnote a {
+ text-decoration: none;
+}