valence_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 valence_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.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(command.into()));
182        value
183    }
184    /// On click, copies the given text to the chat box.
185    fn on_click_suggest_command(self, command: impl Into<Cow<'static, str>>) -> Text {
186        let mut value = self.into_text();
187        value.click_event = Some(ClickEvent::SuggestCommand(command.into()));
188        value
189    }
190    /// On click, turns the page of the opened book to the given number.
191    /// Indexing starts at `1`.
192    fn on_click_change_page(self, page: impl Into<i32>) -> Text {
193        let mut value = self.into_text();
194        value.click_event = Some(ClickEvent::ChangePage(page.into()));
195        value
196    }
197    /// On click, copies the given text to clipboard.
198    fn on_click_copy_to_clipboard(self, text: impl Into<Cow<'static, str>>) -> Text {
199        let mut value = self.into_text();
200        value.click_event = Some(ClickEvent::CopyToClipboard(text.into()));
201        value
202    }
203    /// Clears the `click_event` property of the text. Property of the parent
204    /// [`Text`] object will be used.
205    fn clear_click_event(self) -> Text {
206        let mut value = self.into_text();
207        value.click_event = None;
208        value
209    }
210
211    /// On mouse hover, shows the given text in a tooltip.
212    fn on_hover_show_text(self, text: impl IntoText<'static>) -> Text {
213        let mut value = self.into_text();
214        value.hover_event = Some(HoverEvent::ShowText(text.into_text()));
215        value
216    }
217    /// Clears the `hover_event` property of the text. Property of the parent
218    /// [`Text`] object will be used.
219    fn clear_hover_event(self) -> Text {
220        let mut value = self.into_text();
221        value.hover_event = None;
222        value
223    }
224
225    /// Adds a child [`Text`] object.
226    fn add_child(self, text: impl IntoText<'static>) -> Text {
227        let mut value = self.into_text();
228        value.extra.push(text.into_text());
229        value
230    }
231}
232
233impl<'a> IntoText<'a> for Text {
234    fn into_cow_text(self) -> Cow<'a, Text> {
235        Cow::Owned(self)
236    }
237}
238impl<'a> IntoText<'a> for &'a Text {
239    fn into_cow_text(self) -> Cow<'a, Text> {
240        Cow::Borrowed(self)
241    }
242}
243impl<'a> From<&'a Text> for Text {
244    fn from(value: &'a Text) -> Self {
245        value.clone()
246    }
247}
248
249impl<'a> IntoText<'a> for Cow<'a, Text> {
250    fn into_cow_text(self) -> Cow<'a, Text> {
251        self
252    }
253}
254impl<'a> From<Cow<'a, Text>> for Text {
255    fn from(value: Cow<'a, Text>) -> Self {
256        value.into_owned()
257    }
258}
259impl<'a> IntoText<'a> for &'a Cow<'_, Text> {
260    fn into_cow_text(self) -> Cow<'a, Text> {
261        self.clone()
262    }
263}
264impl<'a, 'b> From<&'a Cow<'b, Text>> for Text {
265    fn from(value: &'a Cow<'b, Text>) -> Self {
266        value.clone().into_owned()
267    }
268}
269
270impl<'a> IntoText<'a> for String {
271    fn into_cow_text(self) -> Cow<'a, Text> {
272        Cow::Owned(Text::text(self))
273    }
274}
275impl From<String> for Text {
276    fn from(value: String) -> Self {
277        value.into_text()
278    }
279}
280impl<'b> IntoText<'b> for &String {
281    fn into_cow_text(self) -> Cow<'b, Text> {
282        Cow::Owned(Text::text(self.clone()))
283    }
284}
285impl<'a> From<&'a String> for Text {
286    fn from(value: &'a String) -> Self {
287        value.into_text()
288    }
289}
290
291impl<'a> IntoText<'a> for Cow<'static, str> {
292    fn into_cow_text(self) -> Cow<'a, Text> {
293        Cow::Owned(Text::text(self))
294    }
295}
296impl From<Cow<'static, str>> for Text {
297    fn from(value: Cow<'static, str>) -> Self {
298        value.into_text()
299    }
300}
301impl IntoText<'static> for &Cow<'static, str> {
302    fn into_cow_text(self) -> Cow<'static, Text> {
303        Cow::Owned(Text::text(self.clone()))
304    }
305}
306impl<'a> From<&'a Cow<'static, str>> for Text {
307    fn from(value: &'a Cow<'static, str>) -> Self {
308        value.into_text()
309    }
310}
311
312impl<'a> IntoText<'a> for &'static str {
313    fn into_cow_text(self) -> Cow<'a, Text> {
314        Cow::Owned(Text::text(self))
315    }
316}
317impl From<&'static str> for Text {
318    fn from(value: &'static str) -> Self {
319        value.into_text()
320    }
321}
322
323impl<'a, 'b, T: IntoText<'a>, const N: usize> IntoText<'b> for [T; N] {
324    fn into_cow_text(self) -> Cow<'b, Text> {
325        let mut txt = Text::text("");
326
327        for child in self {
328            txt = txt.add_child(child.into_cow_text().into_owned());
329        }
330
331        Cow::Owned(txt)
332    }
333}
334
335impl<'a, 'c, T: IntoText<'a> + Clone, const N: usize> IntoText<'c> for &[T; N] {
336    fn into_cow_text(self) -> Cow<'c, Text> {
337        let mut txt = Text::text("");
338
339        for child in self {
340            txt = txt.add_child(child.clone().into_cow_text().into_owned());
341        }
342
343        Cow::Owned(txt)
344    }
345}
346
347macro_rules! impl_primitives {
348    ($($primitive:ty),+) => {
349        $(
350            impl<'a> IntoText<'a> for $primitive {
351                fn into_cow_text(self) -> Cow<'a, Text> {
352                    Cow::Owned(Text::text(self.to_string()))
353                }
354            }
355        )+
356    };
357}
358impl_primitives! {char, bool, f32, f64, isize, usize, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128}
359
360#[cfg(test)]
361mod tests {
362    use super::*;
363
364    #[test]
365    #[allow(clippy::needless_borrows_for_generic_args)]
366    fn intotext_trait() {
367        fn is_borrowed<'a>(value: impl IntoText<'a>) -> bool {
368            matches!(value.into_cow_text(), Cow::Borrowed(..))
369        }
370
371        assert!(is_borrowed(&"this should be borrowed".into_text()));
372        assert!(is_borrowed(&"this should be borrowed too".bold()));
373        assert!(!is_borrowed("this should be owned?".bold()));
374        assert!(!is_borrowed("this should be owned"));
375        assert!(!is_borrowed(465));
376        assert!(!is_borrowed(false));
377    }
378}