use std::{fmt, path::Path};
pub use ansi_term::Color;
use anyhow::Error;
use crate::context::{Context, EditContext, LockContext, SettingsExt};
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub enum Verbosity {
Quiet,
Normal,
Verbose,
}
#[derive(Clone, Copy, Debug)]
pub struct Output {
pub verbosity: Verbosity,
pub no_color: bool,
}
pub trait OutputExt {
fn output(&self) -> &Output;
#[inline]
fn verbosity(&self) -> Verbosity {
self.output().verbosity
}
#[inline]
fn no_color(&self) -> bool {
self.output().no_color
}
}
pub enum Message<'a> {
Borrowed(&'a dyn fmt::Display),
Owned(String),
}
pub trait IntoMessage {
fn into_message<C>(&self, ctx: &C) -> Message
where
C: SettingsExt;
}
impl OutputExt for Output {
#[inline]
fn output(&self) -> &Output {
self
}
}
impl OutputExt for Context<'_> {
#[inline]
fn output(&self) -> &Output {
self.output
}
}
impl OutputExt for EditContext {
#[inline]
fn output(&self) -> &Output {
&self.output
}
}
impl OutputExt for LockContext {
#[inline]
fn output(&self) -> &Output {
&self.output
}
}
impl<'a> fmt::Display for Message<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &*self {
Message::Borrowed(b) => fmt::Display::fmt(b, f),
Message::Owned(o) => fmt::Display::fmt(o, f),
}
}
}
impl<T> IntoMessage for &T
where
T: fmt::Display,
{
fn into_message<C>(&self, _: &C) -> Message
where
C: SettingsExt,
{
Message::Borrowed(self)
}
}
impl IntoMessage for &Path {
fn into_message<C>(&self, ctx: &C) -> Message
where
C: SettingsExt,
{
Message::Owned(ctx.replace_home(self).display().to_string())
}
}
pub fn header<C, M>(ctx: &C, status: &str, message: M)
where
C: SettingsExt + OutputExt,
M: IntoMessage,
{
let message = message.into_message(ctx);
if ctx.no_color() {
eprintln!("[{}] {}", status.to_uppercase(), message);
} else {
eprintln!("{} {}", Color::Purple.bold().paint(status), message);
}
}
pub fn status<C, M>(ctx: &C, color: Color, status: &str, message: M)
where
C: SettingsExt + OutputExt,
M: IntoMessage,
{
let message = message.into_message(ctx);
if ctx.no_color() {
eprintln!(
"{: >12} {}",
format!("[{}]", status.to_uppercase()),
message
)
} else {
eprintln!(
"{} {}",
color.bold().paint(format!("{: >10}", status)),
message
);
}
}
pub fn error<C>(ctx: &C, color: Color, status: &str, error: &Error)
where
C: OutputExt,
{
let pretty = error
.chain()
.map(|c| c.to_string().replace("Template error: ", ""))
.collect::<Vec<_>>()
.join("\n due to: ");
if ctx.no_color() {
eprintln!("\n[{}] {}", status.to_uppercase(), pretty);
} else {
eprintln!(
"\n{} {}",
color.bold().paint(format!("{}:", status)),
pretty
);
}
}