This commit is contained in:
2026-07-14 21:33:54 +02:00
parent 33e4c0ce62
commit 9355c098e0
5 changed files with 198 additions and 0 deletions
+1
View File
@@ -12,6 +12,7 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam blandit dolor nibh,
$[https://krzak.org/krzak-icon.png]
$(https://krzak.org/krzak-icon.png)
$[https://krzak.org/krzak-icon.png|img]
*italic*
**bold**
+7
View File
@@ -2,6 +2,13 @@ package main
import "core:strings"
is_url :: proc(url: string) -> bool {
if strings.contains(url, ":") || strings.contains(url, "/") || strings.contains(url, ".") {
return true
}
return false
}
get_ext :: proc(url: string) -> string {
clean := url
if question := strings.index_byte(clean, '?'); question != -1 {
+33
View File
@@ -278,6 +278,39 @@ print_html :: proc(token: ^Token) {
fmt.print("</a>")
}
case TokenType.Image:
if url, ok := token.value.(string); ok {
b := strings.builder_make(context.temp_allocator)
for child in token.children {
get_text_content(child, &b)
}
alt_text := strings.to_string(b)
fmt.printf("<img src=\"%s\" alt=\"%s\">", url, alt_text)
}
case TokenType.Audio:
if url, ok := token.value.(string); ok {
fmt.printf("<audio controls src=\"%s\">", url)
for child in token.children {
print_html(child)
}
fmt.print("</audio>")
}
case TokenType.Video:
if url, ok := token.value.(string); ok {
fmt.printf("<video controls src=\"%s\">", url)
for child in token.children {
print_html(child)
}
fmt.print("</video>")
}
case TokenType.Iframe:
if url, ok := token.value.(string); ok {
fmt.printf("<iframe src=\"%s\"></iframe>", url)
}
case TokenType.BreakLine:
fmt.print("<br>\n")
+8
View File
@@ -75,6 +75,14 @@ print_token :: proc(token: ^Token, depth: int = 0) {
type_str = "HeaderLink"
case TokenType.Link:
type_str = "Link"
case TokenType.Image:
type_str = "Image"
case TokenType.Audio:
type_str = "Audio"
case TokenType.Video:
type_str = "Video"
case TokenType.Iframe:
type_str = "Iframe"
}
value_str := ""
+149
View File
@@ -34,6 +34,10 @@ TokenType :: enum {
Subscript,
HeaderLink,
Link,
Image,
Audio,
Video,
Iframe,
}
TokenValue :: union {
@@ -476,6 +480,150 @@ parse_links :: proc(token: ^Token) {
}
}
find_embed :: proc(
str: string,
) -> (
start_idx, end_idx: int,
is_embed: bool,
url: string,
alt: string,
embed_type: string,
) {
for i := 0; i < len(str); i += 1 {
if str[i] == '$' && i + 1 < len(str) {
if str[i + 1] == '[' {
if end, alt_text, url_text, ok := match_pair(str[i + 1:], '[', ']', '(', ')'); ok {
clean_url := url_text
type_hint := ""
if pipe_idx := strings.index_byte(url_text, '|'); pipe_idx != -1 {
clean_url = url_text[:pipe_idx]
type_hint = url_text[pipe_idx + 1:]
}
if is_url(clean_url) {
e_type := ""
if type_hint != "" {
e_type = parse_type_hint(type_hint)
}
if e_type == "" {
e_type = detect_embed_type(clean_url)
}
return i, i + 1 + end, true, clean_url, alt_text, e_type
}
}
if end, inner, ok := match_single(str[i + 1:], '[', ']'); ok {
url_text := inner
type_hint := ""
if pipe_idx := strings.index_byte(inner, '|'); pipe_idx != -1 {
url_text = inner[:pipe_idx]
type_hint = inner[pipe_idx + 1:]
}
if is_url(url_text) {
e_type := ""
if type_hint != "" {
e_type = parse_type_hint(type_hint)
}
if e_type == "" {
e_type = detect_embed_type(url_text)
}
return i, i + 1 + end, true, url_text, url_text, e_type
}
}
} else if str[i + 1] == '(' {
if end, url_text, alt_text, ok := match_pair(str[i + 1:], '(', ')', '[', ']'); ok {
clean_url := url_text
type_hint := ""
if pipe_idx := strings.index_byte(url_text, '|'); pipe_idx != -1 {
clean_url = url_text[:pipe_idx]
type_hint = url_text[pipe_idx + 1:]
}
if is_url(clean_url) {
e_type := ""
if type_hint != "" {
e_type = parse_type_hint(type_hint)
}
if e_type == "" {
e_type = detect_embed_type(clean_url)
}
return i, i + 1 + end, true, clean_url, alt_text, e_type
}
}
if end, inner, ok := match_single(str[i + 1:], '(', ')'); ok {
url_text := inner
type_hint := ""
if pipe_idx := strings.index_byte(inner, '|'); pipe_idx != -1 {
url_text = inner[:pipe_idx]
type_hint = inner[pipe_idx + 1:]
}
if is_url(url_text) {
e_type := ""
if type_hint != "" {
e_type = parse_type_hint(type_hint)
}
if e_type == "" {
e_type = detect_embed_type(url_text)
}
return i, i + 1 + end, true, url_text, url_text, e_type
}
}
}
}
}
return -1, -1, false, "", "", ""
}
parse_embeds :: 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_embeds(token.children[i])
}
}
if token.type == .Text {
str, ok := token.value.(string)
if !ok {
return
}
start_idx, end_idx, is_embed, url, alt, e_type := find_embed(str)
if !is_embed {
return
}
token.value = nil
if start_idx > 0 {
push_token(token, .Text, str[:start_idx])
}
embed_token_type: TokenType
if e_type == "image" {
embed_token_type = .Image
} else if e_type == "audio" {
embed_token_type = .Audio
} else if e_type == "video" {
embed_token_type = .Video
} else {
embed_token_type = .Iframe
}
embed_token := push_token(token, embed_token_type, url)
push_token(embed_token, .Text, alt)
if end_idx < len(str) {
rem := push_token(token, .Text, str[end_idx:])
parse_embeds(rem)
}
}
}
add_breaklines :: proc(token: ^Token) {
if token.type == .CodeBlock {
return
@@ -667,6 +815,7 @@ parse :: proc(lines: []string, allocator := context.allocator) -> Token {
for token in root.children {
parse_inline_code(token)
parse_embeds(token)
parse_links(token)
parse_inline_footnotes(token)
pass_through_children(token)