1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! ANSI escape code rendering for the web
//!
//! # Yew
//!
//! ```
//! # use yew::html;
//! # use yew_ansi::AnsiStatic;
//! html! {
//!     <AnsiStatic text="Hello \u{001b}[32mWorld\u{001b}[39;1m!" />
//! }
//! # ;
//! ```
//!
//! This will generate the following output (whitespace added for clarity):
//!
//! ```html
//! <pre style="font-family: monospace">
//!     <span>Hello </span>
//!     <span style="color:#00ff00;">World</span>
//!     <span style="font-weight:bold;">!</span>
//! </pre>
//! ```
//!
//! Refer to [`AnsiRenderer`] and [`AnsiProps`] for more details.
//!
//! # Parsing
//!
//! If you want to parse text containing ANSI escape codes you can use [`get_sgr_segments`]
//! to iterate over text segments along with their [`SgrEffect`].
//!
//! If you need more control, use [`get_markers`] to iterate over the raw [`Escape`] codes in the text.

pub use cursor::CharCursor;
pub use graphic_rendition::*;
pub use sequences::*;
pub use style::*;

#[cfg(feature = "yew")]
pub use yew_component::*;

mod cursor;
mod graphic_rendition;
mod sequences;
mod style;
#[cfg(feature = "yew")]
mod yew_component;

/// Iterator over the SGR segments in a string slice.
///
/// Each item is a tuple containing the [`SgrEffect`] and the [`&str`][str] it applies to.
///
/// Returned by [`get_sgr_segments`].
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct SgrSegmentIter<'a> {
    markers: MarkerIter<'a>,
    effect: SgrEffect,
}
impl<'a> SgrSegmentIter<'a> {
    fn new(s: &'a str) -> Self {
        Self {
            markers: get_markers(s),
            effect: SgrEffect::default(),
        }
    }
}
impl<'a> Iterator for SgrSegmentIter<'a> {
    type Item = (SgrEffect, &'a str);

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match self.markers.next()? {
                Marker::Text(text) => {
                    return Some((self.effect.clone(), text));
                }
                Marker::Sequence(Escape::Csi(Csi::Sgr(sgrs))) => {
                    self.effect.apply_sgrs(sgrs);
                }
            }
        }
    }
}

/// Create an iterator which iterates over SGR segments in a string slice.
/// Each item consists of a [`SgrEffect`] and the corresponding text slice it applies to.
///
/// ```
/// # use yew_ansi::*;
/// let mut segments = yew_ansi::get_sgr_segments("Hello \u{001b}[32mWorld\u{001b}[39;1m!");
/// assert_eq!(segments.next(), Some((SgrEffect::default(), "Hello ")));
/// assert_eq!(
///     segments.next(),
///     Some((
///         SgrEffect {
///             fg: ColorEffect::Name(ColorName::Green),
///             ..Default::default()
///         },
///         "World"
///     ))
/// );
/// assert_eq!(
///     segments.next(),
///     Some((
///         SgrEffect {
///             bold: true,
///             ..Default::default()
///         },
///         "!"
///     ))
/// );
/// ```
pub fn get_sgr_segments(s: &str) -> SgrSegmentIter {
    SgrSegmentIter::new(s)
}