Embeds
This commit is contained in:
@@ -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**
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user