diff options
Diffstat (limited to 'vendor/nu-ansi-term/src')
-rw-r--r-- | vendor/nu-ansi-term/src/ansi.rs | 407 | ||||
-rw-r--r-- | vendor/nu-ansi-term/src/debug.rs | 152 | ||||
-rw-r--r-- | vendor/nu-ansi-term/src/difference.rs | 174 | ||||
-rw-r--r-- | vendor/nu-ansi-term/src/display.rs | 290 | ||||
-rw-r--r-- | vendor/nu-ansi-term/src/gradient.rs | 105 | ||||
-rw-r--r-- | vendor/nu-ansi-term/src/lib.rs | 272 | ||||
-rw-r--r-- | vendor/nu-ansi-term/src/rgb.rs | 173 | ||||
-rw-r--r-- | vendor/nu-ansi-term/src/style.rs | 629 | ||||
-rw-r--r-- | vendor/nu-ansi-term/src/util.rs | 79 | ||||
-rw-r--r-- | vendor/nu-ansi-term/src/windows.rs | 62 | ||||
-rw-r--r-- | vendor/nu-ansi-term/src/write.rs | 37 |
11 files changed, 2380 insertions, 0 deletions
diff --git a/vendor/nu-ansi-term/src/ansi.rs b/vendor/nu-ansi-term/src/ansi.rs new file mode 100644 index 000000000..8f393fcdc --- /dev/null +++ b/vendor/nu-ansi-term/src/ansi.rs @@ -0,0 +1,407 @@ +#![allow(missing_docs)] +use crate::style::{Color, Style}; +use crate::write::AnyWrite; +use std::fmt; + +impl Style { + /// Write any bytes that go *before* a piece of text to the given writer. + fn write_prefix<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> { + // If there are actually no styles here, then don’t write *any* codes + // as the prefix. An empty ANSI code may not affect the terminal + // output at all, but a user may just want a code-free string. + if self.is_plain() { + return Ok(()); + } + + // Write the codes’ prefix, then write numbers, separated by + // semicolons, for each text style we want to apply. + write!(f, "\x1B[")?; + let mut written_anything = false; + + { + let mut write_char = |c| { + if written_anything { + write!(f, ";")?; + } + written_anything = true; + write!(f, "{}", c)?; + Ok(()) + }; + + if self.is_bold { + write_char('1')? + } + if self.is_dimmed { + write_char('2')? + } + if self.is_italic { + write_char('3')? + } + if self.is_underline { + write_char('4')? + } + if self.is_blink { + write_char('5')? + } + if self.is_reverse { + write_char('7')? + } + if self.is_hidden { + write_char('8')? + } + if self.is_strikethrough { + write_char('9')? + } + } + + // The foreground and background colors, if specified, need to be + // handled specially because the number codes are more complicated. + // (see `write_background_code` and `write_foreground_code`) + if let Some(bg) = self.background { + if written_anything { + write!(f, ";")?; + } + written_anything = true; + bg.write_background_code(f)?; + } + + if let Some(fg) = self.foreground { + if written_anything { + write!(f, ";")?; + } + fg.write_foreground_code(f)?; + } + + // All the codes end with an `m`, because reasons. + write!(f, "m")?; + + Ok(()) + } + + /// Write any bytes that go *after* a piece of text to the given writer. + fn write_suffix<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> { + if self.is_plain() { + Ok(()) + } else { + write!(f, "{}", RESET) + } + } +} + +/// The code to send to reset all styles and return to `Style::default()`. +pub static RESET: &str = "\x1B[0m"; + +impl Color { + fn write_foreground_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> { + match self { + Color::Black => write!(f, "30"), + Color::Red => write!(f, "31"), + Color::Green => write!(f, "32"), + Color::Yellow => write!(f, "33"), + Color::Blue => write!(f, "34"), + Color::Purple => write!(f, "35"), + Color::Magenta => write!(f, "35"), + Color::Cyan => write!(f, "36"), + Color::White => write!(f, "37"), + Color::Fixed(num) => write!(f, "38;5;{}", num), + Color::Rgb(r, g, b) => write!(f, "38;2;{};{};{}", r, g, b), + Color::Default => write!(f, "39"), + Color::DarkGray => write!(f, "90"), + Color::LightRed => write!(f, "91"), + Color::LightGreen => write!(f, "92"), + Color::LightYellow => write!(f, "93"), + Color::LightBlue => write!(f, "94"), + Color::LightPurple => write!(f, "95"), + Color::LightMagenta => write!(f, "95"), + Color::LightCyan => write!(f, "96"), + Color::LightGray => write!(f, "97"), + } + } + + fn write_background_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> { + match self { + Color::Black => write!(f, "40"), + Color::Red => write!(f, "41"), + Color::Green => write!(f, "42"), + Color::Yellow => write!(f, "43"), + Color::Blue => write!(f, "44"), + Color::Purple => write!(f, "45"), + Color::Magenta => write!(f, "45"), + Color::Cyan => write!(f, "46"), + Color::White => write!(f, "47"), + Color::Fixed(num) => write!(f, "48;5;{}", num), + Color::Rgb(r, g, b) => write!(f, "48;2;{};{};{}", r, g, b), + Color::Default => write!(f, "49"), + Color::DarkGray => write!(f, "100"), + Color::LightRed => write!(f, "101"), + Color::LightGreen => write!(f, "102"), + Color::LightYellow => write!(f, "103"), + Color::LightBlue => write!(f, "104"), + Color::LightPurple => write!(f, "105"), + Color::LightMagenta => write!(f, "105"), + Color::LightCyan => write!(f, "106"), + Color::LightGray => write!(f, "107"), + } + } +} + +/// Like `AnsiString`, but only displays the style prefix. +/// +/// This type implements the `Display` trait, meaning it can be written to a +/// `std::fmt` formatting without doing any extra allocation, and written to a +/// string with the `.to_string()` method. For examples, see +/// [`Style::prefix`](struct.Style.html#method.prefix). +#[derive(Clone, Copy, Debug)] +pub struct Prefix(Style); + +/// Like `AnsiString`, but only displays the difference between two +/// styles. +/// +/// This type implements the `Display` trait, meaning it can be written to a +/// `std::fmt` formatting without doing any extra allocation, and written to a +/// string with the `.to_string()` method. For examples, see +/// [`Style::infix`](struct.Style.html#method.infix). +#[derive(Clone, Copy, Debug)] +pub struct Infix(Style, Style); + +/// Like `AnsiString`, but only displays the style suffix. +/// +/// This type implements the `Display` trait, meaning it can be written to a +/// `std::fmt` formatting without doing any extra allocation, and written to a +/// string with the `.to_string()` method. For examples, see +/// [`Style::suffix`](struct.Style.html#method.suffix). +#[derive(Clone, Copy, Debug)] +pub struct Suffix(Style); + +impl Style { + /// The prefix bytes for this style. These are the bytes that tell the + /// terminal to use a different color or font style. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::{Style, Color::Blue}; + /// + /// let style = Style::default().bold(); + /// assert_eq!("\x1b[1m", + /// style.prefix().to_string()); + /// + /// let style = Blue.bold(); + /// assert_eq!("\x1b[1;34m", + /// style.prefix().to_string()); + /// + /// let style = Style::default(); + /// assert_eq!("", + /// style.prefix().to_string()); + /// ``` + pub fn prefix(self) -> Prefix { + Prefix(self) + } + + /// The infix bytes between this style and `next` style. These are the bytes + /// that tell the terminal to change the style to `next`. These may include + /// a reset followed by the next color and style, depending on the two styles. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::{Style, Color::Green}; + /// + /// let style = Style::default().bold(); + /// assert_eq!("\x1b[32m", + /// style.infix(Green.bold()).to_string()); + /// + /// let style = Green.normal(); + /// assert_eq!("\x1b[1m", + /// style.infix(Green.bold()).to_string()); + /// + /// let style = Style::default(); + /// assert_eq!("", + /// style.infix(style).to_string()); + /// ``` + pub fn infix(self, next: Style) -> Infix { + Infix(self, next) + } + + /// The suffix for this style. These are the bytes that tell the terminal + /// to reset back to its normal color and font style. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::{Style, Color::Green}; + /// + /// let style = Style::default().bold(); + /// assert_eq!("\x1b[0m", + /// style.suffix().to_string()); + /// + /// let style = Green.normal().bold(); + /// assert_eq!("\x1b[0m", + /// style.suffix().to_string()); + /// + /// let style = Style::default(); + /// assert_eq!("", + /// style.suffix().to_string()); + /// ``` + pub fn suffix(self) -> Suffix { + Suffix(self) + } +} + +impl Color { + /// The prefix bytes for this color as a `Style`. These are the bytes + /// that tell the terminal to use a different color or font style. + /// + /// See also [`Style::prefix`](struct.Style.html#method.prefix). + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color::Green; + /// + /// assert_eq!("\x1b[0m", + /// Green.suffix().to_string()); + /// ``` + pub fn prefix(self) -> Prefix { + Prefix(self.normal()) + } + + /// The infix bytes between this color and `next` color. These are the bytes + /// that tell the terminal to use the `next` color, or to do nothing if + /// the two colors are equal. + /// + /// See also [`Style::infix`](struct.Style.html#method.infix). + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color::{Red, Yellow}; + /// + /// assert_eq!("\x1b[33m", + /// Red.infix(Yellow).to_string()); + /// ``` + pub fn infix(self, next: Color) -> Infix { + Infix(self.normal(), next.normal()) + } + + /// The suffix for this color as a `Style`. These are the bytes that + /// tell the terminal to reset back to its normal color and font style. + /// + /// See also [`Style::suffix`](struct.Style.html#method.suffix). + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color::Purple; + /// + /// assert_eq!("\x1b[0m", + /// Purple.suffix().to_string()); + /// ``` + pub fn suffix(self) -> Suffix { + Suffix(self.normal()) + } +} + +impl fmt::Display for Prefix { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let f: &mut dyn fmt::Write = f; + self.0.write_prefix(f) + } +} + +impl fmt::Display for Infix { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use crate::difference::Difference; + + match Difference::between(&self.0, &self.1) { + Difference::ExtraStyles(style) => { + let f: &mut dyn fmt::Write = f; + style.write_prefix(f) + } + Difference::Reset => { + let f: &mut dyn fmt::Write = f; + write!(f, "{}{}", RESET, self.1.prefix()) + } + Difference::Empty => { + Ok(()) // nothing to write + } + } + } +} + +impl fmt::Display for Suffix { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let f: &mut dyn fmt::Write = f; + self.0.write_suffix(f) + } +} + +#[cfg(test)] +mod test { + use crate::style::Color::*; + use crate::style::Style; + + macro_rules! test { + ($name: ident: $style: expr; $input: expr => $result: expr) => { + #[test] + fn $name() { + assert_eq!($style.paint($input).to_string(), $result.to_string()); + + let mut v = Vec::new(); + $style.paint($input.as_bytes()).write_to(&mut v).unwrap(); + assert_eq!(v.as_slice(), $result.as_bytes()); + } + }; + } + + test!(plain: Style::default(); "text/plain" => "text/plain"); + test!(red: Red; "hi" => "\x1B[31mhi\x1B[0m"); + test!(black: Black.normal(); "hi" => "\x1B[30mhi\x1B[0m"); + test!(yellow_bold: Yellow.bold(); "hi" => "\x1B[1;33mhi\x1B[0m"); + test!(yellow_bold_2: Yellow.normal().bold(); "hi" => "\x1B[1;33mhi\x1B[0m"); + test!(blue_underline: Blue.underline(); "hi" => "\x1B[4;34mhi\x1B[0m"); + test!(green_bold_ul: Green.bold().underline(); "hi" => "\x1B[1;4;32mhi\x1B[0m"); + test!(green_bold_ul_2: Green.underline().bold(); "hi" => "\x1B[1;4;32mhi\x1B[0m"); + test!(purple_on_white: Purple.on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); + test!(purple_on_white_2: Purple.normal().on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); + test!(yellow_on_blue: Style::new().on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); + test!(magenta_on_white: Magenta.on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); + test!(magenta_on_white_2: Magenta.normal().on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); + test!(yellow_on_blue_2: Cyan.on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); + test!(cyan_bold_on_white: Cyan.bold().on(White); "hi" => "\x1B[1;47;36mhi\x1B[0m"); + test!(cyan_ul_on_white: Cyan.underline().on(White); "hi" => "\x1B[4;47;36mhi\x1B[0m"); + test!(cyan_bold_ul_on_white: Cyan.bold().underline().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m"); + test!(cyan_ul_bold_on_white: Cyan.underline().bold().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m"); + test!(fixed: Fixed(100); "hi" => "\x1B[38;5;100mhi\x1B[0m"); + test!(fixed_on_purple: Fixed(100).on(Purple); "hi" => "\x1B[45;38;5;100mhi\x1B[0m"); + test!(fixed_on_fixed: Fixed(100).on(Fixed(200)); "hi" => "\x1B[48;5;200;38;5;100mhi\x1B[0m"); + test!(rgb: Rgb(70,130,180); "hi" => "\x1B[38;2;70;130;180mhi\x1B[0m"); + test!(rgb_on_blue: Rgb(70,130,180).on(Blue); "hi" => "\x1B[44;38;2;70;130;180mhi\x1B[0m"); + test!(blue_on_rgb: Blue.on(Rgb(70,130,180)); "hi" => "\x1B[48;2;70;130;180;34mhi\x1B[0m"); + test!(rgb_on_rgb: Rgb(70,130,180).on(Rgb(5,10,15)); "hi" => "\x1B[48;2;5;10;15;38;2;70;130;180mhi\x1B[0m"); + test!(bold: Style::new().bold(); "hi" => "\x1B[1mhi\x1B[0m"); + test!(underline: Style::new().underline(); "hi" => "\x1B[4mhi\x1B[0m"); + test!(bunderline: Style::new().bold().underline(); "hi" => "\x1B[1;4mhi\x1B[0m"); + test!(dimmed: Style::new().dimmed(); "hi" => "\x1B[2mhi\x1B[0m"); + test!(italic: Style::new().italic(); "hi" => "\x1B[3mhi\x1B[0m"); + test!(blink: Style::new().blink(); "hi" => "\x1B[5mhi\x1B[0m"); + test!(reverse: Style::new().reverse(); "hi" => "\x1B[7mhi\x1B[0m"); + test!(hidden: Style::new().hidden(); "hi" => "\x1B[8mhi\x1B[0m"); + test!(stricken: Style::new().strikethrough(); "hi" => "\x1B[9mhi\x1B[0m"); + test!(lr_on_lr: LightRed.on(LightRed); "hi" => "\x1B[101;91mhi\x1B[0m"); + + #[test] + fn test_infix() { + assert_eq!( + Style::new().dimmed().infix(Style::new()).to_string(), + "\x1B[0m" + ); + assert_eq!( + White.dimmed().infix(White.normal()).to_string(), + "\x1B[0m\x1B[37m" + ); + assert_eq!(White.normal().infix(White.bold()).to_string(), "\x1B[1m"); + assert_eq!(White.normal().infix(Blue.normal()).to_string(), "\x1B[34m"); + assert_eq!(Blue.bold().infix(Blue.bold()).to_string(), ""); + } +} diff --git a/vendor/nu-ansi-term/src/debug.rs b/vendor/nu-ansi-term/src/debug.rs new file mode 100644 index 000000000..1dcde52be --- /dev/null +++ b/vendor/nu-ansi-term/src/debug.rs @@ -0,0 +1,152 @@ +use crate::style::Style; +use std::fmt; + +/// Styles have a special `Debug` implementation that only shows the fields that +/// are set. Fields that haven’t been touched aren’t included in the output. +/// +/// This behaviour gets bypassed when using the alternate formatting mode +/// `format!("{:#?}")`. +/// +/// use nu_ansi_term::Color::{Red, Blue}; +/// assert_eq!("Style { fg(Red), on(Blue), bold, italic }", +/// format!("{:?}", Red.on(Blue).bold().italic())); +impl fmt::Debug for Style { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + if fmt.alternate() { + fmt.debug_struct("Style") + .field("foreground", &self.foreground) + .field("background", &self.background) + .field("blink", &self.is_blink) + .field("bold", &self.is_bold) + .field("dimmed", &self.is_dimmed) + .field("hidden", &self.is_hidden) + .field("italic", &self.is_italic) + .field("reverse", &self.is_reverse) + .field("strikethrough", &self.is_strikethrough) + .field("underline", &self.is_underline) + .finish() + } else if self.is_plain() { + fmt.write_str("Style {}") + } else { + fmt.write_str("Style { ")?; + + let mut written_anything = false; + + if let Some(fg) = self.foreground { + if written_anything { + fmt.write_str(", ")? + } + written_anything = true; + write!(fmt, "fg({:?})", fg)? + } + + if let Some(bg) = self.background { + if written_anything { + fmt.write_str(", ")? + } + written_anything = true; + write!(fmt, "on({:?})", bg)? + } + + { + let mut write_flag = |name| { + if written_anything { + fmt.write_str(", ")? + } + written_anything = true; + fmt.write_str(name) + }; + + if self.is_blink { + write_flag("blink")? + } + if self.is_bold { + write_flag("bold")? + } + if self.is_dimmed { + write_flag("dimmed")? + } + if self.is_hidden { + write_flag("hidden")? + } + if self.is_italic { + write_flag("italic")? + } + if self.is_reverse { + write_flag("reverse")? + } + if self.is_strikethrough { + write_flag("strikethrough")? + } + if self.is_underline { + write_flag("underline")? + } + } + + write!(fmt, " }}") + } + } +} + +#[cfg(test)] +mod test { + use crate::style::Color::*; + use crate::style::Style; + + fn style() -> Style { + Style::new() + } + + macro_rules! test { + ($name: ident: $obj: expr => $result: expr) => { + #[test] + fn $name() { + assert_eq!($result, format!("{:?}", $obj)); + } + }; + } + + test!(empty: style() => "Style {}"); + test!(bold: style().bold() => "Style { bold }"); + test!(italic: style().italic() => "Style { italic }"); + test!(both: style().bold().italic() => "Style { bold, italic }"); + + test!(red: Red.normal() => "Style { fg(Red) }"); + test!(redblue: Red.normal().on(Rgb(3, 2, 4)) => "Style { fg(Red), on(Rgb(3, 2, 4)) }"); + + test!(everything: + Red.on(Blue).blink().bold().dimmed().hidden().italic().reverse().strikethrough().underline() => + "Style { fg(Red), on(Blue), blink, bold, dimmed, hidden, italic, reverse, strikethrough, underline }"); + + #[test] + fn long_and_detailed() { + extern crate regex; + let expected_debug = "Style { fg(Blue), bold }"; + let expected_pretty_repat = r##"(?x) + Style\s+\{\s+ + foreground:\s+Some\(\s+ + Blue,?\s+ + \),\s+ + background:\s+None,\s+ + blink:\s+false,\s+ + bold:\s+true,\s+ + dimmed:\s+false,\s+ + hidden:\s+false,\s+ + italic:\s+false,\s+ + reverse:\s+false,\s+ + strikethrough:\s+ + false,\s+ + underline:\s+false,?\s+ + \}"##; + let re = regex::Regex::new(expected_pretty_repat).unwrap(); + + let style = Blue.bold(); + let style_fmt_debug = format!("{:?}", style); + let style_fmt_pretty = format!("{:#?}", style); + println!("style_fmt_debug:\n{}", style_fmt_debug); + println!("style_fmt_pretty:\n{}", style_fmt_pretty); + + assert_eq!(expected_debug, style_fmt_debug); + assert!(re.is_match(&style_fmt_pretty)); + } +} diff --git a/vendor/nu-ansi-term/src/difference.rs b/vendor/nu-ansi-term/src/difference.rs new file mode 100644 index 000000000..beee8ea25 --- /dev/null +++ b/vendor/nu-ansi-term/src/difference.rs @@ -0,0 +1,174 @@ +use super::Style; + +/// When printing out one colored string followed by another, use one of +/// these rules to figure out which *extra* control codes need to be sent. +#[derive(PartialEq, Clone, Copy, Debug)] +pub enum Difference { + /// Print out the control codes specified by this style to end up looking + /// like the second string's styles. + ExtraStyles(Style), + + /// Converting between these two is impossible, so just send a reset + /// command and then the second string's styles. + Reset, + + /// The before style is exactly the same as the after style, so no further + /// control codes need to be printed. + Empty, +} + +impl Difference { + /// Compute the 'style difference' required to turn an existing style into + /// the given, second style. + /// + /// For example, to turn green text into green bold text, it's redundant + /// to write a reset command then a second green+bold command, instead of + /// just writing one bold command. This method should see that both styles + /// use the foreground color green, and reduce it to a single command. + /// + /// This method returns an enum value because it's not actually always + /// possible to turn one style into another: for example, text could be + /// made bold and underlined, but you can't remove the bold property + /// without also removing the underline property. So when this has to + /// happen, this function returns None, meaning that the entire set of + /// styles should be reset and begun again. + pub fn between(first: &Style, next: &Style) -> Difference { + use self::Difference::*; + + // XXX(Havvy): This algorithm is kind of hard to replicate without + // having the Plain/Foreground enum variants, so I'm just leaving + // it commented out for now, and defaulting to Reset. + + if first == next { + return Empty; + } + + // Cannot un-bold, so must Reset. + if first.is_bold && !next.is_bold { + return Reset; + } + + if first.is_dimmed && !next.is_dimmed { + return Reset; + } + + if first.is_italic && !next.is_italic { + return Reset; + } + + // Cannot un-underline, so must Reset. + if first.is_underline && !next.is_underline { + return Reset; + } + + if first.is_blink && !next.is_blink { + return Reset; + } + + if first.is_reverse && !next.is_reverse { + return Reset; + } + + if first.is_hidden && !next.is_hidden { + return Reset; + } + + if first.is_strikethrough && !next.is_strikethrough { + return Reset; + } + + // Cannot go from foreground to no foreground, so must Reset. + if first.foreground.is_some() && next.foreground.is_none() { + return Reset; + } + + // Cannot go from background to no background, so must Reset. + if first.background.is_some() && next.background.is_none() { + return Reset; + } + + let mut extra_styles = Style::default(); + + if first.is_bold != next.is_bold { + extra_styles.is_bold = true; + } + + if first.is_dimmed != next.is_dimmed { + extra_styles.is_dimmed = true; + } + + if first.is_italic != next.is_italic { + extra_styles.is_italic = true; + } + + if first.is_underline != next.is_underline { + extra_styles.is_underline = true; + } + + if first.is_blink != next.is_blink { + extra_styles.is_blink = true; + } + + if first.is_reverse != next.is_reverse { + extra_styles.is_reverse = true; + } + + if first.is_hidden != next.is_hidden { + extra_styles.is_hidden = true; + } + + if first.is_strikethrough != next.is_strikethrough { + extra_styles.is_strikethrough = true; + } + + if first.foreground != next.foreground { + extra_styles.foreground = next.foreground; + } + + if first.background != next.background { + extra_styles.background = next.background; + } + + ExtraStyles(extra_styles) + } +} + +#[cfg(test)] +mod test { + use super::Difference::*; + use super::*; + use crate::style::Color::*; + use crate::style::Style; + + fn style() -> Style { + Style::new() + } + + macro_rules! test { + ($name: ident: $first: expr; $next: expr => $result: expr) => { + #[test] + fn $name() { + assert_eq!($result, Difference::between(&$first, &$next)); + } + }; + } + + test!(nothing: Green.normal(); Green.normal() => Empty); + test!(uppercase: Green.normal(); Green.bold() => ExtraStyles(style().bold())); + test!(lowercase: Green.bold(); Green.normal() => Reset); + test!(nothing2: Green.bold(); Green.bold() => Empty); + + test!(color_change: Red.normal(); Blue.normal() => ExtraStyles(Blue.normal())); + + test!(addition_of_blink: style(); style().blink() => ExtraStyles(style().blink())); + test!(addition_of_dimmed: style(); style().dimmed() => ExtraStyles(style().dimmed())); + test!(addition_of_hidden: style(); style().hidden() => ExtraStyles(style().hidden())); + test!(addition_of_reverse: style(); style().reverse() => ExtraStyles(style().reverse())); + test!(addition_of_strikethrough: style(); style().strikethrough() => ExtraStyles(style().strikethrough())); + + test!(removal_of_strikethrough: style().strikethrough(); style() => Reset); + test!(removal_of_reverse: style().reverse(); style() => Reset); + test!(removal_of_hidden: style().hidden(); style() => Reset); + test!(removal_of_dimmed: style().dimmed(); style() => Reset); + test!(removal_of_blink: style().blink(); style() => Reset); +} diff --git a/vendor/nu-ansi-term/src/display.rs b/vendor/nu-ansi-term/src/display.rs new file mode 100644 index 000000000..bed934cb3 --- /dev/null +++ b/vendor/nu-ansi-term/src/display.rs @@ -0,0 +1,290 @@ +use crate::ansi::RESET; +use crate::difference::Difference; +use crate::style::{Color, Style}; +use crate::write::AnyWrite; +use std::borrow::Cow; +use std::fmt; +use std::io; + +/// An `AnsiGenericString` includes a generic string type and a `Style` to +/// display that string. `AnsiString` and `AnsiByteString` are aliases for +/// this type on `str` and `\[u8]`, respectively. +#[derive(PartialEq, Debug)] +pub struct AnsiGenericString<'a, S: 'a + ToOwned + ?Sized> +where + <S as ToOwned>::Owned: fmt::Debug, +{ + pub(crate) style: Style, + pub(crate) string: Cow<'a, S>, +} + +/// Cloning an `AnsiGenericString` will clone its underlying string. +/// +/// # Examples +/// +/// ``` +/// use nu_ansi_term::AnsiString; +/// +/// let plain_string = AnsiString::from("a plain string"); +/// let clone_string = plain_string.clone(); +/// assert_eq!(clone_string, plain_string); +/// ``` +impl<'a, S: 'a + ToOwned + ?Sized> Clone for AnsiGenericString<'a, S> +where + <S as ToOwned>::Owned: fmt::Debug, +{ + fn clone(&self) -> AnsiGenericString<'a, S> { + AnsiGenericString { + style: self.style, + string: self.string.clone(), + } + } +} + +// You might think that the hand-written Clone impl above is the same as the +// one that gets generated with #[derive]. But it’s not *quite* the same! +// +// `str` is not Clone, and the derived Clone implementation puts a Clone +// constraint on the S type parameter (generated using --pretty=expanded): +// +// ↓_________________↓ +// impl <'a, S: ::std::clone::Clone + 'a + ToOwned + ?Sized> ::std::clone::Clone +// for ANSIGenericString<'a, S> where +// <S as ToOwned>::Owned: fmt::Debug { ... } +// +// This resulted in compile errors when you tried to derive Clone on a type +// that used it: +// +// #[derive(PartialEq, Debug, Clone, Default)] +// pub struct TextCellContents(Vec<AnsiString<'static>>); +// ^^^^^^^^^^^^^^^^^^^^^^^^^ +// error[E0277]: the trait `std::clone::Clone` is not implemented for `str` +// +// The hand-written impl above can ignore that constraint and still compile. + +/// An ANSI String is a string coupled with the `Style` to display it +/// in a terminal. +/// +/// Although not technically a string itself, it can be turned into +/// one with the `to_string` method. +/// +/// # Examples +/// +/// ``` +/// use nu_ansi_term::AnsiString; +/// use nu_ansi_term::Color::Red; +/// +/// let red_string = Red.paint("a red string"); +/// println!("{}", red_string); +/// ``` +/// +/// ``` +/// use nu_ansi_term::AnsiString; +/// +/// let plain_string = AnsiString::from("a plain string"); +/// ``` +pub type AnsiString<'a> = AnsiGenericString<'a, str>; + +/// An `AnsiByteString` represents a formatted series of bytes. Use +/// `AnsiByteString` when styling text with an unknown encoding. +pub type AnsiByteString<'a> = AnsiGenericString<'a, [u8]>; + +impl<'a, I, S: 'a + ToOwned + ?Sized> From<I> for AnsiGenericString<'a, S> +where + I: Into<Cow<'a, S>>, + <S as ToOwned>::Owned: fmt::Debug, +{ + fn from(input: I) -> AnsiGenericString<'a, S> { + AnsiGenericString { + string: input.into(), + style: Style::default(), + } + } +} + +impl<'a, S: 'a + ToOwned + ?Sized> AnsiGenericString<'a, S> +where + <S as ToOwned>::Owned: fmt::Debug, +{ + /// Directly access the style + pub fn style_ref(&self) -> &Style { + &self.style + } + + /// Directly access the style mutably + pub fn style_ref_mut(&mut self) -> &mut Style { + &mut self.style + } +} + +/// A set of `AnsiGenericStrings`s collected together, in order to be +/// written with a minimum of control characters. +#[derive(Debug, PartialEq)] +pub struct AnsiGenericStrings<'a, S: 'a + ToOwned + ?Sized>(pub &'a [AnsiGenericString<'a, S>]) +where + <S as ToOwned>::Owned: fmt::Debug, + S: PartialEq; + +/// A set of `AnsiString`s collected together, in order to be written with a +/// minimum of control characters. +pub type AnsiStrings<'a> = AnsiGenericStrings<'a, str>; + +/// A function to construct an `AnsiStrings` instance. +#[allow(non_snake_case)] +pub fn AnsiStrings<'a>(arg: &'a [AnsiString<'a>]) -> AnsiStrings<'a> { + AnsiGenericStrings(arg) +} + +/// A set of `AnsiByteString`s collected together, in order to be +/// written with a minimum of control characters. +pub type AnsiByteStrings<'a> = AnsiGenericStrings<'a, [u8]>; + +/// A function to construct an `AnsiByteStrings` instance. +#[allow(non_snake_case)] +pub fn AnsiByteStrings<'a>(arg: &'a [AnsiByteString<'a>]) -> AnsiByteStrings<'a> { + AnsiGenericStrings(arg) +} + +// ---- paint functions ---- + +impl Style { + /// Paints the given text with this color, returning an ANSI string. + #[must_use] + pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> AnsiGenericString<'a, S> + where + I: Into<Cow<'a, S>>, + <S as ToOwned>::Owned: fmt::Debug, + { + AnsiGenericString { + string: input.into(), + style: self, + } + } +} + +impl Color { + /// Paints the given text with this color, returning an ANSI string. + /// This is a short-cut so you don’t have to use `Blue.normal()` just + /// to get blue text. + /// + /// ``` + /// use nu_ansi_term::Color::Blue; + /// println!("{}", Blue.paint("da ba dee")); + /// ``` + #[must_use] + pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> AnsiGenericString<'a, S> + where + I: Into<Cow<'a, S>>, + <S as ToOwned>::Owned: fmt::Debug, + { + AnsiGenericString { + string: input.into(), + style: self.normal(), + } + } +} + +// ---- writers for individual ANSI strings ---- + +impl<'a> fmt::Display for AnsiString<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let w: &mut dyn fmt::Write = f; + self.write_to_any(w) + } +} + +impl<'a> AnsiByteString<'a> { + /// Write an `AnsiByteString` to an `io::Write`. This writes the escape + /// sequences for the associated `Style` around the bytes. + pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> { + let w: &mut dyn io::Write = w; + self.write_to_any(w) + } +} + +impl<'a, S: 'a + ToOwned + ?Sized> AnsiGenericString<'a, S> +where + <S as ToOwned>::Owned: fmt::Debug, + &'a S: AsRef<[u8]>, +{ + fn write_to_any<W: AnyWrite<Wstr = S> + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> { + write!(w, "{}", self.style.prefix())?; + w.write_str(self.string.as_ref())?; + write!(w, "{}", self.style.suffix()) + } +} + +// ---- writers for combined ANSI strings ---- + +impl<'a> fmt::Display for AnsiStrings<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let f: &mut dyn fmt::Write = f; + self.write_to_any(f) + } +} + +impl<'a> AnsiByteStrings<'a> { + /// Write `AnsiByteStrings` to an `io::Write`. This writes the minimal + /// escape sequences for the associated `Style`s around each set of + /// bytes. + pub fn write_to<W: io::Write>(&self, w: &mut W) -> io::Result<()> { + let w: &mut dyn io::Write = w; + self.write_to_any(w) + } +} + +impl<'a, S: 'a + ToOwned + ?Sized + PartialEq> AnsiGenericStrings<'a, S> +where + <S as ToOwned>::Owned: fmt::Debug, + &'a S: AsRef<[u8]>, +{ + fn write_to_any<W: AnyWrite<Wstr = S> + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> { + use self::Difference::*; + + let first = match self.0.first() { + None => return Ok(()), + Some(f) => f, + }; + + write!(w, "{}", first.style.prefix())?; + w.write_str(first.string.as_ref())?; + + for window in self.0.windows(2) { + match Difference::between(&window[0].style, &window[1].style) { + ExtraStyles(style) => write!(w, "{}", style.prefix())?, + Reset => write!(w, "{}{}", RESET, window[1].style.prefix())?, + Empty => { /* Do nothing! */ } + } + + w.write_str(&window[1].string)?; + } + + // Write the final reset string after all of the AnsiStrings have been + // written, *except* if the last one has no styles, because it would + // have already been written by this point. + if let Some(last) = self.0.last() { + if !last.style.is_plain() { + write!(w, "{}", RESET)?; + } + } + + Ok(()) + } +} + +// ---- tests ---- + +#[cfg(test)] +mod tests { + pub use super::super::AnsiStrings; + pub use crate::style::Color::*; + pub use crate::style::Style; + + #[test] + fn no_control_codes_for_plain() { + let one = Style::default().paint("one"); + let two = Style::default().paint("two"); + let output = AnsiStrings(&[one, two]).to_string(); + assert_eq!(output, "onetwo"); + } +} diff --git a/vendor/nu-ansi-term/src/gradient.rs b/vendor/nu-ansi-term/src/gradient.rs new file mode 100644 index 000000000..a0d94c8cd --- /dev/null +++ b/vendor/nu-ansi-term/src/gradient.rs @@ -0,0 +1,105 @@ +use crate::{rgb::Rgb, Color}; + +/// Linear color gradient between two color stops +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Gradient { + /// Start Color of Gradient + pub start: Rgb, + + /// End Color of Gradient + pub end: Rgb, +} + +impl Gradient { + /// Creates a new [Gradient] with two [Rgb] colors, `start` and `end` + #[inline] + pub const fn new(start: Rgb, end: Rgb) -> Self { + Self { start, end } + } + pub const fn from_color_rgb(start: Color, end: Color) -> Self { + let start_grad = match start { + Color::Rgb(r, g, b) => Rgb { r, g, b }, + _ => Rgb { r: 0, g: 0, b: 0 }, + }; + let end_grad = match end { + Color::Rgb(r, g, b) => Rgb { r, g, b }, + _ => Rgb { r: 0, g: 0, b: 0 }, + }; + + Self { + start: start_grad, + end: end_grad, + } + } + + /// Computes the [Rgb] color between `start` and `end` for `t` + pub fn at(&self, t: f32) -> Rgb { + self.start.lerp(self.end, t) + } + + /// Returns the reverse of `self` + #[inline] + pub const fn reverse(&self) -> Self { + Self::new(self.end, self.start) + } + + #[allow(dead_code)] + pub fn build(&self, text: &str, target: TargetGround) -> String { + let delta = 1.0 / text.len() as f32; + let mut result = text.char_indices().fold(String::new(), |mut acc, (i, c)| { + let temp = format!( + "\x1B[{}m{}", + self.at(i as f32 * delta).ansi_color_code(target), + c + ); + acc.push_str(&temp); + acc + }); + + result.push_str("\x1B[0m"); + result + } +} + +#[allow(dead_code)] +pub fn build_all_gradient_text(text: &str, foreground: Gradient, background: Gradient) -> String { + let delta = 1.0 / text.len() as f32; + let mut result = text.char_indices().fold(String::new(), |mut acc, (i, c)| { + let step = i as f32 * delta; + let temp = format!( + "\x1B[{};{}m{}", + foreground + .at(step) + .ansi_color_code(TargetGround::Foreground), + background + .at(step) + .ansi_color_code(TargetGround::Background), + c + ); + acc.push_str(&temp); + acc + }); + + result.push_str("\x1B[0m"); + result +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TargetGround { + Foreground, + Background, +} + +impl TargetGround { + #[inline] + pub const fn code(&self) -> u8 { + match self { + Self::Foreground => 30, + Self::Background => 40, + } + } +} + +pub trait ANSIColorCode { + fn ansi_color_code(&self, target: TargetGround) -> String; +} diff --git a/vendor/nu-ansi-term/src/lib.rs b/vendor/nu-ansi-term/src/lib.rs new file mode 100644 index 000000000..c04fd3276 --- /dev/null +++ b/vendor/nu-ansi-term/src/lib.rs @@ -0,0 +1,272 @@ +//! This is a library for controlling colors and formatting, such as +//! red bold text or blue underlined text, on ANSI terminals. +//! +//! +//! ## Basic usage +//! +//! There are three main types in this crate that you need to be +//! concerned with: [`AnsiString`], [`Style`], and [`Color`]. +//! +//! A `Style` holds stylistic information: foreground and background colors, +//! whether the text should be bold, or blinking, or other properties. The +//! [`Color`] enum represents the available colors. And an [`AnsiString`] is a +//! string paired with a [`Style`]. +//! +//! [`Color`] is also available as an alias to `Color`. +//! +//! To format a string, call the `paint` method on a `Style` or a `Color`, +//! passing in the string you want to format as the argument. For example, +//! here’s how to get some red text: +//! +//! ``` +//! use nu_ansi_term::Color::Red; +//! +//! println!("This is in red: {}", Red.paint("a red string")); +//! ``` +//! +//! It’s important to note that the `paint` method does *not* actually return a +//! string with the ANSI control characters surrounding it. Instead, it returns +//! an [`AnsiString`] value that has a [`Display`] implementation that, when +//! formatted, returns the characters. This allows strings to be printed with a +//! minimum of [`String`] allocations being performed behind the scenes. +//! +//! If you *do* want to get at the escape codes, then you can convert the +//! [`AnsiString`] to a string as you would any other `Display` value: +//! +//! ``` +//! use nu_ansi_term::Color::Red; +//! +//! let red_string = Red.paint("a red string").to_string(); +//! ``` +//! +//! +//! ## Bold, underline, background, and other styles +//! +//! For anything more complex than plain foreground color changes, you need to +//! construct `Style` values themselves, rather than beginning with a `Color`. +//! You can do this by chaining methods based on a new `Style`, created with +//! [`Style::new()`]. Each method creates a new style that has that specific +//! property set. For example: +//! +//! ``` +//! use nu_ansi_term::Style; +//! +//! println!("How about some {} and {}?", +//! Style::new().bold().paint("bold"), +//! Style::new().underline().paint("underline")); +//! ``` +//! +//! For brevity, these methods have also been implemented for `Color` values, +//! so you can give your styles a foreground color without having to begin with +//! an empty `Style` value: +//! +//! ``` +//! use nu_ansi_term::Color::{Blue, Yellow}; +//! +//! println!("Demonstrating {} and {}!", +//! Blue.bold().paint("blue bold"), +//! Yellow.underline().paint("yellow underline")); +//! +//! println!("Yellow on blue: {}", Yellow.on(Blue).paint("wow!")); +//! ``` +//! +//! The complete list of styles you can use are: [`bold`], [`dimmed`], [`italic`], +//! [`underline`], [`blink`], [`reverse`], [`hidden`], [`strikethrough`], and [`on`] for +//! background colors. +//! +//! In some cases, you may find it easier to change the foreground on an +//! existing `Style` rather than starting from the appropriate `Color`. +//! You can do this using the [`fg`] method: +//! +//! ``` +//! use nu_ansi_term::Style; +//! use nu_ansi_term::Color::{Blue, Cyan, Yellow}; +//! +//! println!("Yellow on blue: {}", Style::new().on(Blue).fg(Yellow).paint("yow!")); +//! println!("Also yellow on blue: {}", Cyan.on(Blue).fg(Yellow).paint("zow!")); +//! ``` +//! +//! You can turn a `Color` into a `Style` with the [`normal`] method. +//! This will produce the exact same `AnsiString` as if you just used the +//! `paint` method on the `Color` directly, but it’s useful in certain cases: +//! for example, you may have a method that returns `Styles`, and need to +//! represent both the “red bold” and “red, but not bold” styles with values of +//! the same type. The `Style` struct also has a [`Default`] implementation if you +//! want to have a style with *nothing* set. +//! +//! ``` +//! use nu_ansi_term::Style; +//! use nu_ansi_term::Color::Red; +//! +//! Red.normal().paint("yet another red string"); +//! Style::default().paint("a completely regular string"); +//! ``` +//! +//! +//! ## Extended colors +//! +//! You can access the extended range of 256 colors by using the `Color::Fixed` +//! variant, which takes an argument of the color number to use. This can be +//! included wherever you would use a `Color`: +//! +//! ``` +//! use nu_ansi_term::Color::Fixed; +//! +//! Fixed(134).paint("A sort of light purple"); +//! Fixed(221).on(Fixed(124)).paint("Mustard in the ketchup"); +//! ``` +//! +//! The first sixteen of these values are the same as the normal and bold +//! standard color variants. There’s nothing stopping you from using these as +//! `Fixed` colors instead, but there’s nothing to be gained by doing so +//! either. +//! +//! You can also access full 24-bit color by using the `Color::Rgb` variant, +//! which takes separate `u8` arguments for red, green, and blue: +//! +//! ``` +//! use nu_ansi_term::Color::Rgb; +//! +//! Rgb(70, 130, 180).paint("Steel blue"); +//! ``` +//! +//! ## Combining successive colored strings +//! +//! The benefit of writing ANSI escape codes to the terminal is that they +//! *stack*: you do not need to end every colored string with a reset code if +//! the text that follows it is of a similar style. For example, if you want to +//! have some blue text followed by some blue bold text, it’s possible to send +//! the ANSI code for blue, followed by the ANSI code for bold, and finishing +//! with a reset code without having to have an extra one between the two +//! strings. +//! +//! This crate can optimise the ANSI codes that get printed in situations like +//! this, making life easier for your terminal renderer. The [`AnsiStrings`] +//! type takes a slice of several [`AnsiString`] values, and will iterate over +//! each of them, printing only the codes for the styles that need to be updated +//! as part of its formatting routine. +//! +//! The following code snippet uses this to enclose a binary number displayed in +//! red bold text inside some red, but not bold, brackets: +//! +//! ``` +//! use nu_ansi_term::Color::Red; +//! use nu_ansi_term::{AnsiString, AnsiStrings}; +//! +//! let some_value = format!("{:b}", 42); +//! let strings: &[AnsiString<'static>] = &[ +//! Red.paint("["), +//! Red.bold().paint(some_value), +//! Red.paint("]"), +//! ]; +//! +//! println!("Value: {}", AnsiStrings(strings)); +//! ``` +//! +//! There are several things to note here. Firstly, the [`paint`] method can take +//! *either* an owned [`String`] or a borrowed [`&str`]. Internally, an [`AnsiString`] +//! holds a copy-on-write ([`Cow`]) string value to deal with both owned and +//! borrowed strings at the same time. This is used here to display a `String`, +//! the result of the `format!` call, using the same mechanism as some +//! statically-available `&str` slices. Secondly, that the [`AnsiStrings`] value +//! works in the same way as its singular counterpart, with a [`Display`] +//! implementation that only performs the formatting when required. +//! +//! ## Byte strings +//! +//! This library also supports formatting `\[u8]` byte strings; this supports +//! applications working with text in an unknown encoding. [`Style`] and +//! [`Color`] support painting `\[u8]` values, resulting in an [`AnsiByteString`]. +//! This type does not implement [`Display`], as it may not contain UTF-8, but +//! it does provide a method [`write_to`] to write the result to any value that +//! implements [`Write`]: +//! +//! ``` +//! use nu_ansi_term::Color::Green; +//! +//! Green.paint("user data".as_bytes()).write_to(&mut std::io::stdout()).unwrap(); +//! ``` +//! +//! Similarly, the type [`AnsiByteStrings`] supports writing a list of +//! [`AnsiByteString`] values with minimal escape sequences: +//! +//! ``` +//! use nu_ansi_term::Color::Green; +//! use nu_ansi_term::AnsiByteStrings; +//! +//! AnsiByteStrings(&[ +//! Green.paint("user data 1\n".as_bytes()), +//! Green.bold().paint("user data 2\n".as_bytes()), +//! ]).write_to(&mut std::io::stdout()).unwrap(); +//! ``` +//! +//! [`Cow`]: https://doc.rust-lang.org/std/borrow/enum.Cow.html +//! [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html +//! [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html +//! [`String`]: https://doc.rust-lang.org/std/string/struct.String.html +//! [`&str`]: https://doc.rust-lang.org/std/primitive.str.html +//! [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +//! [`Style`]: struct.Style.html +//! [`Style::new()`]: struct.Style.html#method.new +//! [`Color`]: enum.Color.html +//! [`Color`]: enum.Color.html +//! [`AnsiString`]: type.AnsiString.html +//! [`AnsiStrings`]: type.AnsiStrings.html +//! [`AnsiByteString`]: type.AnsiByteString.html +//! [`AnsiByteStrings`]: type.AnsiByteStrings.html +//! [`write_to`]: type.AnsiByteString.html#method.write_to +//! [`paint`]: type.AnsiByteString.html#method.write_to +//! [`normal`]: enum.Color.html#method.normal +//! +//! [`bold`]: struct.Style.html#method.bold +//! [`dimmed`]: struct.Style.html#method.dimmed +//! [`italic`]: struct.Style.html#method.italic +//! [`underline`]: struct.Style.html#method.underline +//! [`blink`]: struct.Style.html#method.blink +//! [`reverse`]: struct.Style.html#method.reverse +//! [`hidden`]: struct.Style.html#method.hidden +//! [`strikethrough`]: struct.Style.html#method.strikethrough +//! [`fg`]: struct.Style.html#method.fg +//! [`on`]: struct.Style.html#method.on + +#![crate_name = "nu_ansi_term"] +#![crate_type = "rlib"] +#![warn(missing_copy_implementations)] +// #![warn(missing_docs)] +#![warn(trivial_casts, trivial_numeric_casts)] +// #![warn(unused_extern_crates, unused_qualifications)] + +#[cfg(target_os = "windows")] +extern crate winapi; +#[cfg(test)] +#[macro_use] +extern crate doc_comment; + +#[cfg(test)] +doctest!("../README.md"); + +pub mod ansi; +pub use ansi::{Infix, Prefix, Suffix}; + +mod style; +pub use style::{Color, Style}; + +mod difference; +mod display; +pub use display::*; + +mod write; + +mod windows; +pub use windows::*; + +mod util; +pub use util::*; + +mod debug; + +pub mod gradient; +pub use gradient::*; + +mod rgb; +pub use rgb::*; diff --git a/vendor/nu-ansi-term/src/rgb.rs b/vendor/nu-ansi-term/src/rgb.rs new file mode 100644 index 000000000..19475c36b --- /dev/null +++ b/vendor/nu-ansi-term/src/rgb.rs @@ -0,0 +1,173 @@ +// Code liberally borrowed from here +// https://github.com/navierr/coloriz +use std::ops; +use std::u32; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Rgb { + /// Red + pub r: u8, + /// Green + pub g: u8, + /// Blue + pub b: u8, +} + +impl Rgb { + /// Creates a new [Rgb] color + #[inline] + pub const fn new(r: u8, g: u8, b: u8) -> Self { + Self { r, g, b } + } + + /// Creates a new [Rgb] color with a hex code + #[inline] + pub const fn from_hex(hex: u32) -> Self { + Self::new((hex >> 16) as u8, (hex >> 8) as u8, hex as u8) + } + + pub fn from_hex_string(hex: String) -> Self { + if hex.chars().count() == 8 && hex.starts_with("0x") { + // eprintln!("hex:{:?}", hex); + let (_, value_string) = hex.split_at(2); + // eprintln!("value_string:{:?}", value_string); + let int_val = u64::from_str_radix(value_string, 16); + match int_val { + Ok(num) => Self::new( + ((num & 0xff0000) >> 16) as u8, + ((num & 0xff00) >> 8) as u8, + (num & 0xff) as u8, + ), + // Don't fail, just make the color black + // Should we fail? + _ => Self::new(0, 0, 0), + } + } else { + // Don't fail, just make the color black. + // Should we fail? + Self::new(0, 0, 0) + } + } + + /// Creates a new [Rgb] color with three [f32] values + pub fn from_f32(r: f32, g: f32, b: f32) -> Self { + Self::new( + (r.clamp(0.0, 1.0) * 255.0) as u8, + (g.clamp(0.0, 1.0) * 255.0) as u8, + (b.clamp(0.0, 1.0) * 255.0) as u8, + ) + } + + /// Creates a grayscale [Rgb] color + #[inline] + pub const fn gray(x: u8) -> Self { + Self::new(x, x, x) + } + + /// Creates a grayscale [Rgb] color with a [f32] value + pub fn gray_f32(x: f32) -> Self { + Self::from_f32(x, x, x) + } + + /// Creates a new [Rgb] color from a [HSL] color + // pub fn from_hsl(hsl: HSL) -> Self { + // if hsl.s == 0.0 { + // return Self::gray_f32(hsl.l); + // } + + // let q = if hsl.l < 0.5 { + // hsl.l * (1.0 + hsl.s) + // } else { + // hsl.l + hsl.s - hsl.l * hsl.s + // }; + // let p = 2.0 * hsl.l - q; + // let h2c = |t: f32| { + // let t = t.clamp(0.0, 1.0); + // if 6.0 * t < 1.0 { + // p + 6.0 * (q - p) * t + // } else if t < 0.5 { + // q + // } else if 1.0 < 1.5 * t { + // p + 6.0 * (q - p) * (1.0 / 1.5 - t) + // } else { + // p + // } + // }; + + // Self::from_f32(h2c(hsl.h + 1.0 / 3.0), h2c(hsl.h), h2c(hsl.h - 1.0 / 3.0)) + // } + + /// Computes the linear interpolation between `self` and `other` for `t` + pub fn lerp(&self, other: Self, t: f32) -> Self { + let t = t.clamp(0.0, 1.0); + self * (1.0 - t) + other * t + } +} + +impl From<(u8, u8, u8)> for Rgb { + fn from((r, g, b): (u8, u8, u8)) -> Self { + Self::new(r, g, b) + } +} + +impl From<(f32, f32, f32)> for Rgb { + fn from((r, g, b): (f32, f32, f32)) -> Self { + Self::from_f32(r, g, b) + } +} + +use crate::ANSIColorCode; +use crate::TargetGround; +impl ANSIColorCode for Rgb { + fn ansi_color_code(&self, target: TargetGround) -> String { + format!("{};2;{};{};{}", target.code() + 8, self.r, self.g, self.b) + } +} + +overload::overload!( + (lhs: ?Rgb) + (rhs: ?Rgb) -> Rgb { + Rgb::new( + lhs.r.saturating_add(rhs.r), + lhs.g.saturating_add(rhs.g), + lhs.b.saturating_add(rhs.b) + ) + } +); + +overload::overload!( + (lhs: ?Rgb) - (rhs: ?Rgb) -> Rgb { + Rgb::new( + lhs.r.saturating_sub(rhs.r), + lhs.g.saturating_sub(rhs.g), + lhs.b.saturating_sub(rhs.b) + ) + } +); + +overload::overload!( + (lhs: ?Rgb) * (rhs: ?f32) -> Rgb { + Rgb::new( + (lhs.r as f32 * rhs.clamp(0.0, 1.0)) as u8, + (lhs.g as f32 * rhs.clamp(0.0, 1.0)) as u8, + (lhs.b as f32 * rhs.clamp(0.0, 1.0)) as u8 + ) + } +); + +overload::overload!( + (lhs: ?f32) * (rhs: ?Rgb) -> Rgb { + Rgb::new( + (rhs.r as f32 * lhs.clamp(0.0, 1.0)) as u8, + (rhs.g as f32 * lhs.clamp(0.0, 1.0)) as u8, + (rhs.b as f32 * lhs.clamp(0.0, 1.0)) as u8 + ) + } +); + +overload::overload!( + -(rgb: ?Rgb) -> Rgb { + Rgb::new( + 255 - rgb.r, + 255 - rgb.g, + 255 - rgb.b) + } +); diff --git a/vendor/nu-ansi-term/src/style.rs b/vendor/nu-ansi-term/src/style.rs new file mode 100644 index 000000000..3d47a79f7 --- /dev/null +++ b/vendor/nu-ansi-term/src/style.rs @@ -0,0 +1,629 @@ +/// A style is a collection of properties that can format a string +/// using ANSI escape codes. +/// +/// # Examples +/// +/// ``` +/// use nu_ansi_term::{Style, Color}; +/// +/// let style = Style::new().bold().on(Color::Black); +/// println!("{}", style.paint("Bold on black")); +/// ``` +#[derive(PartialEq, Clone, Copy)] +#[cfg_attr( + feature = "derive_serde_style", + derive(serde::Deserialize, serde::Serialize) +)] +pub struct Style { + /// The style's foreground color, if it has one. + pub foreground: Option<Color>, + + /// The style's background color, if it has one. + pub background: Option<Color>, + + /// Whether this style is bold. + pub is_bold: bool, + + /// Whether this style is dimmed. + pub is_dimmed: bool, + + /// Whether this style is italic. + pub is_italic: bool, + + /// Whether this style is underlined. + pub is_underline: bool, + + /// Whether this style is blinking. + pub is_blink: bool, + + /// Whether this style has reverse colors. + pub is_reverse: bool, + + /// Whether this style is hidden. + pub is_hidden: bool, + + /// Whether this style is struckthrough. + pub is_strikethrough: bool, +} + +impl Style { + /// Creates a new Style with no properties set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new(); + /// println!("{}", style.paint("hi")); + /// ``` + pub fn new() -> Style { + Style::default() + } + + /// Returns a `Style` with the bold property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().bold(); + /// println!("{}", style.paint("hey")); + /// ``` + pub fn bold(&self) -> Style { + Style { + is_bold: true, + ..*self + } + } + + /// Returns a `Style` with the dimmed property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().dimmed(); + /// println!("{}", style.paint("sup")); + /// ``` + pub fn dimmed(&self) -> Style { + Style { + is_dimmed: true, + ..*self + } + } + + /// Returns a `Style` with the italic property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().italic(); + /// println!("{}", style.paint("greetings")); + /// ``` + pub fn italic(&self) -> Style { + Style { + is_italic: true, + ..*self + } + } + + /// Returns a `Style` with the underline property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().underline(); + /// println!("{}", style.paint("salutations")); + /// ``` + pub fn underline(&self) -> Style { + Style { + is_underline: true, + ..*self + } + } + + /// Returns a `Style` with the blink property set. + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().blink(); + /// println!("{}", style.paint("wazzup")); + /// ``` + pub fn blink(&self) -> Style { + Style { + is_blink: true, + ..*self + } + } + + /// Returns a `Style` with the reverse property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().reverse(); + /// println!("{}", style.paint("aloha")); + /// ``` + pub fn reverse(&self) -> Style { + Style { + is_reverse: true, + ..*self + } + } + + /// Returns a `Style` with the hidden property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().hidden(); + /// println!("{}", style.paint("ahoy")); + /// ``` + pub fn hidden(&self) -> Style { + Style { + is_hidden: true, + ..*self + } + } + + /// Returns a `Style` with the strikethrough property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().strikethrough(); + /// println!("{}", style.paint("yo")); + /// ``` + pub fn strikethrough(&self) -> Style { + Style { + is_strikethrough: true, + ..*self + } + } + + /// Returns a `Style` with the foreground color property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::{Style, Color}; + /// + /// let style = Style::new().fg(Color::Yellow); + /// println!("{}", style.paint("hi")); + /// ``` + pub fn fg(&self, foreground: Color) -> Style { + Style { + foreground: Some(foreground), + ..*self + } + } + + /// Returns a `Style` with the background color property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::{Style, Color}; + /// + /// let style = Style::new().on(Color::Blue); + /// println!("{}", style.paint("eyyyy")); + /// ``` + pub fn on(&self, background: Color) -> Style { + Style { + background: Some(background), + ..*self + } + } + + /// Return true if this `Style` has no actual styles, and can be written + /// without any control characters. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// assert_eq!(true, Style::default().is_plain()); + /// assert_eq!(false, Style::default().bold().is_plain()); + /// ``` + pub fn is_plain(self) -> bool { + self == Style::default() + } +} + +impl Default for Style { + /// Returns a style with *no* properties set. Formatting text using this + /// style returns the exact same text. + /// + /// ``` + /// use nu_ansi_term::Style; + /// assert_eq!(None, Style::default().foreground); + /// assert_eq!(None, Style::default().background); + /// assert_eq!(false, Style::default().is_bold); + /// assert_eq!("txt", Style::default().paint("txt").to_string()); + /// ``` + fn default() -> Style { + Style { + foreground: None, + background: None, + is_bold: false, + is_dimmed: false, + is_italic: false, + is_underline: false, + is_blink: false, + is_reverse: false, + is_hidden: false, + is_strikethrough: false, + } + } +} + +// ---- colors ---- + +/// A color is one specific type of ANSI escape code, and can refer +/// to either the foreground or background color. +/// +/// These use the standard numeric sequences. +/// See <http://invisible-island.net/xterm/ctlseqs/ctlseqs.html> +#[derive(PartialEq, Clone, Copy, Debug)] +#[cfg_attr( + feature = "derive_serde_style", + derive(serde::Deserialize, serde::Serialize) +)] +pub enum Color { + /// Color #0 (foreground code `30`, background code `40`). + /// + /// This is not necessarily the background color, and using it as one may + /// render the text hard to read on terminals with dark backgrounds. + Black, + + /// Color #0 (foreground code `90`, background code `100`). + DarkGray, + + /// Color #1 (foreground code `31`, background code `41`). + Red, + + /// Color #1 (foreground code `91`, background code `101`). + LightRed, + + /// Color #2 (foreground code `32`, background code `42`). + Green, + + /// Color #2 (foreground code `92`, background code `102`). + LightGreen, + + /// Color #3 (foreground code `33`, background code `43`). + Yellow, + + /// Color #3 (foreground code `93`, background code `103`). + LightYellow, + + /// Color #4 (foreground code `34`, background code `44`). + Blue, + + /// Color #4 (foreground code `94`, background code `104`). + LightBlue, + + /// Color #5 (foreground code `35`, background code `45`). + Purple, + + /// Color #5 (foreground code `95`, background code `105`). + LightPurple, + + /// Color #5 (foreground code `35`, background code `45`). + Magenta, + + /// Color #5 (foreground code `95`, background code `105`). + LightMagenta, + + /// Color #6 (foreground code `36`, background code `46`). + Cyan, + + /// Color #6 (foreground code `96`, background code `106`). + LightCyan, + + /// Color #7 (foreground code `37`, background code `47`). + /// + /// As above, this is not necessarily the foreground color, and may be + /// hard to read on terminals with light backgrounds. + White, + + /// Color #7 (foreground code `97`, background code `107`). + LightGray, + + /// A color number from 0 to 255, for use in 256-color terminal + /// environments. + /// + /// - colors 0 to 7 are the `Black` to `White` variants respectively. + /// These colors can usually be changed in the terminal emulator. + /// - colors 8 to 15 are brighter versions of the eight colors above. + /// These can also usually be changed in the terminal emulator, or it + /// could be configured to use the original colors and show the text in + /// bold instead. It varies depending on the program. + /// - colors 16 to 231 contain several palettes of bright colors, + /// arranged in six squares measuring six by six each. + /// - colors 232 to 255 are shades of grey from black to white. + /// + /// It might make more sense to look at a [color chart][cc]. + /// + /// [cc]: https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg + Fixed(u8), + + /// A 24-bit Rgb color, as specified by ISO-8613-3. + Rgb(u8, u8, u8), + + /// The default color (foreground code `39`, background codr `49`). + Default, +} + +impl Default for Color { + fn default() -> Self { + Color::White + } +} + +impl Color { + /// Returns a `Style` with the foreground color set to this color. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Red.normal(); + /// println!("{}", style.paint("hi")); + /// ``` + pub fn normal(self) -> Style { + Style { + foreground: Some(self), + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// bold property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Green.bold(); + /// println!("{}", style.paint("hey")); + /// ``` + pub fn bold(self) -> Style { + Style { + foreground: Some(self), + is_bold: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// dimmed property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Yellow.dimmed(); + /// println!("{}", style.paint("sup")); + /// ``` + pub fn dimmed(self) -> Style { + Style { + foreground: Some(self), + is_dimmed: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// italic property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Blue.italic(); + /// println!("{}", style.paint("greetings")); + /// ``` + pub fn italic(self) -> Style { + Style { + foreground: Some(self), + is_italic: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// underline property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Purple.underline(); + /// println!("{}", style.paint("salutations")); + /// ``` + pub fn underline(self) -> Style { + Style { + foreground: Some(self), + is_underline: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// blink property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Cyan.blink(); + /// println!("{}", style.paint("wazzup")); + /// ``` + pub fn blink(self) -> Style { + Style { + foreground: Some(self), + is_blink: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// reverse property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Black.reverse(); + /// println!("{}", style.paint("aloha")); + /// ``` + pub fn reverse(self) -> Style { + Style { + foreground: Some(self), + is_reverse: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// hidden property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::White.hidden(); + /// println!("{}", style.paint("ahoy")); + /// ``` + pub fn hidden(self) -> Style { + Style { + foreground: Some(self), + is_hidden: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// strikethrough property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Fixed(244).strikethrough(); + /// println!("{}", style.paint("yo")); + /// ``` + pub fn strikethrough(self) -> Style { + Style { + foreground: Some(self), + is_strikethrough: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// background color property set to the given color. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Rgb(31, 31, 31).on(Color::White); + /// println!("{}", style.paint("eyyyy")); + /// ``` + pub fn on(self, background: Color) -> Style { + Style { + foreground: Some(self), + background: Some(background), + ..Style::default() + } + } +} + +impl From<Color> for Style { + /// You can turn a `Color` into a `Style` with the foreground color set + /// with the `From` trait. + /// + /// ``` + /// use nu_ansi_term::{Style, Color}; + /// let green_foreground = Style::default().fg(Color::Green); + /// assert_eq!(green_foreground, Color::Green.normal()); + /// assert_eq!(green_foreground, Color::Green.into()); + /// assert_eq!(green_foreground, Style::from(Color::Green)); + /// ``` + fn from(color: Color) -> Style { + color.normal() + } +} + +#[cfg(test)] +#[cfg(feature = "derive_serde_style")] +mod serde_json_tests { + use super::{Color, Style}; + + #[test] + fn color_serialization() { + let colors = &[ + Color::Red, + Color::Blue, + Color::Rgb(123, 123, 123), + Color::Fixed(255), + ]; + + assert_eq!( + serde_json::to_string(&colors).unwrap(), + String::from("[\"Red\",\"Blue\",{\"Rgb\":[123,123,123]},{\"Fixed\":255}]") + ); + } + + #[test] + fn color_deserialization() { + let colors = [ + Color::Red, + Color::Blue, + Color::Rgb(123, 123, 123), + Color::Fixed(255), + ]; + + for color in colors { + let serialized = serde_json::to_string(&color).unwrap(); + let deserialized: Color = serde_json::from_str(&serialized).unwrap(); + + assert_eq!(color, deserialized); + } + } + + #[test] + fn style_serialization() { + let style = Style::default(); + + assert_eq!(serde_json::to_string(&style).unwrap(), "{\"foreground\":null,\"background\":null,\"is_bold\":false,\"is_dimmed\":false,\"is_italic\":false,\"is_underline\":false,\"is_blink\":false,\"is_reverse\":false,\"is_hidden\":false,\"is_strikethrough\":false}".to_string()); + } +} diff --git a/vendor/nu-ansi-term/src/util.rs b/vendor/nu-ansi-term/src/util.rs new file mode 100644 index 000000000..a35020137 --- /dev/null +++ b/vendor/nu-ansi-term/src/util.rs @@ -0,0 +1,79 @@ +use crate::display::{AnsiString, AnsiStrings}; +use std::ops::Deref; + +/// Return a substring of the given AnsiStrings sequence, while keeping the formatting. +pub fn sub_string<'a>( + start: usize, + len: usize, + strs: &AnsiStrings<'a>, +) -> Vec<AnsiString<'static>> { + let mut vec = Vec::new(); + let mut pos = start; + let mut len_rem = len; + + for i in strs.0.iter() { + let frag_len = i.string.len(); + if pos >= frag_len { + pos -= frag_len; + continue; + } + if len_rem == 0 { + break; + } + + let end = pos + len_rem; + let pos_end = if end >= frag_len { frag_len } else { end }; + + vec.push(i.style_ref().paint(String::from(&i.string[pos..pos_end]))); + + if end <= frag_len { + break; + } + + len_rem -= pos_end - pos; + pos = 0; + } + + vec +} + +/// Return a concatenated copy of `strs` without the formatting, as an allocated `String`. +pub fn unstyle(strs: &AnsiStrings) -> String { + let mut s = String::new(); + + for i in strs.0.iter() { + s += i.string.deref(); + } + + s +} + +/// Return the unstyled length of AnsiStrings. This is equaivalent to `unstyle(strs).len()`. +pub fn unstyled_len(strs: &AnsiStrings) -> usize { + let mut l = 0; + for i in strs.0.iter() { + l += i.string.len(); + } + l +} + +#[cfg(test)] +mod test { + use super::*; + use crate::Color::*; + + #[test] + fn test() { + let l = [ + Black.paint("first"), + Red.paint("-second"), + White.paint("-third"), + ]; + let a = AnsiStrings(&l); + assert_eq!(unstyle(&a), "first-second-third"); + assert_eq!(unstyled_len(&a), 18); + + let l2 = [Black.paint("st"), Red.paint("-second"), White.paint("-t")]; + assert_eq!(sub_string(3, 11, &a), l2); + } +} diff --git a/vendor/nu-ansi-term/src/windows.rs b/vendor/nu-ansi-term/src/windows.rs new file mode 100644 index 000000000..828e35573 --- /dev/null +++ b/vendor/nu-ansi-term/src/windows.rs @@ -0,0 +1,62 @@ +/// Enables ANSI code support on Windows 10. +/// +/// This uses Windows API calls to alter the properties of the console that +/// the program is running in. +/// +/// https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx +/// +/// Returns a `Result` with the Windows error code if unsuccessful. +#[cfg(windows)] +pub fn enable_ansi_support() -> Result<(), u32> { + // ref: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#EXAMPLE_OF_ENABLING_VIRTUAL_TERMINAL_PROCESSING @@ https://archive.is/L7wRJ#76% + + use std::ffi::OsStr; + use std::iter::once; + use std::os::windows::ffi::OsStrExt; + use std::ptr::null_mut; + use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode}; + use winapi::um::errhandlingapi::GetLastError; + use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING}; + use winapi::um::handleapi::INVALID_HANDLE_VALUE; + use winapi::um::winnt::{FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE}; + + const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004; + + unsafe { + // ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew + // Using `CreateFileW("CONOUT$", ...)` to retrieve the console handle works correctly even if STDOUT and/or STDERR are redirected + let console_out_name: Vec<u16> = + OsStr::new("CONOUT$").encode_wide().chain(once(0)).collect(); + let console_handle = CreateFileW( + console_out_name.as_ptr(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, + null_mut(), + OPEN_EXISTING, + 0, + null_mut(), + ); + if console_handle == INVALID_HANDLE_VALUE { + return Err(GetLastError()); + } + + // ref: https://docs.microsoft.com/en-us/windows/console/getconsolemode + let mut console_mode: u32 = 0; + if 0 == GetConsoleMode(console_handle, &mut console_mode) { + return Err(GetLastError()); + } + + // VT processing not already enabled? + if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 { + // https://docs.microsoft.com/en-us/windows/console/setconsolemode + if 0 == SetConsoleMode( + console_handle, + console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING, + ) { + return Err(GetLastError()); + } + } + } + + Ok(()) +} diff --git a/vendor/nu-ansi-term/src/write.rs b/vendor/nu-ansi-term/src/write.rs new file mode 100644 index 000000000..552771918 --- /dev/null +++ b/vendor/nu-ansi-term/src/write.rs @@ -0,0 +1,37 @@ +use std::fmt; +use std::io; + +pub trait AnyWrite { + type Wstr: ?Sized; + type Error; + + fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Self::Error>; + + fn write_str(&mut self, s: &Self::Wstr) -> Result<(), Self::Error>; +} + +impl<'a> AnyWrite for dyn fmt::Write + 'a { + type Wstr = str; + type Error = fmt::Error; + + fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Self::Error> { + fmt::Write::write_fmt(self, fmt) + } + + fn write_str(&mut self, s: &Self::Wstr) -> Result<(), Self::Error> { + fmt::Write::write_str(self, s) + } +} + +impl<'a> AnyWrite for dyn io::Write + 'a { + type Wstr = [u8]; + type Error = io::Error; + + fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Self::Error> { + io::Write::write_fmt(self, fmt) + } + + fn write_str(&mut self, s: &Self::Wstr) -> Result<(), Self::Error> { + io::Write::write_all(self, s) + } +} |