use crate::formatter::{
ErrorKind, FormatError, Render,
condition::{Condition, ConditionalToken},
format_args::FormatArg,
};
#[derive(Debug, Clone)]
pub(crate) struct Block<'a> {
content: Vec<FormatArg<'a>>,
prefix: Vec<FormatArg<'a>>,
postfix: Vec<FormatArg<'a>>,
fallback: Vec<FormatArg<'a>>,
condition: Option<Condition<'a>>,
}
impl<'a> Render for Block<'a> {
fn render(&self, format_table: &super::FormatTable) -> String {
if let Some(condition) = &self.condition
&& !condition.solve(format_table)
{
return String::new();
}
let mut content = self.content.render(format_table);
if content.is_empty() {
let fallback = self.fallback.render(format_table);
if fallback.is_empty() {
return String::new();
}
content = fallback
}
let mut prefix = self.prefix.render(format_table);
prefix.push_str(&content);
prefix.push_str(&self.postfix.render(format_table));
prefix
}
}
#[derive(Debug, PartialEq, Eq)]
pub(super) enum BlockMode {
Content,
Prefix,
Suffix,
Fallback,
Condition,
}
impl std::fmt::Display for BlockMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BlockMode::Content => f.write_str("Content"),
BlockMode::Prefix => f.write_str("Prefix"),
BlockMode::Suffix => f.write_str("Suffix"),
BlockMode::Fallback => f.write_str("Fallback"),
BlockMode::Condition => f.write_str("Condition"),
}
}
}
impl BlockMode {
pub fn to_str(&self) -> &'static str {
match self {
BlockMode::Content => panic!(
"Attempted to turn BlockMode::Content into a &str. This mode should never be set, only defaulted to"
),
BlockMode::Prefix => "<",
BlockMode::Suffix => ">",
BlockMode::Fallback => "?",
BlockMode::Condition => "@",
}
}
}
pub(super) struct BlockBuilder<'a> {
content: Vec<FormatArg<'a>>,
prefix: Vec<FormatArg<'a>>,
postfix: Vec<FormatArg<'a>>,
fallback: Vec<FormatArg<'a>>,
condition: Option<Condition<'a>>,
mode: Vec<BlockMode>,
}
impl<'a> Default for BlockBuilder<'a> {
fn default() -> Self {
Self {
content: Default::default(),
prefix: Default::default(),
postfix: Default::default(),
fallback: Default::default(),
condition: Default::default(),
mode: vec![BlockMode::Content],
}
}
}
impl<'a> BlockBuilder<'a> {
pub(super) fn build(self) -> Block<'a> {
Block {
content: self.content,
prefix: self.prefix,
postfix: self.postfix,
fallback: self.fallback,
condition: self.condition,
}
}
pub(super) fn set_mode(&mut self, mode: BlockMode) -> Result<(), FormatError> {
if self.mode.contains(&mode) {
Err(FormatError::new(ErrorKind::DoubleDefinition(mode.to_str())))
} else {
self.mode.push(mode);
Ok(())
}
}
pub(super) fn push_arg(&mut self, arg: FormatArg<'a>) {
let arg_list = match self.mode.last().unwrap() {
BlockMode::Content => &mut self.content,
BlockMode::Prefix => &mut self.prefix,
BlockMode::Suffix => &mut self.postfix,
BlockMode::Fallback => &mut self.fallback,
BlockMode::Condition => {
let condition = self.condition.get_or_insert(Condition::default());
condition.tokens.push(ConditionalToken::Arg(arg));
return;
}
};
arg_list.push(arg);
}
pub(super) fn push_conditional_token(&mut self, token: ConditionalToken<'a>) {
match self.mode.last().unwrap() {
BlockMode::Condition => {
let condition = self.condition.get_or_insert(Condition::default());
condition.tokens.push(token);
}
_ => self.push_arg(FormatArg::Text(token.to_str())),
}
}
}