terminator 0.3.2

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

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 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}", self.config.theme.hidden.style(buffer.as_str()))
    }
}

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 backtrace: Backtrace = BacktraceParser::new(&backtrace).collect::<Vec<_>>().into();
        Display::fmt(&self.config.bundle(&backtrace), f)
    }
}

impl Display for Bundle<'_, Option<&std::backtrace::Backtrace>> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let backtrace = self.data.as_ref().map(ToString::to_string);
        let backtrace: Backtrace = if let Some(ref backtrace) = backtrace {
            BacktraceParser::new(backtrace).collect::<Vec<_>>().into()
        } else {
            Backtrace::default()
        };
        Display::fmt(&self.config.bundle(&backtrace), f)
    }
}