wowlab_common/markdown/
inline.rs1use std::fmt::Display;
2
3const SHORT_SHA_LEN: usize = 7;
4
5fn wrap(text: impl Display, prefix: &str, suffix: &str) -> String {
6 format!("{prefix}{text}{suffix}")
7}
8
9pub fn bold(text: impl Display) -> String {
11 wrap(text, "**", "**")
12}
13
14pub fn italic(text: impl Display) -> String {
16 wrap(text, "*", "*")
17}
18
19pub fn bold_italic(text: impl Display) -> String {
21 wrap(text, "***", "***")
22}
23
24pub fn underline(text: impl Display) -> String {
26 wrap(text, "__", "__")
27}
28
29pub fn strike(text: impl Display) -> String {
31 wrap(text, "~~", "~~")
32}
33
34pub fn underline_italic(text: impl Display) -> String {
36 wrap(text, "__*", "*__")
37}
38
39pub fn underline_bold(text: impl Display) -> String {
41 wrap(text, "__**", "**__")
42}
43
44pub fn underline_bold_italic(text: impl Display) -> String {
46 wrap(text, "__***", "***__")
47}
48
49pub fn code(text: impl Display) -> String {
51 wrap(text, "`", "`")
52}
53
54pub fn quote_block(text: impl Display) -> String {
56 wrap(text, ">>> ", "")
57}
58
59pub fn h1(text: impl Display) -> String {
61 wrap(text, "# ", "")
62}
63
64pub fn h2(text: impl Display) -> String {
66 wrap(text, "## ", "")
67}
68
69pub fn h3(text: impl Display) -> String {
71 wrap(text, "### ", "")
72}
73
74pub fn subtext(text: impl Display) -> String {
76 wrap(text, "-# ", "")
77}
78
79pub fn spoiler(text: impl Display) -> String {
81 wrap(text, "||", "||")
82}
83
84pub fn channel(text: impl Display) -> String {
86 wrap(text, "<#", ">")
87}
88
89pub fn user(text: impl Display) -> String {
91 wrap(text, "<@", ">")
92}
93
94pub fn role(text: impl Display) -> String {
96 wrap(text, "<@&", ">")
97}
98
99pub fn code_block(language: &str, content: impl Display) -> String {
101 if language.is_empty() {
102 format!("```\n{content}\n```")
103 } else {
104 format!("```{language}\n{content}\n```")
105 }
106}
107
108pub fn quote(text: impl Display) -> String {
110 let text = text.to_string();
111
112 text.lines()
113 .map(|line| format!("> {line}"))
114 .collect::<Vec<_>>()
115 .join("\n")
116}
117
118#[inline]
120pub fn link(text: impl Display, url: impl Display) -> String {
121 format!("[{text}]({url})")
122}
123
124#[inline]
126pub fn link_titled(text: impl Display, url: impl Display, title: impl Display) -> String {
127 format!("[{text}]({url} \"{title}\")")
128}
129
130#[inline]
132pub fn anchor_link(text: impl Display, anchor: impl Display) -> String {
133 format!("[{text}](#{anchor})")
134}
135
136#[inline]
138pub fn slash_command(name: &str, id: impl Display) -> String {
139 format!("</{name}:{id}>")
140}
141
142#[inline]
144#[must_use]
145pub fn timestamp(unix: i64) -> String {
146 format!("<t:{unix}>")
147}
148
149#[inline]
151#[must_use]
152pub fn timestamp_styled(unix: i64, style: char) -> String {
153 format!("<t:{unix}:{style}>")
154}
155
156#[inline]
158#[must_use]
159pub fn relative_time(unix: i64) -> String {
160 timestamp_styled(unix, 'R')
161}
162
163#[inline]
165pub fn kv(key: impl Display, value: impl Display) -> String {
166 format!("**{key}:** {value}")
167}
168
169#[inline]
171pub fn kv_code(key: impl Display, value: impl Display) -> String {
172 format!("**{key}:** `{value}`")
173}
174
175#[inline]
177pub fn diff_stats(additions: impl Display, deletions: impl Display) -> String {
178 format!("`+{additions}` `-{deletions}`")
179}
180
181#[must_use]
183pub fn commit(sha: &str, message: &str) -> String {
184 let short_sha = &sha[..SHORT_SHA_LEN.min(sha.len())];
186 let first_line = message.lines().next().unwrap_or("");
187
188 format!("`{short_sha}` {first_line}")
189}
190
191#[inline]
193pub fn arrow(from: impl Display, to: impl Display) -> String {
194 format!("{from} → {to}")
195}
196
197#[inline]
199pub fn arrow_code(from: impl Display, to: impl Display) -> String {
200 format!("`{from}` → `{to}`")
201}