dntk 3.0.15

Command line's multi-platform interactive calculator, GNU bc wrapper.
Documentation
use std::fmt;

use super::util;

#[derive(Debug, PartialEq)]
pub(crate) enum DntkStringType {
    Ok,
    Ng,
    Warn,
    Refresh,
}

#[derive(Debug)]
pub(crate) struct DntkString {
    data: String,
    dtype: DntkStringType,
    cur_pos_from_right: usize,
}

impl DntkString {
    pub(crate) fn new(data: String, dtype: DntkStringType, cur_pos_from_right: usize) -> Self {
        Self {
            data,
            dtype,
            cur_pos_from_right,
        }
    }

    pub(crate) fn ancize(mut self) -> Self {
        self = self.colorize();
        #[cfg(not(target_os = "windows"))]
        {
            self = self.cursorize();
        }
        self
    }

    pub(crate) fn colorize(mut self) -> Self {
        if !util::DNTK_OPT.white {
            match &self.dtype {
                DntkStringType::Ok => {
                    self.data = ansi_term::Colour::Cyan.paint(&self.data).to_string();
                }
                DntkStringType::Ng => {
                    self.data = ansi_term::Colour::Purple.paint(&self.data).to_string();
                }
                DntkStringType::Warn => {
                    self.data = ansi_term::Colour::Yellow.paint(&self.data).to_string();
                }
                DntkStringType::Refresh => {
                    self.data = ansi_term::Colour::Green.paint(&self.data).to_string();
                }
            }
        }
        self
    }

    pub(crate) fn cursorize(mut self) -> Self {
        self.data = format!(
            "{}{}{}{}",
            self.data,
            util::CURSOR_MOVE_ES_HEAD,
            self.cur_pos_from_right,
            util::CURSOR_MOVE_ES_BACK
        );
        self
    }
}

impl fmt::Display for DntkString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(&self.data)
    }
}

#[derive(Debug)]
pub(crate) struct PromptState {
    total_len: usize,
    statement_len: usize,
    result_len: usize,
}

impl Default for PromptState {
    fn default() -> Self {
        Self {
            total_len: util::DNTK_PROMPT.len(),
            statement_len: 0,
            result_len: 0,
        }
    }
}

impl PromptState {
    pub(crate) fn reset(&mut self) {
        *self = Self::default();
    }

    pub(crate) fn whitespace(&self) -> String {
        whitespace(self.total_len)
    }

    pub(crate) fn render_success(
        &mut self,
        prompt: &str,
        statement: &str,
        separator: &str,
        result: &str,
        cursor_pos: usize,
    ) -> DntkString {
        self.statement_len = statement.len();
        self.result_len = result.len();
        self.total_len = prompt.len() + self.statement_len + separator.len() + self.result_len;
        let pos_difference = self.statement_len.saturating_sub(cursor_pos);
        DntkString::new(
            format!("{prompt}{statement}{separator}{result}"),
            DntkStringType::Ok,
            separator.len() + self.result_len + pos_difference,
        )
    }

    pub(crate) fn render_error(
        &mut self,
        prompt: &str,
        statement: &str,
        separator: &str,
        cursor_pos: usize,
    ) -> DntkString {
        self.statement_len = statement.len();
        self.total_len = prompt.len() + self.statement_len + separator.len() + self.result_len;
        let pos_difference = self.statement_len.saturating_sub(cursor_pos);
        DntkString::new(
            format!("{prompt}{statement}{separator}"),
            DntkStringType::Ng,
            separator.len() + pos_difference,
        )
    }
}

pub(crate) fn whitespace(len: usize) -> String {
    format!("\r{}", " ".repeat(len))
}