add: markdown emoji parsing

This commit is contained in:
trisua 2025-05-05 23:12:46 -04:00
parent d9234bf656
commit af67077ae7
8 changed files with 243 additions and 46 deletions

View file

@ -48,6 +48,8 @@ pub struct CustomEmoji {
pub name: String,
}
pub type EmojiParserResult = Vec<(String, usize, String)>;
impl CustomEmoji {
/// Create a new [`CustomEmoji`].
pub fn new(owner: usize, community: usize, upload_id: usize, name: String) -> Self {
@ -63,4 +65,105 @@ impl CustomEmoji {
name,
}
}
/// Replace emojis in the given input string.
pub fn replace(input: &str) -> String {
let res = Self::parse(input);
let mut out = input.to_string();
for emoji in res {
if emoji.1 == 0 {
out = out.replace(
&emoji.0,
match emojis::get_by_shortcode(&emoji.2) {
Some(e) => e.as_str(),
None => &emoji.0,
},
);
} else {
out = out.replace(
&emoji.0,
&format!(
"<img class=\"emoji\" src=\"/api/v1/communities/{}/emoji/{}\" />",
emoji.1, emoji.2
),
);
}
}
out
}
/// Parse text for emojis.
///
/// Another "great" parser, just like the mentions parser.
///
/// # Returns
/// `(capture, community id, emoji name)`
pub fn parse(input: &str) -> EmojiParserResult {
let mut out = Vec::new();
let mut buffer: String = String::new();
let mut escape: bool = false;
let mut in_emoji: bool = false;
let mut chars = input.chars();
while let Some(char) = chars.next() {
if escape == true {
buffer.push(char);
continue;
}
if char == '\\' && escape == false {
escape = true;
continue;
} else if char == ':' {
let mut community_id: String = String::new();
let mut accepting_community_id_chars: bool = true;
let mut emoji_name: String = String::new();
let mut char_count: u32 = 0; // if we're past the first 4 characters and we haven't hit a digit, stop accepting community id
while let Some(char) = chars.next() {
if (char == ':') | (char == ' ') {
in_emoji = false;
break;
}
if char.is_digit(10) && accepting_community_id_chars {
community_id.push(char);
} else if char == '.' {
// the period closes the community id
accepting_community_id_chars = false;
} else {
emoji_name.push(char);
}
if char_count >= 4 && community_id.is_empty() {
accepting_community_id_chars = false;
}
char_count += 1;
}
out.push((
format!(
":{}{emoji_name}:",
if !community_id.is_empty() {
format!("{community_id}.")
} else {
String::new()
}
),
community_id.parse::<usize>().unwrap_or(0),
emoji_name,
));
continue;
} else if in_emoji {
buffer.push(char);
}
}
out
}
}