Escaping
This commit is contained in:
+4
-1
@@ -8,7 +8,7 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam blandit dolor nibh,
|
|||||||
#[Link to nekoweb.org in the middle](https://n0va.nekoweb.org) ^^
|
#[Link to nekoweb.org in the middle](https://n0va.nekoweb.org) ^^
|
||||||
#[https://krzak.org]
|
#[https://krzak.org]
|
||||||
#(https://krzak.org)
|
#(https://krzak.org)
|
||||||
^ Links with no alt text
|
\^ Links with no alt text
|
||||||
|
|
||||||
$[https://krzak.org/krzak-icon.png|img]
|
$[https://krzak.org/krzak-icon.png|img]
|
||||||
$[/staircase.mp3]
|
$[/staircase.mp3]
|
||||||
@@ -56,6 +56,8 @@ Here is some __underlined__ text
|
|||||||
|
|
||||||
[Go to Top](#Heading)
|
[Go to Top](#Heading)
|
||||||
|
|
||||||
|
! Escaped star: \*
|
||||||
|
|
||||||
[&&1] Ordered list item 2 not included
|
[&&1] Ordered list item 2 not included
|
||||||
[&&named] This is the definition for a named footnote
|
[&&named] This is the definition for a named footnote
|
||||||
|
|
||||||
@@ -65,6 +67,7 @@ $(counter=0)
|
|||||||
$(link=https://git.krzak.org/N0VA/TypoML)
|
$(link=https://git.krzak.org/N0VA/TypoML)
|
||||||
|
|
||||||
`tlm.counter` = $(counter)
|
`tlm.counter` = $(counter)
|
||||||
|
\^ This is JS!!!
|
||||||
|
|
||||||
#($(link))[Repo link]
|
#($(link))[Repo link]
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -5,8 +5,10 @@ import "core:strings"
|
|||||||
import "core:unicode"
|
import "core:unicode"
|
||||||
|
|
||||||
escape_html :: proc(s: string, allocator := context.temp_allocator) -> string {
|
escape_html :: proc(s: string, allocator := context.temp_allocator) -> string {
|
||||||
|
escaped := decode_escapes(s, allocator)
|
||||||
|
|
||||||
b := strings.builder_make(allocator)
|
b := strings.builder_make(allocator)
|
||||||
for ch in s {
|
for ch in escaped {
|
||||||
switch ch {
|
switch ch {
|
||||||
case '&':
|
case '&':
|
||||||
strings.write_string(&b, "&")
|
strings.write_string(&b, "&")
|
||||||
|
|||||||
+109
-44
@@ -121,6 +121,15 @@ push_text :: proc(parent: ^Token, text: string) {
|
|||||||
push_token(target, TokenType.Text, cleaned)
|
push_token(target, TokenType.Text, cleaned)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
push_text_line :: proc(target: ^Token, text: string) {
|
||||||
|
if len(target.children) > 0 {
|
||||||
|
br := new(Token)
|
||||||
|
br^ = Token{TokenType.BreakLine, nil, nil, target}
|
||||||
|
append(&target.children, br)
|
||||||
|
}
|
||||||
|
push_text(target, text)
|
||||||
|
}
|
||||||
|
|
||||||
strip_alignment_markers :: proc(text: string) -> string {
|
strip_alignment_markers :: proc(text: string) -> string {
|
||||||
trimmed := strings.trim_space(text)
|
trimmed := strings.trim_space(text)
|
||||||
if strings.has_suffix(trimmed, ">>") {
|
if strings.has_suffix(trimmed, ">>") {
|
||||||
@@ -144,6 +153,92 @@ strip_alignment_markers :: proc(text: string) -> string {
|
|||||||
return trimmed
|
return trimmed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESCAPE_PLACEHOLDER_BASE :: 0xE000 // Unicode Private Use Area
|
||||||
|
|
||||||
|
is_escapable_char :: proc(b: byte) -> bool {
|
||||||
|
switch b {
|
||||||
|
case '\\',
|
||||||
|
'*',
|
||||||
|
'_',
|
||||||
|
'~',
|
||||||
|
'^',
|
||||||
|
'`',
|
||||||
|
'[',
|
||||||
|
']',
|
||||||
|
'(',
|
||||||
|
')',
|
||||||
|
'$',
|
||||||
|
'&',
|
||||||
|
'!',
|
||||||
|
'>',
|
||||||
|
'|',
|
||||||
|
'-',
|
||||||
|
'=',
|
||||||
|
'#',
|
||||||
|
'.':
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
escape_placeholder_rune :: proc(b: byte) -> rune {
|
||||||
|
return rune(ESCAPE_PLACEHOLDER_BASE + int(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
is_escape_placeholder :: proc(r: rune) -> bool {
|
||||||
|
return r >= ESCAPE_PLACEHOLDER_BASE && r < ESCAPE_PLACEHOLDER_BASE + 256
|
||||||
|
}
|
||||||
|
|
||||||
|
escape_placeholder_to_byte :: proc(r: rune) -> byte {
|
||||||
|
return byte(int(r) - ESCAPE_PLACEHOLDER_BASE)
|
||||||
|
}
|
||||||
|
|
||||||
|
unescape_backslashes :: proc(s: string, allocator := context.temp_allocator) -> string {
|
||||||
|
if !strings.contains(s, "\\") {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
b := strings.builder_make(allocator)
|
||||||
|
i := 0
|
||||||
|
for i < len(s) {
|
||||||
|
if s[i] == '\\' && i + 1 < len(s) && is_escapable_char(s[i + 1]) {
|
||||||
|
strings.write_rune(&b, escape_placeholder_rune(s[i + 1]))
|
||||||
|
i += 2
|
||||||
|
} else {
|
||||||
|
strings.write_byte(&b, s[i])
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.to_string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
decode_escapes :: proc(s: string, allocator := context.temp_allocator) -> string {
|
||||||
|
has_placeholder := false
|
||||||
|
for r in s {
|
||||||
|
if is_escape_placeholder(r) {
|
||||||
|
has_placeholder = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !has_placeholder {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
b := strings.builder_make(allocator)
|
||||||
|
for r in s {
|
||||||
|
if is_escape_placeholder(r) {
|
||||||
|
strings.write_byte(&b, escape_placeholder_to_byte(r))
|
||||||
|
} else {
|
||||||
|
strings.write_rune(&b, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.to_string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_space_byte :: proc(b: byte) -> bool {
|
||||||
|
return b == ' ' || b == '\t'
|
||||||
|
}
|
||||||
|
|
||||||
parse_header :: proc(line: string) -> (int, string) {
|
parse_header :: proc(line: string) -> (int, string) {
|
||||||
if len(line) == 0 {
|
if len(line) == 0 {
|
||||||
return 0, line
|
return 0, line
|
||||||
@@ -221,6 +316,14 @@ parse_inline_style :: proc(token: ^Token, symbol: byte, toggles: []StyleToggle)
|
|||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preceded_by_space := symbol_start > 0 && is_space_byte(str[symbol_start - 1])
|
||||||
|
followed_by_space := i < len(str) && is_space_byte(str[i])
|
||||||
|
if preceded_by_space && followed_by_space {
|
||||||
|
push_token(current_node, TokenType.Text, str[symbol_start:i])
|
||||||
|
start = i
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for count > 0 {
|
for count > 0 {
|
||||||
matched := false
|
matched := false
|
||||||
for toggle in toggles {
|
for toggle in toggles {
|
||||||
@@ -827,40 +930,6 @@ resolve_variables :: proc(token: ^Token, vars: ^map[string]string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add_breaklines :: proc(token: ^Token) {
|
|
||||||
if token.type == .CodeBlock {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if token.children == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
new_children: [dynamic]^Token
|
|
||||||
for i := 0; i < len(token.children); i += 1 {
|
|
||||||
child := token.children[i]
|
|
||||||
add_breaklines(child)
|
|
||||||
append(&new_children, child)
|
|
||||||
is_child_inline :=
|
|
||||||
child.type == TokenType.Text ||
|
|
||||||
child.type == TokenType.Left ||
|
|
||||||
child.type == TokenType.Right ||
|
|
||||||
child.type == TokenType.Middle
|
|
||||||
is_next_inline :=
|
|
||||||
i + 1 < len(token.children) &&
|
|
||||||
(token.children[i + 1].type == TokenType.Text ||
|
|
||||||
token.children[i + 1].type == TokenType.Left ||
|
|
||||||
token.children[i + 1].type == TokenType.Right ||
|
|
||||||
token.children[i + 1].type == TokenType.Middle)
|
|
||||||
|
|
||||||
if is_child_inline && is_next_inline {
|
|
||||||
br := new(Token)
|
|
||||||
br^ = Token{TokenType.BreakLine, nil, nil, token}
|
|
||||||
append(&new_children, br)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
token.children = new_children
|
|
||||||
}
|
|
||||||
|
|
||||||
parse :: proc(lines: []string, allocator := context.allocator) -> Token {
|
parse :: proc(lines: []string, allocator := context.allocator) -> Token {
|
||||||
root := Token{TokenType.Root, nil, nil, nil}
|
root := Token{TokenType.Root, nil, nil, nil}
|
||||||
current_token := &root
|
current_token := &root
|
||||||
@@ -900,6 +969,8 @@ parse :: proc(lines: []string, allocator := context.allocator) -> Token {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
line = unescape_backslashes(line)
|
||||||
|
|
||||||
if strings.has_prefix(line, "```") {
|
if strings.has_prefix(line, "```") {
|
||||||
lang := strings.trim_space(line[3:])
|
lang := strings.trim_space(line[3:])
|
||||||
current_token = push_token(&root, TokenType.CodeBlock, lang)
|
current_token = push_token(&root, TokenType.CodeBlock, lang)
|
||||||
@@ -965,7 +1036,7 @@ parse :: proc(lines: []string, allocator := context.allocator) -> Token {
|
|||||||
push_token(current_token, TokenType.Paragraph, nil)
|
push_token(current_token, TokenType.Paragraph, nil)
|
||||||
}
|
}
|
||||||
last_p := current_token.children[len(current_token.children) - 1]
|
last_p := current_token.children[len(current_token.children) - 1]
|
||||||
push_text(last_p, text[2:])
|
push_text_line(last_p, text[2:])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1025,15 +1096,15 @@ parse :: proc(lines: []string, allocator := context.allocator) -> Token {
|
|||||||
|
|
||||||
if current_token.type == .Blockquote {
|
if current_token.type == .Blockquote {
|
||||||
last_p := current_token.children[len(current_token.children) - 1]
|
last_p := current_token.children[len(current_token.children) - 1]
|
||||||
push_text(last_p, line)
|
push_text_line(last_p, line)
|
||||||
} else if current_token.type == .UnorderedList || current_token.type == .OrderedList {
|
} else if current_token.type == .UnorderedList || current_token.type == .OrderedList {
|
||||||
last_li := current_token.children[len(current_token.children) - 1]
|
last_li := current_token.children[len(current_token.children) - 1]
|
||||||
push_text(last_li, line)
|
push_text_line(last_li, line)
|
||||||
} else {
|
} else {
|
||||||
if current_token.type != .Paragraph {
|
if current_token.type != .Paragraph {
|
||||||
current_token = push_token(&root, TokenType.Paragraph, nil)
|
current_token = push_token(&root, TokenType.Paragraph, nil)
|
||||||
}
|
}
|
||||||
push_text(current_token, line)
|
push_text_line(current_token, line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1048,12 +1119,6 @@ parse :: proc(lines: []string, allocator := context.allocator) -> Token {
|
|||||||
pass_through_children(token)
|
pass_through_children(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
// THIRD PASS
|
|
||||||
|
|
||||||
for token in root.children {
|
|
||||||
add_breaklines(token)
|
|
||||||
}
|
|
||||||
|
|
||||||
// VARIABLE RESOLUTION PASS
|
// VARIABLE RESOLUTION PASS
|
||||||
|
|
||||||
vars: map[string]string
|
vars: map[string]string
|
||||||
|
|||||||
Reference in New Issue
Block a user