use super::{line::Line, word::Word};
use super::{segment_words, MetaTag};
use ratatui::style::{Color, Modifier, Style};
use std::fmt;
use term_rustdoc::util::XString;
#[derive(Default, Debug)]
pub struct Block {
lines: Vec<Line>,
links: Vec<usize>,
footnotes: Vec<XString>,
}
impl FromIterator<Line> for Block {
fn from_iter<T: IntoIterator<Item = Line>>(iter: T) -> Self {
Block {
lines: Vec::from_iter(iter),
links: Vec::new(),
footnotes: Vec::new(),
}
}
}
impl FromIterator<Word> for Block {
fn from_iter<T: IntoIterator<Item = Word>>(iter: T) -> Self {
let mut lines = Vec::with_capacity(8);
lines.push(Line::from_iter(iter));
Block {
lines,
links: Vec::new(),
footnotes: Vec::new(),
}
}
}
impl Extend<Line> for Block {
fn extend<T: IntoIterator<Item = Line>>(&mut self, iter: T) {
self.lines.extend(iter);
}
}
impl Extend<Word> for Block {
fn extend<T: IntoIterator<Item = Word>>(&mut self, iter: T) {
self.last_line().extend(iter);
}
}
impl fmt::Display for Block {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for line in &self.lines {
writeln!(f, "{line}")?;
}
Ok(())
}
}
impl Block {
fn last_line(&mut self) -> &mut Line {
if self.lines.is_empty() {
self.lines.push(Line {
words: Vec::with_capacity(16),
});
}
self.lines.last_mut().unwrap()
}
pub fn push_normal_words(&mut self, words: &str) {
let last_line = self.last_line();
segment_words(words, |word, trailling_whitespace| {
last_line.words.push(Word {
word: word.into(),
trailling_whitespace,
..Default::default()
})
});
}
pub fn push_words(&mut self, words: &str, style: Style, tag: MetaTag) {
let last_line = self.last_line();
segment_words(words, |word, trailling_whitespace| {
last_line.words.push(Word {
word: word.into(),
style,
tag: tag.clone(),
trailling_whitespace,
})
});
}
pub fn push_a_word(&mut self, word: Word) {
self.last_line().words.push(word);
}
pub fn shrink_to_fit(&mut self) {
if let Some(true) = self.lines.last().map(|line| line.words.is_empty()) {
self.lines.pop();
}
self.lines.shrink_to_fit();
for line in &mut self.lines {
line.words.shrink_to_fit();
}
self.links.shrink_to_fit();
}
pub fn set_heading(&mut self, id: usize) {
for line in &mut self.lines {
for word in &mut line.words {
word.tag = MetaTag::Heading(id);
word.style.fg = Some(Color::LightCyan);
word.style.add_modifier = Modifier::BOLD;
}
}
}
pub fn set_quote_block(&mut self) {
for line in &mut self.lines {
for word in &mut line.words {
word.tag = MetaTag::QuoteBlock;
word.style.fg = Some(Color::Rgb(186, 85, 211)); }
}
}
pub fn set_foot_note(&mut self) {
for line in &mut self.lines {
for word in &mut line.words {
word.tag = MetaTag::FootnoteSource;
word.style.fg = Some(Color::LightMagenta);
}
}
}
pub fn push_code_block(&mut self, code: Block) {
self.lines.extend(code.lines);
}
}
impl Block {
pub fn lines(&self) -> &[Line] {
&self.lines
}
pub fn links(&self) -> &[usize] {
&self.links
}
pub fn footnotes(&self) -> &[XString] {
&self.footnotes
}
pub fn push_link(&mut self, idx: usize) {
if !self.links.iter().any(|l| *l == idx) {
self.links.push(idx);
}
}
pub fn push_footnote(&mut self, key: XString) {
if !self.footnotes.iter().any(|f| *f == key) {
self.footnotes.push(key);
}
}
}