terminator 0.2.0-alpha

Formatter for pretty panics and errors
Documentation
use std::cell::Cell;
use std::cell::RefCell;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;
use std::fmt::Write;

use owo_colors::OwoColorize;

use crate::config::Bundle;
use crate::verbosity::Verbosity;

use super::convert::BacktraceParser;
use super::Backtrace;
use super::Frame;

struct Hidden<'a> {
    buffer: &'a RefCell<String>,
    count: usize,
}

impl Display for Bundle<'_, Hidden<'_>> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let config = self.config();
        let Hidden { buffer, count } = *self.data();
        let mut buffer = buffer.borrow_mut();
        buffer.clear();
        write!(
            buffer,
            "{decorator} {count} frame{plural} hidden {decorator}",
            plural = if count == 1 { "" } else { "s" },
            decorator = "",
        )?;
        write!(f, "{:^80}", buffer.style(config.theme.hidden))
    }
}

impl Display for Bundle<'_, &Backtrace<'_>> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let config = self.config();
        let mut frames: Vec<_> = self.data().frames.replace(Vec::new());

        write!(f, "{:━^80}", " BACKTRACE ")?;
        if frames.is_empty() {
            return write!(f, "{:^80}", "<empty backtrace>");
        }

        let last = frames.last().map_or(0, Frame::index);

        if config.selected_verbosity() != Verbosity::Full {
            for filter in &config.filters {
                filter(&mut frames);
                frames.sort_unstable_by_key(Frame::index);
            }
        }

        let buffer = RefCell::new(String::with_capacity(128));
        let mut next = 0;
        for frame in frames {
            let delta = frame.index - next;
            if delta != 0 {
                write!(
                    f,
                    "\n{}",
                    config.bundle(Hidden {
                        buffer: &buffer,
                        count: delta
                    })
                )?;
            }
            write!(f, "\n{}", config.bundle(&frame))?;
            next = frame.index + 1;
        }

        if (last + 1) != next {
            write!(
                f,
                "\n{}",
                config.bundle(Hidden {
                    buffer: &buffer,
                    count: last - next
                })
            )?;
        }

        Ok(())
    }
}

#[cfg(feature = "backtrace")]
impl Display for Bundle<'_, &'_ backtrace::Backtrace> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let backtrace = Backtrace::from(*self.data());
        Display::fmt(&self.config().bundle(&backtrace), f)
    }
}

impl Display for Bundle<'_, &'_ std::backtrace::Backtrace> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let backtrace = self.data().to_string();
        let frames = BacktraceParser::new(&backtrace).collect();
        let cell = Cell::new(frames);
        let backtrace = Backtrace::from(cell);
        Display::fmt(&self.config().bundle(&backtrace), f)
    }
}