use crate::error::Result;
use crate::module_trait::ModuleContext;
use crate::parser::{Token, parse};
use crate::registry::ModuleRegistry;
use crate::style::{AnsiStyle, ModuleStyle, global_no_color};
use is_terminal::IsTerminal;
pub struct Template<'a> {
tokens: Vec<Token<'a>>,
estimated_size: usize,
}
impl<'a> Template<'a> {
#[inline]
pub fn new(template: &'a str) -> Self {
let tokens = parse(template);
let estimated_size = template.len() + (template.len() / 2) + 128;
Self {
tokens,
estimated_size,
}
}
pub fn render(&self, registry: &ModuleRegistry, context: &ModuleContext) -> Result<String> {
let mut output = String::with_capacity(self.estimated_size);
let no_color = global_no_color() || !IsTerminal::is_terminal(&std::io::stdout());
for token in &self.tokens {
match token {
Token::Text(text) => {
output.push_str(text);
}
Token::Placeholder(params) => {
let module = registry.get(¶ms.module).ok_or_else(|| {
crate::error::PromptError::UnknownModule(params.module.to_string())
})?;
if let Some(text) = module.render(¶ms.format, context)?
&& !text.is_empty()
{
let has_prefix = !params.prefix.is_empty();
let has_suffix = !params.suffix.is_empty();
let styled = !params.style.is_empty() && !no_color;
if styled {
let style = AnsiStyle::parse(¶ms.style).map_err(|error| {
crate::error::PromptError::StyleError {
module: params.module.to_string(),
error,
}
})?;
style.write_start_codes(&mut output, context.shell);
if has_prefix {
output.push_str(¶ms.prefix);
}
output.push_str(&text);
if has_suffix {
output.push_str(¶ms.suffix);
}
style.write_reset(&mut output, context.shell);
} else {
if has_prefix {
output.push_str(¶ms.prefix);
}
output.push_str(&text);
if has_suffix {
output.push_str(¶ms.suffix);
}
}
}
}
}
}
Ok(output)
}
pub fn tokens(&self) -> impl Iterator<Item = &Token<'a>> {
self.tokens.iter()
}
pub fn token_count(&self) -> usize {
self.tokens.len()
}
}