Footnotes
This commit is contained in:
+5
-2
@@ -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
|
||||
|
||||
@@ -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("<hr class=\"footnotes-sep\">\n")
|
||||
has_footnotes = true
|
||||
}
|
||||
print_html(child)
|
||||
}
|
||||
|
||||
@@ -168,6 +173,20 @@ print_html :: proc(token: ^Token) {
|
||||
}
|
||||
fmt.print("</div>")
|
||||
|
||||
case TokenType.FootnoteRef:
|
||||
if id, ok := token.value.(string); ok {
|
||||
fmt.printf("<a href=\"#fn-%s\" id=\"ref-%s\"><sup>%s</sup></a>", id, id, id)
|
||||
}
|
||||
|
||||
case TokenType.FootnoteDef:
|
||||
if id, ok := token.value.(string); ok {
|
||||
fmt.printf("<div class=\"footnote\" id=\"fn-%s\"><a href=\"#ref-%s\">^</a> ", id, id)
|
||||
for child in token.children {
|
||||
print_html(child)
|
||||
}
|
||||
fmt.print("</div>\n")
|
||||
}
|
||||
|
||||
case TokenType.BreakLine:
|
||||
fmt.print("<br>\n")
|
||||
|
||||
|
||||
@@ -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 := ""
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+13
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user