Merge pull request #864 from epage/color

fix(cli): Improve color formatting
This commit is contained in:
Ed Page 2023-10-27 10:05:00 -05:00 committed by GitHub
commit 6a7b7d0777
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 120 deletions

View file

@ -13,21 +13,11 @@ pub enum Format {
} }
impl Format { impl Format {
pub(crate) fn reporter( pub(crate) fn reporter(self) -> Box<dyn typos_cli::report::Report> {
self,
stdout_palette: crate::report::Palette,
stderr_palette: crate::report::Palette,
) -> Box<dyn typos_cli::report::Report> {
match self { match self {
Format::Silent => Box::new(crate::report::PrintSilent), Format::Silent => Box::new(crate::report::PrintSilent),
Format::Brief => Box::new(crate::report::PrintBrief { Format::Brief => Box::new(crate::report::PrintBrief),
stdout_palette, Format::Long => Box::new(crate::report::PrintLong),
stderr_palette,
}),
Format::Long => Box::new(crate::report::PrintLong {
stdout_palette,
stderr_palette,
}),
Format::Json => Box::new(crate::report::PrintJson), Format::Json => Box::new(crate::report::PrintJson),
} }
} }

View file

@ -255,9 +255,7 @@ fn run_checks(args: &args::Args) -> proc_exit::ExitResult {
let output_reporter = if args.diff { let output_reporter = if args.diff {
Box::new(crate::report::PrintSilent) Box::new(crate::report::PrintSilent)
} else { } else {
let stdout_palette = report::Palette::colored(); args.format.reporter()
let stderr_palette = report::Palette::colored();
args.format.reporter(stdout_palette, stderr_palette)
}; };
let status_reporter = report::MessageStatus::new(output_reporter.as_ref()); let status_reporter = report::MessageStatus::new(output_reporter.as_ref());
let reporter: &dyn typos_cli::report::Report = &status_reporter; let reporter: &dyn typos_cli::report::Report = &status_reporter;

View file

@ -8,60 +8,9 @@ use unicode_width::UnicodeWidthStr;
use typos_cli::report::{Context, Message, Report, Typo}; use typos_cli::report::{Context, Message, Report, Typo};
#[derive(Copy, Clone, Debug, Default)] const ERROR: anstyle::Style = anstyle::AnsiColor::BrightRed.on_default();
pub struct Palette { const INFO: anstyle::Style = anstyle::AnsiColor::BrightBlue.on_default();
error: anstyle::Style, const GOOD: anstyle::Style = anstyle::AnsiColor::BrightGreen.on_default();
info: anstyle::Style,
strong: anstyle::Style,
}
impl Palette {
pub fn colored() -> Self {
Self {
error: anstyle::AnsiColor::Red.on_default(),
info: anstyle::AnsiColor::Blue.on_default(),
strong: anstyle::Effects::BOLD.into(),
}
}
pub(crate) fn error<D: std::fmt::Display>(self, display: D) -> Styled<D> {
Styled::new(display, self.error)
}
pub(crate) fn info<D: std::fmt::Display>(self, display: D) -> Styled<D> {
Styled::new(display, self.info)
}
pub(crate) fn strong<D: std::fmt::Display>(self, display: D) -> Styled<D> {
Styled::new(display, self.strong)
}
}
#[derive(Debug)]
pub(crate) struct Styled<D> {
display: D,
style: anstyle::Style,
}
impl<D: std::fmt::Display> Styled<D> {
pub(crate) fn new(display: D, style: anstyle::Style) -> Self {
Self { display, style }
}
}
impl<D: std::fmt::Display> std::fmt::Display for Styled<D> {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
write!(f, "{}", self.style.render())?;
self.display.fmt(f)?;
write!(f, "{}", self.style.render_reset())?;
Ok(())
} else {
self.display.fmt(f)
}
}
}
pub struct MessageStatus<'r> { pub struct MessageStatus<'r> {
typos_found: atomic::AtomicBool, typos_found: atomic::AtomicBool,
@ -108,10 +57,7 @@ impl Report for PrintSilent {
} }
} }
pub struct PrintBrief { pub struct PrintBrief;
pub stdout_palette: Palette,
pub stderr_palette: Palette,
}
impl Report for PrintBrief { impl Report for PrintBrief {
fn report(&self, msg: Message) -> Result<(), std::io::Error> { fn report(&self, msg: Message) -> Result<(), std::io::Error> {
@ -119,11 +65,13 @@ impl Report for PrintBrief {
Message::BinaryFile(msg) => { Message::BinaryFile(msg) => {
log::info!("{}", msg); log::info!("{}", msg);
} }
Message::Typo(msg) => print_brief_correction(msg, self.stdout_palette)?, Message::Typo(msg) => print_brief_correction(msg)?,
Message::FileType(msg) => { Message::FileType(msg) => {
let info = INFO.render();
let reset = anstyle::Reset.render();
writeln!( writeln!(
stdout().lock(), stdout().lock(),
"{}:{}", "{info}{}{reset}: {}",
msg.path.display(), msg.path.display(),
msg.file_type.unwrap_or("-") msg.file_type.unwrap_or("-")
)?; )?;
@ -143,10 +91,7 @@ impl Report for PrintBrief {
} }
} }
pub struct PrintLong { pub struct PrintLong;
pub stdout_palette: Palette,
pub stderr_palette: Palette,
}
impl Report for PrintLong { impl Report for PrintLong {
fn report(&self, msg: Message) -> Result<(), std::io::Error> { fn report(&self, msg: Message) -> Result<(), std::io::Error> {
@ -154,11 +99,13 @@ impl Report for PrintLong {
Message::BinaryFile(msg) => { Message::BinaryFile(msg) => {
log::info!("{}", msg); log::info!("{}", msg);
} }
Message::Typo(msg) => print_long_correction(msg, self.stdout_palette)?, Message::Typo(msg) => print_long_correction(msg)?,
Message::FileType(msg) => { Message::FileType(msg) => {
let info = INFO.render();
let reset = anstyle::Reset.render();
writeln!( writeln!(
stdout().lock(), stdout().lock(),
"{}:{}", "{info}{}{reset}: {}",
msg.path.display(), msg.path.display(),
msg.file_type.unwrap_or("-") msg.file_type.unwrap_or("-")
)?; )?;
@ -178,7 +125,12 @@ impl Report for PrintLong {
} }
} }
fn print_brief_correction(msg: &Typo, palette: Palette) -> Result<(), std::io::Error> { fn print_brief_correction(msg: &Typo) -> Result<(), std::io::Error> {
let error = ERROR.render();
let good = GOOD.render();
let info = INFO.render();
let reset = anstyle::Reset.render();
let start = String::from_utf8_lossy(&msg.buffer[0..msg.byte_offset]); let start = String::from_utf8_lossy(&msg.buffer[0..msg.byte_offset]);
let column_number = let column_number =
unicode_segmentation::UnicodeSegmentation::graphemes(start.as_ref(), true).count() + 1; unicode_segmentation::UnicodeSegmentation::graphemes(start.as_ref(), true).count() + 1;
@ -188,26 +140,22 @@ fn print_brief_correction(msg: &Typo, palette: Palette) -> Result<(), std::io::E
let divider = ":"; let divider = ":";
writeln!( writeln!(
stdout().lock(), stdout().lock(),
"{:#}{:#}{:#}: {:#}", "{info}{}{divider}{column_number}{reset}: `{error}{}{reset}` is disallowed",
palette.info(context_display(&msg.context)), context_display(&msg.context),
palette.info(divider), msg.typo,
palette.info(column_number),
palette.strong(format_args!("`{}` is disallowed:", msg.typo)),
)?; )?;
} }
typos::Status::Corrections(corrections) => { typos::Status::Corrections(corrections) => {
let divider = ":"; let divider = ":";
writeln!( writeln!(
stdout().lock(), stdout().lock(),
"{:#}{:#}{:#}: {:#}", "{info}{}{divider}{column_number}{reset}: `{error}{}{reset}` -> {}",
palette.info(context_display(&msg.context)), context_display(&msg.context),
palette.info(divider),
palette.info(column_number),
palette.strong(format_args!(
"`{}` -> {}",
msg.typo, msg.typo,
itertools::join(corrections.iter().map(|s| format!("`{}`", s)), ", ") itertools::join(
)), corrections.iter().map(|s| format!("`{good}{}{reset}`", s)),
", "
)
)?; )?;
} }
} }
@ -215,7 +163,12 @@ fn print_brief_correction(msg: &Typo, palette: Palette) -> Result<(), std::io::E
Ok(()) Ok(())
} }
fn print_long_correction(msg: &Typo, palette: Palette) -> Result<(), std::io::Error> { fn print_long_correction(msg: &Typo) -> Result<(), std::io::Error> {
let error = ERROR.render();
let good = GOOD.render();
let info = INFO.render();
let reset = anstyle::Reset.render();
let stdout = stdout(); let stdout = stdout();
let mut handle = stdout.lock(); let mut handle = stdout.lock();
@ -229,36 +182,33 @@ fn print_long_correction(msg: &Typo, palette: Palette) -> Result<(), std::io::Er
typos::Status::Invalid => { typos::Status::Invalid => {
writeln!( writeln!(
handle, handle,
"{:#}: {:#}", "{error}error{reset}: `{error}{}{reset}` is disallowed",
palette.error("error"), msg.typo,
palette.strong(format_args!("`{}` is disallowed", msg.typo))
)?; )?;
} }
typos::Status::Corrections(corrections) => { typos::Status::Corrections(corrections) => {
writeln!( writeln!(
handle, handle,
"{:#}: {:#}", "{error}error{reset}: `{error}{}{reset}` should be {}",
palette.error("error"),
palette.strong(format_args!(
"`{}` should be {}",
msg.typo, msg.typo,
itertools::join(corrections.iter().map(|s| format!("`{}`", s)), ", ") itertools::join(
)) corrections.iter().map(|s| format!("`{good}{}{reset}`", s)),
", "
)
)?; )?;
} }
} }
let divider = ":"; let divider = ":";
writeln!( writeln!(
handle, handle,
" --> {:#}{:#}{:#}", "{info} --> {reset}{}{divider}{column_number}",
palette.info(context_display(&msg.context)), context_display(&msg.context),
palette.info(divider),
palette.info(column_number)
)?; )?;
if let Some(Context::File(context)) = &msg.context { if let Some(Context::File(context)) = &msg.context {
let line_num = context.line_num.to_string(); let line_num = context.line_num.to_string();
let line_indent: String = itertools::repeat_n(" ", line_num.len()).collect(); let line_indent: String = itertools::repeat_n(" ", line_num.len()).collect();
let line = line.trim_end();
let visible_column = calculate_visible_column_width(start.as_ref()); let visible_column = calculate_visible_column_width(start.as_ref());
let visible_len = calculate_visible_column_width(msg.typo); let visible_len = calculate_visible_column_width(msg.typo);
@ -266,16 +216,13 @@ fn print_long_correction(msg: &Typo, palette: Palette) -> Result<(), std::io::Er
let hl_indent: String = itertools::repeat_n(" ", visible_column).collect(); let hl_indent: String = itertools::repeat_n(" ", visible_column).collect();
let hl: String = itertools::repeat_n("^", visible_len).collect(); let hl: String = itertools::repeat_n("^", visible_len).collect();
writeln!(handle, "{} |", line_indent)?; writeln!(handle, "{info}{line_indent} |{reset}")?;
writeln!(handle, "{:#} | {}", palette.info(line_num), line.trim_end())?; writeln!(handle, "{info}{line_num} |{reset} {line}")?;
writeln!( writeln!(
handle, handle,
"{} | {}{:#}", "{info}{line_indent} |{reset} {hl_indent}{error}{hl}{reset}",
line_indent,
hl_indent,
palette.error(hl)
)?; )?;
writeln!(handle, "{} |", line_indent)?; writeln!(handle, "{info}{line_indent} |{reset}")?;
} }
Ok(()) Ok(())