ansiconst 0.2.1

Library for declaring nestable ANSI styles in const context
Documentation
use crate::{Ansi, Styled};
use super::{AnsiNode, StyledString};
use std::{cell::Cell, fmt};

pub(super) struct StyledStringBuildPosition {
    ansi_node_index: usize,
    parent_number_of_inner_ansis: u8,
}

pub(super) struct StyledStringBuild {
    ansi_nodes: Vec<AnsiNode>,
    number_of_inner_ansis: u8,
    max_depth: u8,
    depth: u8,
}

impl StyledStringBuild {
    thread_local! {
        static BUILD: Cell<Option<StyledStringBuild>> = Cell::new(None)
    }

    #[inline]
    fn new() -> Self {
        Self {
            ansi_nodes: Vec::new(),
            number_of_inner_ansis: 0,
            max_depth: 0,
            depth: 0,
        }
    }

    pub(super) fn from_styled<T: fmt::Display>(styled: &Styled<T>) -> StyledString {
        Self::BUILD.set(Some(Self::new()));
        let template = format!("{}", styled);
        let build = Self::BUILD.take().unwrap();

        StyledString {
            template,
            ansi_nodes: build.ansi_nodes,
            max_depth: build.max_depth,
        }
    }

    pub(super) fn fmt_styled_string(
        f: &mut fmt::Formatter<'_>,
        styled_string: &StyledString,
    ) -> Result<bool, fmt::Error> {
        Self::BUILD.with(|opt| {
            match opt.take() {
                None => Ok(false),
                Some(mut build) => {

                    if build.depth > 0 { f.write_str(AnsiNode::PLACEHOLDER)?; }
                    f.write_str(&styled_string.template)?;
                    if build.depth > 0 { f.write_str(AnsiNode::PLACEHOLDER)?; }

                    build.add_styled_string(styled_string);

                    opt.set(Some(build));
                    Ok(true)
                },
            }
        })
    }

    pub(super) fn fmt_styled_begin(
        f: &mut fmt::Formatter<'_>,
        ansi: Ansi,
    ) -> Result<Option<StyledStringBuildPosition>, fmt::Error> {
        Self::BUILD.with(|opt| {
            match opt.take() {
                None => Ok(None),
                Some(mut build) => {
                    if build.depth > 0 { f.write_str(AnsiNode::PLACEHOLDER)?; }

                    let position = build.styled_begin(ansi);

                    opt.set(Some(build));
                    Ok(Some(position))
                },
            }
        })
    }

    pub(super) fn fmt_styled_end(f: &mut fmt::Formatter<'_>, position: StyledStringBuildPosition) -> fmt::Result {
        Self::BUILD.with(|opt| {
            let mut build = opt.take().unwrap();

            build.styled_end(position);

            if build.depth > 0 { f.write_str(AnsiNode::PLACEHOLDER)?; }

            opt.set(Some(build));
            Ok(())
        })
    }

    #[inline]
    fn add_styled_string(&mut self, styled_string: &StyledString) {
        self.number_of_inner_ansis += 1;
        let max_depth = self.depth + styled_string.max_depth;
        if max_depth > self.max_depth { self.max_depth = max_depth; }
        self.ansi_nodes.extend_from_slice(&styled_string.ansi_nodes);
    }

    #[inline]
    fn styled_begin(&mut self, ansi: Ansi) -> StyledStringBuildPosition {
        let position = StyledStringBuildPosition {
            ansi_node_index:              self.ansi_nodes.len(),
            parent_number_of_inner_ansis: self.number_of_inner_ansis,
        };

        self.number_of_inner_ansis = 0;
        self.depth += 1;
        if self.depth > self.max_depth { self.max_depth += 1; }
        self.ansi_nodes.push(AnsiNode::new(ansi));

        position
    }

    #[inline]
    fn styled_end(&mut self, position: StyledStringBuildPosition) {
        let ansi_node = self.ansi_nodes.get_mut(position.ansi_node_index).unwrap();
        ansi_node.number_of_inner_ansis = self.number_of_inner_ansis;
        self.number_of_inner_ansis = position.parent_number_of_inner_ansis + 1;
        self.depth -= 1;
    }
}