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}