phoebe/services/phoebe-discord/src/chat_conv.rs

87 lines
2.9 KiB
Rust

use discord_message_format::DiscordComponent;
use phoebe::mid_chat::{ChatContentComponent, ChatContentComponent::*, ChatMessageContent};
pub fn convert(discord_message: &[DiscordComponent<'_>]) -> ChatMessageContent {
discord_message
.iter()
.map(discord_to_mid)
.collect::<ChatMessageContent>()
}
pub fn format(message_content: &[ChatContentComponent]) -> String {
message_content.iter().map(mid_to_discord).collect()
}
fn discord_to_mid(discord: &DiscordComponent<'_>) -> ChatContentComponent {
match discord {
DiscordComponent::Plain(text) => Plain(text.to_string()),
DiscordComponent::Literal(char) => Plain(char.to_string()),
DiscordComponent::Link(link) => Link {
target: link.to_string(),
text: vec![Plain(link.to_string())],
},
DiscordComponent::Bold(content) => Bold(convert(content)),
DiscordComponent::Italic(content) => Italic(convert(content)),
DiscordComponent::Strikethrough(content) => Strikethrough(convert(content)),
DiscordComponent::Underline(content) => Underline(convert(content)),
DiscordComponent::Code(code) => Code(code.to_string()),
DiscordComponent::CodeBlock { lang, source } => CodeBlock {
lang: lang.map(|s| s.to_string()),
source: source.to_string(),
},
DiscordComponent::Spoiler(content) => Spoiler {
reason: None,
content: convert(content),
},
DiscordComponent::LineBreak => HardBreak,
DiscordComponent::Quote(content) => BlockQuote(convert(content)),
}
}
fn mid_to_discord(component: &ChatContentComponent) -> String {
match component {
Plain(text) => text.to_string(), // TODO: Escape
Link { target, text } => {
let formatted_text = format(text);
// TODO: Maybe tolerate a missing http(s) URL scheme?
if &formatted_text == target {
formatted_text
} else {
format!("{} ({})", formatted_text, target)
}
}
Italic(inner) => format!("*{}*", format(inner)),
Bold(inner) => format!("**{}**", format(inner)),
Strikethrough(inner) => format!("~~{}~~", format(inner)),
Underline(inner) => format!("__{}__", format(inner)),
Code(code) => format!("`{}`", code), // TODO: Double-grave delimiting when code contains '`'
CodeBlock { lang, source } => {
format!(
"```{}\n{}\n```",
lang.as_ref()
.map(|s| s.to_string())
.unwrap_or_else(|| "".to_string()),
source
)
}
Spoiler { content, .. } => {
format!("||{}||", format(content))
} // TODO: Spoiler reason
HardBreak => "\n".to_string(),
BlockQuote(inner) => format(inner)
.lines()
.map(|l| format!("> {}\n", l))
.collect(),
}
}