i_slint_core/
styled_text.rs1#[repr(transparent)]
6#[derive(Debug, PartialEq, Clone, Default)]
7pub struct StyledText {
8 pub(crate) paragraphs: crate::SharedVector<i_slint_common::styled_text::StyledTextParagraph>,
10}
11
12#[cfg(feature = "std")]
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct StyledTextFromMarkdownError {
16 message: alloc::string::String,
17}
18
19#[cfg(feature = "std")]
20impl StyledTextFromMarkdownError {
21 fn new(errors: alloc::vec::Vec<i_slint_common::styled_text::StyledTextParseError>) -> Self {
22 Self {
23 message: errors
24 .iter()
25 .map(alloc::string::ToString::to_string)
26 .collect::<alloc::vec::Vec<_>>()
27 .join("\n"),
28 }
29 }
30}
31
32#[cfg(feature = "std")]
33impl core::fmt::Display for StyledTextFromMarkdownError {
34 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
35 f.write_str(&self.message)
36 }
37}
38
39#[cfg(feature = "std")]
40impl std::error::Error for StyledTextFromMarkdownError {}
41
42#[cfg(feature = "std")]
43impl StyledText {
44 pub fn from_plain_text(text: &str) -> Self {
46 Self {
47 paragraphs: [i_slint_common::styled_text::paragraph_from_plain_text(text.into())]
48 .into(),
49 }
50 }
51
52 pub fn from_markdown(markdown: &str) -> Result<Self, StyledTextFromMarkdownError> {
54 let (paragraphs, errors) = i_slint_common::styled_text::parse_interpolated::<
55 &[i_slint_common::styled_text::StyledTextParagraph],
56 >(markdown, &[]);
57
58 if errors.is_empty() {
59 Ok(Self { paragraphs: paragraphs.as_slice().into() })
60 } else {
61 Err(StyledTextFromMarkdownError::new(errors))
62 }
63 }
64}
65
66pub fn get_raw_text(styled_text: &StyledText) -> alloc::borrow::Cow<'_, str> {
67 match styled_text.paragraphs.as_slice() {
68 [] => "".into(),
69 [paragraph] => paragraph.text.as_str().into(),
70 _ => {
71 let mut result = alloc::string::String::new();
72 for paragraph in styled_text.paragraphs.iter() {
73 if !result.is_empty() {
74 result.push('\n');
75 }
76 result.push_str(paragraph.text.as_str());
77 }
78 result.into()
79 }
80 }
81}
82
83#[cfg(feature = "ffi")]
85pub mod ffi {
86 #![allow(unsafe_code)]
87
88 use super::*;
89
90 #[unsafe(no_mangle)]
91 pub unsafe extern "C" fn slint_styled_text_new(out: *mut StyledText) {
93 unsafe {
94 core::ptr::write(out, Default::default());
95 }
96 }
97
98 #[unsafe(no_mangle)]
99 pub unsafe extern "C" fn slint_styled_text_drop(text: *const StyledText) {
101 unsafe {
102 core::ptr::read(text);
103 }
104 }
105
106 #[unsafe(no_mangle)]
107 pub extern "C" fn slint_styled_text_eq(a: &StyledText, b: &StyledText) -> bool {
109 a == b
110 }
111
112 #[unsafe(no_mangle)]
113 pub unsafe extern "C" fn slint_styled_text_clone(out: *mut StyledText, ss: &StyledText) {
115 unsafe { core::ptr::write(out, ss.clone()) }
116 }
117
118 #[cfg(feature = "std")]
119 #[unsafe(no_mangle)]
120 pub extern "C" fn slint_styled_text_from_plain_text(
122 text: crate::slice::Slice<u8>,
123 out: &mut StyledText,
124 ) {
125 let text = unsafe { core::str::from_utf8_unchecked(text.as_slice()) };
126 *out = StyledText::from_plain_text(text);
127 }
128
129 #[cfg(feature = "std")]
130 #[unsafe(no_mangle)]
131 pub extern "C" fn slint_styled_text_from_markdown(
134 markdown: crate::slice::Slice<u8>,
135 out: &mut StyledText,
136 ) -> bool {
137 let markdown = unsafe { core::str::from_utf8_unchecked(markdown.as_slice()) };
138 match StyledText::from_markdown(markdown) {
139 Ok(styled) => {
140 *out = styled;
141 true
142 }
143 Err(_) => false,
144 }
145 }
146}
147
148pub fn parse_markdown(_format_string: &str, _args: &[StyledText]) -> StyledText {
149 #[cfg(feature = "std")]
150 {
151 let paragraph_slices = _args
152 .iter()
153 .map(|styled_text| styled_text.paragraphs.as_slice())
154 .collect::<alloc::vec::Vec<_>>();
155
156 let (paragraphs, errors) =
157 i_slint_common::styled_text::parse_interpolated(_format_string, ¶graph_slices);
158
159 for e in &errors {
160 crate::debug_log!("@markdown: {e}");
161 }
162
163 StyledText { paragraphs: paragraphs.as_slice().into() }
164 }
165 #[cfg(not(feature = "std"))]
166 Default::default()
167}
168
169pub fn color_to_styled_text(_color: crate::Color) -> StyledText {
170 #[cfg(feature = "std")]
171 {
172 let hex = alloc::format!(
173 "#{:02x}{:02x}{:02x}{:02x}",
174 _color.red(),
175 _color.green(),
176 _color.blue(),
177 _color.alpha()
178 );
179 StyledText::from_plain_text(&hex)
180 }
181 #[cfg(not(feature = "std"))]
182 Default::default()
183}
184
185pub fn string_to_styled_text(_string: alloc::string::String) -> StyledText {
186 #[cfg(feature = "std")]
187 {
188 if _string.is_empty() {
189 return Default::default();
190 }
191 StyledText::from_plain_text(&_string)
192 }
193 #[cfg(not(feature = "std"))]
194 Default::default()
195}
196
197#[cfg(all(test, feature = "std"))]
198mod tests {
199 use super::*;
200
201 #[test]
202 fn string_to_styled_text_returns_default_for_empty_string() {
203 assert_eq!(super::string_to_styled_text(Default::default()), StyledText::default());
204 }
205}