use crate::{Line, Render, Span, Style, Text, TextError};
use unicode_width::UnicodeWidthChar;
const DEFAULT_CHARACTER: char = '─';
pub fn hr() -> Hr {
Hr::new()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Hr {
character: char,
character_width: usize,
style: Style,
}
impl Hr {
pub fn new() -> Self {
Self {
character: DEFAULT_CHARACTER,
character_width: 1,
style: Style::new(),
}
}
pub fn with_character(character: char) -> Result<Self, TextError> {
Self::new().character(character)
}
pub fn character(mut self, character: char) -> Result<Self, TextError> {
self.character_width = validate_character(character)?;
self.character = character;
Ok(self)
}
pub fn style(mut self, style: Style) -> Self {
self.style = style;
self
}
pub fn fill_character(&self) -> char {
self.character
}
pub fn character_width(&self) -> usize {
self.character_width
}
pub fn rule_style(&self) -> Style {
self.style
}
}
impl Default for Hr {
fn default() -> Self {
Self::new()
}
}
impl Render for Hr {
fn render(&self, width: u16) -> Text {
let width = usize::from(width);
if width == 0 {
return Text::empty();
}
let count = width / self.character_width;
if count == 0 {
return Text::from_lines(vec![Line::from_spans(Vec::new())]);
}
let content: String = std::iter::repeat_n(self.character, count).collect();
let span = Span::from_trusted_content(content, self.style);
Text::from_lines(vec![Line::from_spans(vec![span])])
}
}
fn validate_character(character: char) -> Result<usize, TextError> {
let mut buffer = [0; 4];
Span::validate_content(character.encode_utf8(&mut buffer))?;
let width = UnicodeWidthChar::width(character).unwrap_or(0);
if width == 0 {
return Err(TextError::StructuralContent);
}
Ok(width)
}