chunkedge_text/
into_text.rs

1//! Provides the [`IntoText`] trait and implementations.
2
3use std::borrow::Cow;
4
5use super::{ClickEvent, Color, Font, HoverEvent, Text};
6
7/// Trait for any data that can be converted to a [`Text`] object.
8///
9/// Also conveniently provides many useful methods for modifying a [`Text`]
10/// object.
11///
12/// # Usage
13///
14/// ```
15/// # use chunkedge_text::{IntoText, color::NamedColor};
16/// let mut my_text = "".into_text();
17/// my_text = my_text.color(NamedColor::Red).bold();
18/// my_text = my_text.add_child("CRABBBBB".obfuscated());
19pub trait IntoText<'a>: Sized {
20    /// Converts to a [`Text`] object, either owned or borrowed.
21    fn into_cow_text(self) -> Cow<'a, Text>;
22
23    /// Converts to an owned [`Text`] object.
24    fn into_text(self) -> Text {
25        self.into_cow_text().into_owned()
26    }
27
28    /// Sets the color of the text.
29    fn color(self, color: impl Into<Color>) -> Text {
30        let mut value = self.into_text();
31        value.color = Some(color.into());
32        value
33    }
34    /// Clears the color of the text. Color of parent [`Text`] object will be
35    /// used.
36    fn clear_color(self) -> Text {
37        let mut value = self.into_text();
38        value.color = None;
39        value
40    }
41
42    /// Sets the font of the text.
43    fn font(self, font: Font) -> Text {
44        let mut value = self.into_text();
45        value.font = Some(font);
46        value
47    }
48    /// Clears the font of the text. Font of parent [`Text`] object will be
49    /// used.
50    fn clear_font(self) -> Text {
51        let mut value = self.into_text();
52        value.font = None;
53        value
54    }
55
56    /// Makes the text bold.
57    fn bold(self) -> Text {
58        let mut value = self.into_text();
59        value.bold = Some(true);
60        value
61    }
62    /// Makes the text not bold.
63    fn not_bold(self) -> Text {
64        let mut value = self.into_text();
65        value.bold = Some(false);
66        value
67    }
68    /// Clears the `bold` property of the text. Property of the parent [`Text`]
69    /// object will be used.
70    fn clear_bold(self) -> Text {
71        let mut value = self.into_text();
72        value.bold = None;
73        value
74    }
75
76    /// Makes the text italic.
77    fn italic(self) -> Text {
78        let mut value = self.into_text();
79        value.italic = Some(true);
80        value
81    }
82    /// Makes the text not italic.
83    fn not_italic(self) -> Text {
84        let mut value = self.into_text();
85        value.italic = Some(false);
86        value
87    }
88    /// Clears the `italic` property of the text. Property of the parent
89    /// [`Text`] object will be used.
90    fn clear_italic(self) -> Text {
91        let mut value = self.into_text();
92        value.italic = None;
93        value
94    }
95
96    /// Makes the text underlined.
97    fn underlined(self) -> Text {
98        let mut value = self.into_text();
99        value.underlined = Some(true);
100        value
101    }
102    /// Makes the text not underlined.
103    fn not_underlined(self) -> Text {
104        let mut value = self.into_text();
105        value.underlined = Some(false);
106        value
107    }
108    /// Clears the `underlined` property of the text. Property of the parent
109    /// [`Text`] object will be used.
110    fn clear_underlined(self) -> Text {
111        let mut value = self.into_text();
112        value.underlined = None;
113        value
114    }
115
116    /// Adds a strikethrough effect to the text.
117    fn strikethrough(self) -> Text {
118        let mut value = self.into_text();
119        value.strikethrough = Some(true);
120        value
121    }
122    /// Removes the strikethrough effect from the text.
123    fn not_strikethrough(self) -> Text {
124        let mut value = self.into_text();
125        value.strikethrough = Some(false);
126        value
127    }
128    /// Clears the `strikethrough` property of the text. Property of the parent
129    /// [`Text`] object will be used.
130    fn clear_strikethrough(self) -> Text {
131        let mut value = self.into_text();
132        value.strikethrough = None;
133        value
134    }
135
136    /// Makes the text obfuscated.
137    fn obfuscated(self) -> Text {
138        let mut value = self.into_text();
139        value.obfuscated = Some(true);
140        value
141    }
142    /// Makes the text not obfuscated.
143    fn not_obfuscated(self) -> Text {
144        let mut value = self.into_text();
145        value.obfuscated = Some(false);
146        value
147    }
148    /// Clears the `obfuscated` property of the text. Property of the parent
149    /// [`Text`] object will be used.
150    fn clear_obfuscated(self) -> Text {
151        let mut value = self.into_text();
152        value.obfuscated = None;
153        value
154    }
155
156    /// Adds an `insertion` property to the text. When shift-clicked, the given
157    /// text will be inserted into chat box for the client.
158    fn insertion(self, insertion: impl Into<Cow<'static, str>>) -> Text {
159        let mut value = self.into_text();
160        value.insertion = Some(insertion.into());
161        value
162    }
163    /// Clears the `insertion` property of the text. Property of the parent
164    /// [`Text`] object will be used.
165    fn clear_insertion(self) -> Text {
166        let mut value = self.into_text();
167        value.insertion = None;
168        value
169    }
170
171    /// On click, opens the given URL. Has to be `http` or `https` protocol.
172    fn on_click_open_url(self, url: impl Into<Cow<'static, str>>) -> Text {
173        let mut value = self.into_text();
174        value.click_event = Some(ClickEvent::OpenUrl { url: url.into() });
175        value
176    }
177    /// On click, sends a command. Doesn't actually have to be a command, can be
178    /// a simple chat message.
179    fn on_click_run_command(self, command: impl Into<Cow<'static, str>>) -> Text {
180        let mut value = self.into_text();
181        value.click_event = Some(ClickEvent::RunCommand {
182            command: command.into(),
183        });
184        value
185    }
186    /// On click, copies the given text to the chat box.
187    fn on_click_suggest_command(self, command: impl Into<Cow<'static, str>>) -> Text {
188        let mut value = self.into_text();
189        value.click_event = Some(ClickEvent::SuggestCommand {
190            command: command.into(),
191        });
192        value
193    }
194    /// On click, turns the page of the opened book to the given number.
195    /// Indexing starts at `1`.
196    fn on_click_change_page(self, page: impl Into<i32>) -> Text {
197        let mut value = self.into_text();
198        value.click_event = Some(ClickEvent::ChangePage { page: page.into() });
199        value
200    }
201    /// On click, copies the given text to clipboard.
202    fn on_click_copy_to_clipboard(self, text: impl Into<Cow<'static, str>>) -> Text {
203        let mut value = self.into_text();
204        value.click_event = Some(ClickEvent::CopyToClipboard { value: text.into() });
205        value
206    }
207    /// Clears the `click_event` property of the text. Property of the parent
208    /// [`Text`] object will be used.
209    fn clear_click_event(self) -> Text {
210        let mut value = self.into_text();
211        value.click_event = None;
212        value
213    }
214
215    /// On mouse hover, shows the given text in a tooltip.
216    fn on_hover_show_text(self, text: impl IntoText<'static>) -> Text {
217        let mut value = self.into_text();
218        value.hover_event = Some(HoverEvent::ShowText {
219            value: text.into_text(),
220        });
221        value
222    }
223    /// Clears the `hover_event` property of the text. Property of the parent
224    /// [`Text`] object will be used.
225    fn clear_hover_event(self) -> Text {
226        let mut value = self.into_text();
227        value.hover_event = None;
228        value
229    }
230
231    /// Adds a child [`Text`] object.
232    fn add_child(self, text: impl IntoText<'static>) -> Text {
233        let mut value = self.into_text();
234        value.extra.push(text.into_text());
235        value
236    }
237}
238
239impl<'a> IntoText<'a> for Text {
240    fn into_cow_text(self) -> Cow<'a, Text> {
241        Cow::Owned(self)
242    }
243}
244impl<'a> IntoText<'a> for &'a Text {
245    fn into_cow_text(self) -> Cow<'a, Text> {
246        Cow::Borrowed(self)
247    }
248}
249impl<'a> From<&'a Text> for Text {
250    fn from(value: &'a Text) -> Self {
251        value.clone()
252    }
253}
254
255impl<'a> IntoText<'a> for Cow<'a, Text> {
256    fn into_cow_text(self) -> Cow<'a, Text> {
257        self
258    }
259}
260impl<'a> From<Cow<'a, Text>> for Text {
261    fn from(value: Cow<'a, Text>) -> Self {
262        value.into_owned()
263    }
264}
265impl<'a> IntoText<'a> for &'a Cow<'_, Text> {
266    fn into_cow_text(self) -> Cow<'a, Text> {
267        self.clone()
268    }
269}
270impl<'a, 'b> From<&'a Cow<'b, Text>> for Text {
271    fn from(value: &'a Cow<'b, Text>) -> Self {
272        value.clone().into_owned()
273    }
274}
275
276impl<'a> IntoText<'a> for String {
277    fn into_cow_text(self) -> Cow<'a, Text> {
278        Cow::Owned(Text::text(self))
279    }
280}
281impl From<String> for Text {
282    fn from(value: String) -> Self {
283        value.into_text()
284    }
285}
286impl<'b> IntoText<'b> for &String {
287    fn into_cow_text(self) -> Cow<'b, Text> {
288        Cow::Owned(Text::text(self.clone()))
289    }
290}
291impl<'a> From<&'a String> for Text {
292    fn from(value: &'a String) -> Self {
293        value.into_text()
294    }
295}
296
297impl<'a> IntoText<'a> for Cow<'static, str> {
298    fn into_cow_text(self) -> Cow<'a, Text> {
299        Cow::Owned(Text::text(self))
300    }
301}
302impl From<Cow<'static, str>> for Text {
303    fn from(value: Cow<'static, str>) -> Self {
304        value.into_text()
305    }
306}
307impl IntoText<'static> for &Cow<'static, str> {
308    fn into_cow_text(self) -> Cow<'static, Text> {
309        Cow::Owned(Text::text(self.clone()))
310    }
311}
312impl<'a> From<&'a Cow<'static, str>> for Text {
313    fn from(value: &'a Cow<'static, str>) -> Self {
314        value.into_text()
315    }
316}
317
318impl<'a> IntoText<'a> for &'static str {
319    fn into_cow_text(self) -> Cow<'a, Text> {
320        Cow::Owned(Text::text(self))
321    }
322}
323impl From<&'static str> for Text {
324    fn from(value: &'static str) -> Self {
325        value.into_text()
326    }
327}
328
329impl<'a, 'b, T: IntoText<'a>, const N: usize> IntoText<'b> for [T; N] {
330    fn into_cow_text(self) -> Cow<'b, Text> {
331        let mut txt = Text::text("");
332
333        for child in self {
334            txt = txt.add_child(child.into_cow_text().into_owned());
335        }
336
337        Cow::Owned(txt)
338    }
339}
340
341impl<'a, 'c, T: IntoText<'a> + Clone, const N: usize> IntoText<'c> for &[T; N] {
342    fn into_cow_text(self) -> Cow<'c, Text> {
343        let mut txt = Text::text("");
344
345        for child in self {
346            txt = txt.add_child(child.clone().into_cow_text().into_owned());
347        }
348
349        Cow::Owned(txt)
350    }
351}
352
353macro_rules! impl_primitives {
354    ($($primitive:ty),+) => {
355        $(
356            impl<'a> IntoText<'a> for $primitive {
357                fn into_cow_text(self) -> Cow<'a, Text> {
358                    Cow::Owned(Text::text(self.to_string()))
359                }
360            }
361        )+
362    };
363}
364impl_primitives! {char, bool, f32, f64, isize, usize, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128}
365
366#[cfg(test)]
367mod tests {
368    use super::*;
369
370    #[test]
371    #[allow(clippy::needless_borrows_for_generic_args)]
372    fn intotext_trait() {
373        fn is_borrowed<'a>(value: impl IntoText<'a>) -> bool {
374            matches!(value.into_cow_text(), Cow::Borrowed(..))
375        }
376
377        assert!(is_borrowed(&"this should be borrowed".into_text()));
378        assert!(is_borrowed(&"this should be borrowed too".bold()));
379        assert!(!is_borrowed("this should be owned?".bold()));
380        assert!(!is_borrowed("this should be owned"));
381        assert!(!is_borrowed(465));
382        assert!(!is_borrowed(false));
383    }
384}