use super::*;
use unicode_width::UnicodeWidthStr;
pub struct LLLineDisplay<'a> {
ll_line: &'a LLLine,
include_attrs: Vec<(LRange, String)>,
}
impl<'a> std::fmt::Display for LLLineDisplay<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
const SPACE_PADDING: usize = 2;
let mut token_idx_to_start_display_char_idx = Vec::new();
let mut token_idx_to_end_display_char_idx = Vec::new();
let mut opening_line = String::new();
{
let mut is_first = true;
for ll_token in self.ll_line.ll_tokens.iter() {
if is_first {
is_first = false;
} else {
opening_line.extend(std::iter::repeat(' ').take(SPACE_PADDING));
}
token_idx_to_start_display_char_idx.push(UnicodeWidthStr::width(&*opening_line));
match &ll_token.token {
LToken::Text(text, _) => {
opening_line.push_str(&text);
}
LToken::Value { .. } => {
write!(&mut opening_line, "<>")?;
}
}
token_idx_to_end_display_char_idx.push(UnicodeWidthStr::width(&*opening_line));
}
}
f.write_str(&opening_line)?;
for ((starts_at_token_idx, ends_at_token_idx), debug_value) in self.include_attrs.iter() {
f.write_char('\n')?;
let start_char_idx = token_idx_to_start_display_char_idx[*starts_at_token_idx];
for _ in 0..start_char_idx {
f.write_char(' ')?;
}
f.write_char('╰')?;
let end_char_idx = token_idx_to_end_display_char_idx[*ends_at_token_idx];
let char_len = end_char_idx - start_char_idx;
for _ in (start_char_idx + 1)..end_char_idx.saturating_sub(1) {
f.write_char('─')?;
}
if char_len > 1 {
f.write_char('╯')?;
}
f.write_str(&debug_value)?;
}
Ok(())
}
}
impl<'a> LLLineDisplay<'a> {
pub fn new(ll_line: &'a LLLine) -> Self {
LLLineDisplay {
ll_line,
include_attrs: Vec::new(),
}
}
pub fn include<T: 'static + std::fmt::Debug>(&mut self) {
for ll_range in self.ll_line.attrs.ranges.get::<T>() {
for debug_value in self
.ll_line
.attrs
.values
.get(ll_range)
.into_iter()
.flat_map(|type_bucket| type_bucket.get_debug::<T>())
.rev()
{
self.include_attrs.push((*ll_range, debug_value));
}
}
}
pub fn with<T: 'static + std::fmt::Debug>(mut self) -> Self {
self.include::<T>();
self
}
}