char/phoebe

git clone https://git.t4t.associates/char/phoebe

videogame hackerImprove quality of Discord formatted output079efa5

legacy
3.5 KiB87 linesraw
1use super::{MessageComponent, MessageContent};
2use discord_message_format::DiscordComponent;
3
4impl<'a> From<&DiscordComponent<'a>> for MessageComponent {
5    fn from(discord: &DiscordComponent<'a>) -> Self {
6        match discord {
7            DiscordComponent::Plain(text) => Self::Plain(text.to_string()),
8            DiscordComponent::Literal(char) => Self::Plain(char.to_string()),
9            DiscordComponent::Link(link) => Self::Link {
10                target: link.to_string(),
11                text: vec![Self::Plain(link.to_string())],
12            },
13
14            DiscordComponent::Bold(content) => Self::Bold(convert_discord(content)),
15            DiscordComponent::Italic(content) => Self::Italic(convert_discord(content)),
16            DiscordComponent::Strikethrough(content) => {
17                Self::Strikethrough(convert_discord(content))
18            }
19            DiscordComponent::Underline(content) => Self::Underline(convert_discord(content)),
20
21            DiscordComponent::Code(code) => Self::Code(code.to_string()),
22            DiscordComponent::CodeBlock { lang, source } => Self::CodeBlock {
23                lang: lang.map(|s| s.to_string()),
24                source: source.to_string(),
25            },
26
27            DiscordComponent::Spoiler(content) => Self::Spoiler {
28                reason: None,
29                content: convert_discord(content),
30            },
31
32            DiscordComponent::LineBreak => Self::HardBreak,
33            DiscordComponent::Quote(content) => Self::BlockQuote(convert_discord(content)),
34        }
35    }
36}
37
38pub fn convert_discord(discord_message: &[DiscordComponent<'_>]) -> MessageContent {
39    discord_message
40        .iter()
41        .map(MessageComponent::from)
42        .collect::<MessageContent>()
43}
44
45pub fn format_discord(message_content: &[MessageComponent]) -> String {
46    message_content
47        .iter()
48        .map(|component| match component {
49            MessageComponent::Plain(text) => text.to_string(), // TODO: Escape
50
51            MessageComponent::Link { target, text } => {
52                let formatted_text = format_discord(text);
53
54                // TODO: Maybe tolerate a missing http(s) URL scheme?
55                if &formatted_text == target {
56                    formatted_text
57                } else {
58                    format!("{} ({})", formatted_text, target)
59                }
60            }
61
62            MessageComponent::Italic(inner) => format!("*{}*", format_discord(inner)),
63            MessageComponent::Bold(inner) => format!("**{}**", format_discord(inner)),
64            MessageComponent::Strikethrough(inner) => format!("~~{}~~", format_discord(inner)),
65            MessageComponent::Underline(inner) => format!("__{}__", format_discord(inner)),
66
67            MessageComponent::Code(code) => format!("`{}`", code), // TODO: Double-grave delimiting when code contains '`'
68            MessageComponent::CodeBlock { lang, source } => {
69                format!(
70                    "```{}\n{}\n```",
71                    lang.as_ref()
72                        .map(|s| s.to_string())
73                        .unwrap_or_else(|| "".to_string()),
74                    source.to_string()
75                )
76            }
77
78            MessageComponent::Spoiler { content, .. } => format!("||{}||", format_discord(content)), // TODO: Spoiler reason
79
80            MessageComponent::HardBreak => "\n".to_string(),
81            MessageComponent::BlockQuote(inner) => format_discord(inner)
82                .lines()
83                .map(|l| format!("> {}\n", l))
84                .collect(),
85        })
86        .collect()
87}