iced_selection/lib.rs
1//! A text selection API built around [`iced`]'s [`Paragraph`].
2//!
3//! [`iced`]: https://iced.rs
4//! [`Paragraph`]: https://docs.iced.rs/iced_graphics/text/paragraph/struct.Paragraph.html
5
6mod click;
7#[cfg(feature = "markdown")]
8pub mod markdown;
9pub mod selection;
10pub mod text;
11
12use iced_widget::core;
13use iced_widget::graphics::text::Paragraph;
14#[cfg(feature = "markdown")]
15pub use markdown::view as markdown;
16#[doc(no_inline)]
17pub use text::Text;
18
19/// Creates a new [`Text`] widget with the provided content.
20///
21/// [`Text`]: core::widget::Text
22///
23/// This macro uses the same syntax as [`format!`], but creates a new [`Text`] widget instead.
24///
25/// See [the formatting documentation in `std::fmt`](std::fmt)
26/// for details of the macro argument syntax.
27///
28/// # Examples
29///
30/// ```no_run,ignore
31/// use iced_selection::text;
32///
33/// enum Message {
34/// // ...
35/// }
36///
37/// fn view(_state: &State) -> Element<Message> {
38/// let simple = text!("Hello, world!");
39///
40/// let keyword = text!("Hello, {}", "world!");
41///
42/// let planet = "Earth";
43/// let local_variable = text!("Hello, {planet}!");
44/// // ...
45/// }
46/// ```
47#[macro_export]
48macro_rules! text {
49 ($($arg:tt)*) => {
50 $crate::Text::new(format!($($arg)*))
51 };
52}
53
54/// Creates some [`Rich`] text with the given spans.
55///
56/// # Example
57/// ```no_run,ignore
58/// use iced::font;
59/// use iced_selection::{rich_text, span};
60/// use iced::{color, never, Font};
61///
62/// #[derive(Debug, Clone)]
63/// enum Message {
64/// // ...
65/// }
66///
67/// fn view(state: &State) -> Element<'_, Message> {
68/// rich_text![
69/// span("I am red!").color(color!(0xff0000)),
70/// span(" "),
71/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
72/// ]
73/// .on_link_click(never)
74/// .size(20)
75/// .into()
76/// }
77/// ```
78///
79/// [`Rich`]: crate::text::Rich
80#[macro_export]
81macro_rules! rich_text {
82 () => (
83 $crate::text::Rich::new()
84 );
85 ($($x:expr),+ $(,)?) => (
86 $crate::text::Rich::from_iter([$($crate::text::Span::from($x)),+])
87 );
88}
89
90/// Creates a new [`Span`] of text with the provided content.
91///
92/// A [`Span`] is a fragment of some [`Rich`] text.
93///
94/// This macro uses the same syntax as [`format!`], but creates a new [`Span`] widget instead.
95///
96/// See [the formatting documentation in `std::fmt`](std::fmt)
97/// for details of the macro argument syntax.
98///
99/// # Example
100/// ```no_run,ignore
101/// use iced::font;
102/// use iced_selection::{rich_text, span};
103/// use iced::{color, never, Font};
104///
105/// #[derive(Debug, Clone)]
106/// enum Message {
107/// // ...
108/// }
109///
110/// fn view(state: &State) -> Element<'_, Message> {
111/// rich_text![
112/// span!("I am {}!", red).color(color!(0xff0000)),
113/// " ",
114/// span!("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
115/// ]
116/// .on_link_click(never)
117/// .size(20)
118/// .into()
119/// }
120/// ```
121///
122/// [`Rich`]: crate::text::Rich
123/// [`Span`]: crate::text::Span
124#[macro_export]
125macro_rules! span {
126 ($($arg:tt)*) => {
127 $crate::text::Span::new(format!($($arg)*))
128 };
129}
130
131/// Creates a new [`Text`] widget with the provided content.
132///
133/// # Example
134/// ```no_run,ignore
135/// use iced_selection::text;
136///
137/// enum Message {
138/// // ...
139/// }
140///
141/// fn view(state: &State) -> Element<'_, Message> {
142/// text("Hello, this is iced!")
143/// .size(20)
144/// .into()
145/// }
146/// ```
147pub fn text<'a, Theme, Renderer>(
148 text: impl text::IntoFragment<'a>,
149) -> Text<'a, Theme, Renderer>
150where
151 Theme: text::Catalog + 'a,
152 Renderer: core::text::Renderer,
153{
154 Text::new(text)
155}
156
157/// Creates some [`Rich`] text with the given spans.
158///
159/// [`Rich`]: crate::text::Rich
160///
161/// # Example
162/// ```no_run,ignore
163/// use iced::font;
164/// use iced_selection::{rich_text, span};
165/// use iced::{color, never, Font};
166///
167/// #[derive(Debug, Clone)]
168/// enum Message {
169/// LinkClicked(&'static str),
170/// // ...
171/// }
172///
173/// fn view(state: &State) -> Element<'_, Message> {
174/// rich_text([
175/// span("I am red!").color(color!(0xff0000)),
176/// span(" "),
177/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
178/// ])
179/// .on_link_click(never)
180/// .size(20)
181/// .into()
182/// }
183/// ```
184pub fn rich_text<'a, Link, Message, Theme, Renderer>(
185 spans: impl AsRef<[text::Span<'a, Link, core::Font>]> + 'a,
186) -> text::Rich<'a, Link, Message, Theme, Renderer>
187where
188 Link: Clone + 'static,
189 Theme: text::Catalog + 'a,
190 Renderer: core::text::Renderer<Paragraph = Paragraph, Font = core::Font>,
191{
192 text::Rich::with_spans(spans)
193}
194
195/// Creates a new [`Span`] of text with the provided content.
196///
197/// A [`Span`] is a fragment of some [`Rich`] text.
198///
199/// [`Rich`]: crate::text::Rich
200/// [`Span`]: crate::text::Span
201///
202/// # Example
203/// ```no_run,ignore
204/// use iced::font;
205/// use iced_selection::{rich_text, span};
206/// use iced::{color, never, Font};
207///
208/// #[derive(Debug, Clone)]
209/// enum Message {
210/// // ...
211/// }
212///
213/// fn view(state: &State) -> Element<'_, Message> {
214/// rich_text![
215/// span("I am red!").color(color!(0xff0000)),
216/// " ",
217/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
218/// ]
219/// .on_link_click(never)
220/// .size(20)
221/// .into()
222/// }
223/// ```
224pub fn span<'a, Link>(
225 text: impl text::IntoFragment<'a>,
226) -> text::Span<'a, Link, core::Font> {
227 text::Span::new(text)
228}