use crate::constants::HORIZONTAL_BAR;
use crate::printer::{Printable, Printer, PrinterFormat};
use crate::LogLevel;
use const_format::{concatcp, formatcp};
use std::borrow::Cow;
use std::fmt::Display;
use yansi::Style;
const N_HORIZONTAL_BARS: usize = 100;
const HORIZONTAL_BARS: &str = formatcp!("{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}", HORIZONTAL_BAR);
const _: () = {
assert!(HORIZONTAL_BARS.len() == HORIZONTAL_BAR.len_utf8() * N_HORIZONTAL_BARS);
};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SeparatorBlock {
pub width: usize,
character: char,
}
impl SeparatorBlock {
#[inline(always)]
pub fn new(width: usize, character: char) -> Self {
assert_ne!(
character, '\n',
"The character cannot be a newline character."
);
Self { width, character }
}
#[inline(always)]
pub fn with_width(width: usize) -> Self {
Self {
width,
character: HORIZONTAL_BAR,
}
}
#[inline(always)]
pub fn with_white() -> Self {
Self {
width: 0,
character: ' ',
}
}
#[inline(always)]
pub fn get_character(&self) -> char {
self.character
}
#[inline(always)]
pub fn set_character(&mut self, character: char) {
assert_ne!(
character, '\n',
"The character cannot be a newline character."
);
self.character = character;
}
#[inline(always)]
pub fn width(mut self, width: usize) -> Self {
self.width = width;
self
}
#[inline(always)]
pub fn character(mut self, character: char) -> Self {
assert_ne!(
character, '\n',
"The character cannot be a newline character."
);
self.character = character;
self
}
}
impl<'a> Printable<'a> for SeparatorBlock {
fn print<'s>(&'s self, printer: &mut Printer<'a>)
where
'a: 's,
{
if self.width == 0 {
return;
}
let separator = match self.character {
c if c.is_whitespace() => Cow::Borrowed(""),
HORIZONTAL_BAR => {
if self.width < N_HORIZONTAL_BARS {
Cow::Borrowed(&HORIZONTAL_BARS[0..(self.width * HORIZONTAL_BAR.len_utf8())])
} else {
Cow::Owned(concatcp!(HORIZONTAL_BAR).repeat(self.width))
}
}
_ => Cow::Owned(format!("{}", self.character).repeat(self.width)),
};
printer.push_styled_text(separator, Style::new().bold().fg(printer.level.color()));
}
}
impl Display for SeparatorBlock {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut printer = Printer::new(LogLevel::trace(), PrinterFormat::Plain);
self.print(&mut printer);
printer.fmt(f, PrinterFormat::Plain)
}
}
#[cfg(test)]
mod tests {
use crate::blocks::SeparatorBlock;
use crate::printer::{Printable, PrinterFormat};
use crate::LogLevel;
#[test]
fn test_plain() {
let log = SeparatorBlock::new(0, '/');
let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
assert_eq!(text, "");
let log = SeparatorBlock::new(10, '/');
let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
assert_eq!(text, "//////////");
let log = SeparatorBlock::with_width(10);
let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
assert_eq!(text, "──────────");
}
#[test]
fn test_styled() {
let log = SeparatorBlock::new(0, '/');
let text = log
.print_to_string(LogLevel::info(), PrinterFormat::Styled)
.to_string();
println!("{}", text);
assert_eq!(text, "");
let log = SeparatorBlock::new(10, '/');
let text = log
.print_to_string(LogLevel::info(), PrinterFormat::Styled)
.to_string();
println!("{}", text);
assert_eq!(text, "\u{1b}[1;34m//////////\u{1b}[0m");
let log = SeparatorBlock::with_width(10);
let text = log
.print_to_string(LogLevel::info(), PrinterFormat::Styled)
.to_string();
println!("{}", text);
assert_eq!(text, "\u{1b}[1;34m──────────\u{1b}[0m");
}
}