pub use crossterm::style::Color;
use crossterm::style::{Attribute, Attributes, ContentStyle, Stylize};
use unicode_width::UnicodeWidthChar;
#[derive(Debug)]
pub struct Styled {
content: String,
fg: Option<Color>,
bg: Option<Color>,
attr: Option<Attributes>,
}
impl Styled {
pub fn new(content: impl std::fmt::Display) -> Self {
Self {
content: content.to_string(),
fg: None,
bg: None,
attr: None,
}
}
pub fn fg(&mut self, color: Color) -> &mut Self {
self.fg = Some(color);
self
}
pub fn bg(&mut self, color: Color) -> &mut Self {
self.bg = Some(color);
self
}
pub fn bold(&mut self) -> &mut Self {
self.attr(Attribute::Bold)
}
pub fn italic(&mut self) -> &mut Self {
self.attr(Attribute::Italic)
}
pub fn underline(&mut self) -> &mut Self {
self.attr(Attribute::Underlined)
}
pub fn dim(&mut self) -> &mut Self {
self.attr(Attribute::Dim)
}
pub fn rev(&mut self) -> &mut Self {
self.attr(Attribute::Reverse)
}
pub fn blink(&mut self) -> &mut Self {
self.attr(Attribute::SlowBlink)
}
fn attr(&mut self, attr: Attribute) -> &mut Self {
match self.attr {
Some(ref mut attrs) => attrs.set(attr),
None => self.attr = Some(Attributes::from(attr)),
}
self
}
}
impl std::fmt::Display for Styled {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut style = ContentStyle::new();
if let Some(fg) = self.fg {
style = style.with(fg);
}
if let Some(bg) = self.bg {
style = style.on(bg);
}
if let Some(attr) = &self.attr {
style.attributes = *attr;
}
write!(f, "{}", style.apply(self.content.as_str()))
}
}
#[cfg(windows)]
fn is_unicode_supported() -> bool {
use std::env;
if env::var("WT_SESSION").is_ok() {
return true;
}
if let Ok(program) = env::var("TERM_PROGRAM") {
match program.as_str() {
"vscode" => return true,
_ => {}
}
}
if let Ok(term) = env::var("TERM") {
match term.as_str() {
"xterm-256color" | "alacritty" => return true,
_ => {}
}
}
false
}
#[cfg(unix)]
fn is_unicode_supported() -> bool {
true
}
#[derive(Debug, Copy, Clone)]
pub struct Symbol<'a, 'b>(
pub &'a str,
pub &'b str,
);
impl<'a, 'b> Symbol<'a, 'b> {
pub fn new(main: &'a str, fallback: &'b str) -> Self {
Self(main, fallback)
}
}
impl<'a, 'b> std::fmt::Display for Symbol<'a, 'b> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if is_unicode_supported() {
write!(f, "{}", self.0)
} else {
write!(f, "{}", self.1)
}
}
}
pub fn wrap_text(input: &str, col: u16) -> String {
let mut output = String::new();
let mut cw = 0;
for (_, c) in input.char_indices() {
let w = c.width().unwrap_or(0);
if c == '\n' {
cw = 0;
output.push(c);
continue;
}
if cw + w > col as usize {
output.push('\n');
cw = 0;
}
output.push(c);
cw += w;
}
output
}