add: parse_image_line, parse_link_line

This commit is contained in:
trisua 2025-07-24 01:06:03 -04:00
parent d8167aa06f
commit 9fe5735127
9 changed files with 234 additions and 25 deletions

View file

@ -2,7 +2,9 @@ use std::collections::HashSet;
pub fn render_markdown(input: &str) -> String {
let html = tetratto_shared::markdown::render_markdown_dirty(&parse_text_color(
&parse_highlight(&parse_underline(&parse_comment(&parse_image_size(input)))),
&parse_highlight(&parse_link(&parse_image(&parse_image_size(
&parse_underline(&parse_comment(input)),
)))),
));
let mut allowed_attributes = HashSet::new();
@ -16,7 +18,13 @@ pub fn render_markdown(input: &str) -> String {
allowed_attributes.insert("src");
allowed_attributes.insert("style");
tetratto_shared::markdown::clean_html(html, allowed_attributes)
tetratto_shared::markdown::clean_html(
html.replace("<style>", "<span>:temp_style")
.replace("</style>", "</span>:temp_style"),
allowed_attributes,
)
.replace("<span>:temp_style", "<style>")
.replace("</span>:temp_style", "</style>")
}
fn parse_text_color_line(output: &mut String, buffer: &mut String, line: &str) {
@ -258,6 +266,11 @@ fn parse_comment_line(output: &mut String, _: &mut String, line: &str) {
return;
}
if line == "[..]" {
output.push_str(" ");
return;
}
output.push_str(line);
}
@ -323,17 +336,7 @@ fn parse_image_size_line(output: &mut String, buffer: &mut String, line: &str) {
if in_size && in_size_rhs {
// end
output.push_str(&format!(
"<span style=\"width: {}; height: {}\" class=\"img_sizer\">![{buffer}</span>",
if size_lhs == "auto" {
size_lhs
} else {
format!("{size_lhs}px")
},
if size_rhs == "auto" {
size_rhs
} else {
format!("{size_rhs}px")
}
"<span style=\"width: {size_lhs}; height: {size_rhs}\" class=\"img_sizer\">![{buffer}</span>"
));
size_lhs = String::new();
@ -380,6 +383,174 @@ fn parse_image_size_line(output: &mut String, buffer: &mut String, line: &str) {
}
}
fn parse_image_line(output: &mut String, buffer: &mut String, line: &str) {
let mut image_possible = false;
let mut in_image = false;
let mut in_alt = false;
let mut in_src = false;
let mut alt = String::new();
for char in line.chars() {
if image_possible && char != '[' {
image_possible = false;
output.push('!');
}
match char {
'[' => {
if image_possible {
in_image = true;
image_possible = false;
in_alt = true;
continue;
}
if in_image {
buffer.push(char);
} else {
output.push(char);
}
}
']' => {
if in_alt {
in_alt = false;
in_src = true;
continue;
}
output.push(char);
}
'(' => {
if in_src {
continue;
}
if in_image {
buffer.push(char);
} else {
output.push(char);
}
}
')' => {
if in_image {
// end
output.push_str(&format!(
"<img loading=\"lazy\" alt=\"{alt}\" src=\"{buffer}\" />"
));
alt = String::new();
in_alt = false;
in_src = false;
in_image = false;
image_possible = false;
buffer.clear();
continue;
}
output.push(char);
}
'!' => {
// flush buffer
output.push_str(&buffer);
buffer.clear();
// ...
image_possible = true;
}
_ => {
if in_image {
if in_alt {
alt.push(char)
} else {
buffer.push(char);
}
} else {
output.push(char)
}
}
}
}
}
fn parse_link_line(output: &mut String, buffer: &mut String, line: &str) {
let mut in_link = false;
let mut in_text = false;
let mut in_src = false;
let mut text = String::new();
for (i, char) in line.chars().enumerate() {
match char {
'[' => {
// flush buffer
output.push_str(&buffer);
buffer.clear();
// scan for closing, otherwise quit
let haystack = &line[i..];
if !haystack.contains("]") {
output.push('[');
continue;
}
// ...
in_link = true;
in_text = true;
}
']' => {
if in_text {
in_text = false;
in_src = true;
continue;
}
output.push(char);
}
'(' => {
if in_src {
continue;
}
if in_link {
buffer.push(char);
} else {
output.push(char);
}
}
')' => {
if in_link {
// end
output.push_str(&format!(
"<a href=\"{buffer}\" rel=\"noopener noreferrer\">{text}</a>"
));
text = String::new();
in_text = false;
in_src = false;
in_link = false;
buffer.clear();
continue;
}
output.push(char);
}
_ => {
if in_link {
if in_text {
text.push(char)
} else {
buffer.push(char);
}
} else {
output.push(char)
}
}
}
}
}
/// Helper macro to quickly allow parsers to ignore fenced code blocks.
macro_rules! parser_ignores_pre {
($body:ident, $input:ident) => {{
@ -427,3 +598,11 @@ pub fn parse_comment(input: &str) -> String {
pub fn parse_image_size(input: &str) -> String {
parser_ignores_pre!(parse_image_size_line, input)
}
pub fn parse_image(input: &str) -> String {
parser_ignores_pre!(parse_image_line, input)
}
pub fn parse_link(input: &str) -> String {
parser_ignores_pre!(parse_link_line, input)
}