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)
}