use crate::input::events::AppEvent;
use crate::input::events::Event;
use crate::output::ansi::AnsiConfig;
use crate::output::ansi::AnsiPrintConfigured;
use crate::output::style::Pretty;
use crate::output::style::Stylist;
use crate::prelude::Window;
use crate::widget::Widget;
use crate::Painter;
use crate::Screen;
use crossterm::style::Attribute;
use crossterm::style::Stylize;
use crossterm::Command;
use std::borrow::Cow;
use std::fmt::Display;
impl<T> Command for crate::output::ansi::AnsiPrint<T>
where
T: AsRef<str>,
{
fn write_ansi(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
let ansi = AnsiPrintConfigured(&self.0, AnsiConfig::default());
write!(f, "{ansi}")
}
#[cfg(windows)]
fn execute_winapi(&self) -> crossterm::Result<()> {
todo!()
}
}
impl<T> Command for crate::output::ansi::AnsiPrintConfigured<T>
where
crate::output::ansi::AnsiPrintConfigured<T>: Display,
{
fn write_ansi(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
write!(f, "{self}")
}
#[cfg(windows)]
fn execute_winapi(&self) -> crossterm::Result<()> {
todo!()
}
}
impl From<crate::output::color::Color> for crossterm::style::Color {
fn from(val: crate::output::color::Color) -> Self {
let (r, g, b) = val.to_24b();
crossterm::style::Color::Rgb { r, g, b }
}
}
impl From<crossterm::style::Color> for crate::output::color::Color {
fn from(value: crossterm::style::Color) -> Self {
use crate::output::color::Color;
match value {
crossterm::style::Color::Reset => Color::black(),
crossterm::style::Color::Black => Color::black(),
crossterm::style::Color::DarkGrey => Color::grey(false),
crossterm::style::Color::Red => Color::red(true),
crossterm::style::Color::DarkRed => Color::red(false),
crossterm::style::Color::Green => Color::green(true),
crossterm::style::Color::DarkGreen => Color::green(false),
crossterm::style::Color::Yellow => Color::yellow(true),
crossterm::style::Color::DarkYellow => Color::yellow(false),
crossterm::style::Color::Blue => Color::blue(true),
crossterm::style::Color::DarkBlue => Color::blue(false),
crossterm::style::Color::Magenta => Color::magenta(true),
crossterm::style::Color::DarkMagenta => Color::magenta(false),
crossterm::style::Color::Cyan => Color::cyan(true),
crossterm::style::Color::DarkCyan => Color::cyan(false),
crossterm::style::Color::White => Color::white(),
crossterm::style::Color::Grey => Color::grey(true),
crossterm::style::Color::Rgb { r, g, b } => Color::rgb(r, g, b),
crossterm::style::Color::AnsiValue(ansi) => Color::ansi(ansi),
}
}
}
impl From<&crossterm::style::ContentStyle> for crate::output::style::Style {
fn from(style: &crossterm::style::ContentStyle) -> Self {
use crate::output::color::Color;
crate::output::style::Style::DEFAULT
.front(style.foreground_color.map(Color::from))
.back(style.background_color.map(Color::from))
.frame(style.underline_color.map(Color::from))
.underlined(style.attributes.has(Attribute::Underlined))
.bold(style.attributes.has(Attribute::Bold))
.italic(style.attributes.has(Attribute::Italic))
.blink(
style.attributes.has(Attribute::SlowBlink)
|| style.attributes.has(Attribute::RapidBlink),
)
}
}
impl From<&crate::output::style::Style> for crossterm::style::ContentStyle {
fn from(val: &crate::output::style::Style) -> Self {
let mut style = crossterm::style::ContentStyle::default();
if let Some(c) = val.front_color {
style = style.with(c.into());
}
if let Some(c) = val.back_color {
style = style.on(c.into());
}
if let Some(c) = val.frame_color {
style = style.underline(c.into());
}
if val.underlined.unwrap_or_default() {
style.attributes.set(Attribute::Underlined)
}
if val.crossed_out.unwrap_or_default() {
style.attributes.set(Attribute::CrossedOut)
}
if val.bold.unwrap_or_default() {
style.attributes.set(Attribute::Bold)
}
if val.italic.unwrap_or_default() {
style.attributes.set(Attribute::Italic)
}
if val.blink.unwrap_or_default() {
style.attributes.set(Attribute::SlowBlink)
}
style
}
}
impl From<crossterm::style::ContentStyle> for crate::output::ansi::ScreenStyle {
fn from(style: crossterm::style::ContentStyle) -> Self {
let style = crate::output::style::Style::from(&style);
crate::output::ansi::ScreenStyle::from(&style)
}
}
impl<'a> From<crossterm::style::StyledContent<&'a str>> for Pretty<Cow<'a, str>> {
fn from(content: crossterm::style::StyledContent<&'a str>) -> Self {
let style = content.style();
let content = content.content().clone();
Pretty::new(Cow::Borrowed(content)).apply(crate::output::style::Style::from(style))
}
}
impl<'a> From<crossterm::style::StyledContent<String>> for Pretty<Cow<'a, str>> {
fn from(content: crossterm::style::StyledContent<String>) -> Self {
let style = crate::output::style::Style::from(content.style());
let content = content.content().clone();
let content: Cow<'a, str> = Cow::Owned(content);
Pretty::new(content).apply(style)
}
}
impl<M, C, A: AppEvent> Widget<M, A> for crossterm::style::StyledContent<C>
where
C: AsRef<str>,
C: std::fmt::Display,
{
fn update(
&mut self,
_model: &mut M,
_input: &Event<A>,
screen: &mut Screen,
painter: &Painter,
) -> Window {
painter
.apply(crate::output::style::Style::from(self.style()))
.paint(self.content().as_ref(), screen, 0, false)
}
}