use anstyle::{AnsiColor, Color, Style};
use color_print::cstr;
pub const ADDITION: Style = Style::new().fg_color(Some(Color::Ansi(AnsiColor::Green)));
pub const DELETION: Style = Style::new().fg_color(Some(Color::Ansi(AnsiColor::Red)));
pub const GUTTER: Style = Style::new().bg_color(Some(Color::Ansi(AnsiColor::BrightWhite)));
pub const DEFAULT_HELP_WIDTH: usize = 98;
pub const PROGRESS_SYMBOL: &str = cstr!("<cyan>◎</>");
pub const SUCCESS_SYMBOL: &str = cstr!("<green>✓</>");
pub const ERROR_SYMBOL: &str = cstr!("<red>✗</>");
pub const WARNING_SYMBOL: &str = cstr!("<yellow>▲</>");
pub const HINT_SYMBOL: &str = cstr!("<dim>↳</>");
pub const INFO_SYMBOL: &str = cstr!("<dim>○</>");
pub const PROMPT_SYMBOL: &str = cstr!("<cyan>❯</>");
use std::fmt;
#[derive(Debug, Clone)]
pub struct FormattedMessage(String);
impl FormattedMessage {
pub fn new(content: String) -> Self {
Self(content)
}
pub fn into_inner(self) -> String {
self.0
}
pub fn append(mut self, suffix: &str) -> Self {
self.0.push_str(suffix);
self
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for FormattedMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<FormattedMessage> for String {
fn from(msg: FormattedMessage) -> String {
msg.0
}
}
use color_print::cformat;
pub fn error_message(content: impl AsRef<str>) -> FormattedMessage {
FormattedMessage(cformat!("{ERROR_SYMBOL} <red>{}</>", content.as_ref()))
}
pub fn hint_message(content: impl AsRef<str>) -> FormattedMessage {
FormattedMessage(cformat!("{HINT_SYMBOL} <dim>{}</>", content.as_ref()))
}
pub fn warning_message(content: impl AsRef<str>) -> FormattedMessage {
FormattedMessage(cformat!("{WARNING_SYMBOL} <yellow>{}</>", content.as_ref()))
}
pub fn success_message(content: impl AsRef<str>) -> FormattedMessage {
FormattedMessage(cformat!("{SUCCESS_SYMBOL} <green>{}</>", content.as_ref()))
}
pub fn progress_message(content: impl AsRef<str>) -> FormattedMessage {
FormattedMessage(cformat!("{PROGRESS_SYMBOL} <cyan>{}</>", content.as_ref()))
}
pub fn info_message(content: impl AsRef<str>) -> FormattedMessage {
FormattedMessage(format!("{INFO_SYMBOL} {}", content.as_ref()))
}
pub fn prompt_message(content: impl AsRef<str>) -> FormattedMessage {
FormattedMessage(cformat!("{PROMPT_SYMBOL} <cyan>{}</>", content.as_ref()))
}
pub fn format_heading(title: &str, suffix: Option<&str>) -> String {
match suffix {
Some(s) => cformat!("<cyan>{}</> {}", title, s),
None => cformat!("<cyan>{}</>", title),
}
}
#[cfg(test)]
mod tests {
use insta::assert_snapshot;
use super::*;
#[test]
fn test_symbol_constants() {
assert_snapshot!(PROGRESS_SYMBOL, @"[36m◎[39m");
assert_snapshot!(SUCCESS_SYMBOL, @"[32m✓[39m");
assert_snapshot!(ERROR_SYMBOL, @"[31m✗[39m");
assert_snapshot!(WARNING_SYMBOL, @"[33m▲[39m");
assert_snapshot!(HINT_SYMBOL, @"[2m↳[22m");
assert_snapshot!(INFO_SYMBOL, @"[2m○[22m");
assert_snapshot!(PROMPT_SYMBOL, @"[36m❯[39m");
}
#[test]
fn test_message_formatting() {
assert_snapshot!(error_message("Something went wrong").as_str(), @"[31m✗[39m [31mSomething went wrong[39m");
assert_snapshot!(hint_message("Try running --help").as_str(), @"[2m↳[22m [2mTry running --help[22m");
assert_snapshot!(warning_message("Deprecated option").as_str(), @"[33m▲[39m [33mDeprecated option[39m");
assert_snapshot!(success_message("Operation completed").as_str(), @"[32m✓[39m [32mOperation completed[39m");
assert_snapshot!(progress_message("Loading data...").as_str(), @"[36m◎[39m [36mLoading data...[39m");
assert_snapshot!(info_message("5 items found").as_str(), @"[2m○[22m 5 items found");
assert_snapshot!(prompt_message("Continue?").as_str(), @"[36m❯[39m [36mContinue?[39m");
}
#[test]
fn test_error_message_with_inner_styling() {
let name = "feature";
let msg = error_message(cformat!("Branch <bold>{name}</> not found"));
assert_snapshot!(msg.as_str(), @"[31m✗[39m [31mBranch [1mfeature[22m not found[39m");
}
#[test]
fn test_format_heading() {
assert_snapshot!(format_heading("BINARIES", None), @"[36mBINARIES[39m");
assert_snapshot!(format_heading("USER CONFIG", Some("~/.config/wt.toml")), @"[36mUSER CONFIG[39m ~/.config/wt.toml");
assert_snapshot!(format_heading("", None), @"[36m[39m");
}
#[test]
fn test_formatted_message_into_inner() {
let msg = success_message("Done");
assert_snapshot!(msg.into_inner(), @"[32m✓[39m [32mDone[39m");
}
}