diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:32 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:32 +0000 |
commit | 4547b622d8d29df964fa2914213088b148c498fc (patch) | |
tree | 9fc6b25f3c3add6b745be9a2400a6e96140046e9 /vendor/yansi/src | |
parent | Releasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz rustc-4547b622d8d29df964fa2914213088b148c498fc.zip |
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/yansi/src')
-rw-r--r-- | vendor/yansi/src/color.rs | 96 | ||||
-rw-r--r-- | vendor/yansi/src/lib.rs | 214 | ||||
-rw-r--r-- | vendor/yansi/src/macros.rs | 19 | ||||
-rw-r--r-- | vendor/yansi/src/paint.rs | 463 | ||||
-rw-r--r-- | vendor/yansi/src/style.rs | 480 | ||||
-rw-r--r-- | vendor/yansi/src/tests.rs | 182 | ||||
-rw-r--r-- | vendor/yansi/src/windows.rs | 69 |
7 files changed, 1523 insertions, 0 deletions
diff --git a/vendor/yansi/src/color.rs b/vendor/yansi/src/color.rs new file mode 100644 index 000000000..fee620a1d --- /dev/null +++ b/vendor/yansi/src/color.rs @@ -0,0 +1,96 @@ +use std::fmt; + +use {Paint, Style}; + +/// An enum representing an ANSI color code. +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)] +pub enum Color { + /// No color has been set. Nothing is changed when applied. + Unset, + + /// Terminal default #9. (foreground code `39`, background code `49`). + Default, + + /// Black #0 (foreground code `30`, background code `40`). + Black, + + /// Red: #1 (foreground code `31`, background code `41`). + Red, + + /// Green: #2 (foreground code `32`, background code `42`). + Green, + + /// Yellow: #3 (foreground code `33`, background code `43`). + Yellow, + + /// Blue: #4 (foreground code `34`, background code `44`). + Blue, + + /// Magenta: #5 (foreground code `35`, background code `45`). + Magenta, + + /// Cyan: #6 (foreground code `36`, background code `46`). + Cyan, + + /// White: #7 (foreground code `37`, background code `47`). + White, + + /// A color number from 0 to 255, for use in 256-color terminals. + Fixed(u8), + + /// A 24-bit RGB color, as specified by ISO-8613-3. + RGB(u8, u8, u8), +} + +impl Color { + /// Constructs a new `Paint` structure that encapsulates `item` with the + /// foreground color set to the color `self`. + /// + /// ```rust + /// use yansi::Color::Blue; + /// + /// println!("This is going to be blue: {}", Blue.paint("yay!")); + /// ``` + #[inline] + pub fn paint<T>(self, item: T) -> Paint<T> { + Paint::new(item).fg(self) + } + + /// Constructs a new `Style` structure with the foreground color set to the + /// color `self`. + /// + /// ```rust + /// use yansi::Color::Green; + /// + /// let success = Green.style().bold(); + /// println!("Hey! {}", success.paint("Success!")); + /// ``` + #[inline] + pub fn style(self) -> Style { + Style::new(self) + } + + pub(crate) fn ascii_fmt(&self, f: &mut fmt::Write) -> fmt::Result { + match *self { + Color::Unset => Ok(()), + Color::Default => write!(f, "9"), + Color::Black => write!(f, "0"), + Color::Red => write!(f, "1"), + Color::Green => write!(f, "2"), + Color::Yellow => write!(f, "3"), + Color::Blue => write!(f, "4"), + Color::Magenta => write!(f, "5"), + Color::Cyan => write!(f, "6"), + Color::White => write!(f, "7"), + Color::Fixed(num) => write!(f, "8;5;{}", num), + Color::RGB(r, g, b) => write!(f, "8;2;{};{};{}", r, g, b), + } + } +} + +impl Default for Color { + #[inline(always)] + fn default() -> Self { + Color::Unset + } +} diff --git a/vendor/yansi/src/lib.rs b/vendor/yansi/src/lib.rs new file mode 100644 index 000000000..8fccd804c --- /dev/null +++ b/vendor/yansi/src/lib.rs @@ -0,0 +1,214 @@ +#![doc(html_root_url = "https://docs.rs/yansi/0.6.0-dev")] + +//! A dead simple ANSI terminal color painting library. +//! +//! # Usage +//! +//! Usage is best illustrated via a quick example: +//! +//! ```rust +//! use yansi::{Paint, Color}; +//! +//! println!("Testing, {}, {}, {}!", +//! Paint::red(1), +//! Paint::green(2).bold().underline(), +//! Paint::blue("3").bg(Color::White).italic()); +//! ``` +//! +//! ## Paint +//! +//! The main entry point into this library is the [`Paint`] type. `Paint` +//! encapsulates a value of any type that implements the [`Display`] or +//! [`Debug`] trait. When a `Paint` is `Display`ed or `Debug`ed, the appropriate +//! ANSI escape characters are emitted before and after the wrapped type's `fmt` +//! implementation. +//! +//! `Paint` can be constructed via [a myriad of methods]. In addition to these +//! constructors, you can also use the [`color.paint()`](Color::paint()) method +//! on a given [`Color`] value to construct a `Paint` type. Both of these +//! approaches are shown below: +//! +//! ```rust +//! use yansi::Paint; +//! use yansi::Color::Red; +//! +//! println!("I'm {}!", Paint::red("red").bold()); +//! println!("I'm also {}!", Red.paint("red").bold()); +//! ``` +//! [`Display`]: ::std::fmt::Display +//! [`Debug`]: ::std::fmt::Debug +//! [a myriad of methods]: struct.Paint.html#unstyled-constructors +//! +//! ## Styling +//! +//! Modifications to the styling of an item can be made via [a number of +//! chainable methods] on `Paint`. +//! +//! ```rust +//! use yansi::Paint; +//! +//! Paint::new("hi").underline().invert().italic().dimmed().bold(); +//! ``` +//! +//! Styling can also be created independently from a `Paint` structure via the +//! [`Style`] structure. This allows common styling to be stored and reused. A +//! `Style` can be applied via the [`style.paint()`] method or the +//! [`paint.with_style()`] method: +//! +//! ```rust +//! use yansi::{Paint, Color, Style}; +//! +//! // A bold, itatlic style with red foreground. +//! let alert = Style::new(Color::Red).bold().italic(); +//! +//! // Using `style.paint()`; this is preferred. +//! println!("Alert! {}", alert.paint("This is serious business!")); +//! println!("Hi! {}", alert.underline().paint("Super serious!")); +//! +//! // Using `paint.with_style()`. +//! println!("Alert! {}", Paint::new("Yet another.").with_style(alert)); +//! ``` +//! +//! [a number of chainable methods]: struct.Paint.html#setters +//! [`style.paint()`]: Style::paint() +//! [`paint.with_style()`]: Paint::with_style() +//! +//! # Disabling +//! +//! Painting can be disabled globally via the [`Paint::disable()`] method. When +//! painting is disabled, the `Display` and `Debug` implementations for `Paint` +//! will emit the `Display` or `Debug` of the contained object and nothing else. +//! Painting can be reenabled via the [`Paint::enable()`] method. +//! +//! One potential use of this feature is to allow users to control color ouput +//! via an environment variable. For instance, to disable coloring if the +//! `CLICOLOR` variable is set to `0`, you might write: +//! +//! ```rust +//! # { if false { // we don't actually want to disable coloring +//! use yansi::Paint; +//! +//! if let Ok(true) = std::env::var("CLICOLOR").map(|v| v == "0") { +//! Paint::disable(); +//! } +//! # } } +//! ``` +//! +//! ## Masking +//! +//! Items can be arbitrarily _masked_. When an item is masked and painting is +//! disabled, the `Display` and `Debug` implementations of `Paint` write +//! nothing. This allows you to selectively omit output when painting is +//! disabled. Values can be masked using the [`Paint::masked()`] constructor +//! or [`paint.mask()`] and [`style.mask()`] style setters. +//! +//! [`paint.mask()`]: Paint::mask() +//! [`style.mask()`]: Style::mask() +//! +//! One use for this feature is to print certain characters only when painting +//! is enabled. For instance, you might wish to emit the 🎨 emoji when +//! coloring is enabled but not otherwise. This can be accomplished by masking +//! the emoji: +//! +//! ```rust +//! use yansi::Paint; +//! +//! println!("I like colors!{}", Paint::masked(" 🎨")); +//! ``` +//! +//! This will print "I like colors! 🎨" when painting is enabled and "I like +//! colors!" when painting is disabled. +//! +//! ## Wrapping +//! +//! Styling can be set to _wrap_ existing styles using either the +//! [`Paint::wrapping()`] constructor or the [`paint.wrap()`] and +//! [`style.wrap()`] style setters. When a style is _wrapping_, all color +//! resets written out by the internal item's `Display` or `Debug` +//! implementation are set to the styling of the wrapping style itself. In other +//! words, the "default" style of the wrapped item is modified to be the +//! wrapping style. This allows for easy wrapping of other colored text. Without +//! this feature, the console would reset styling to the terminal's default +//! style instead of the wrapping style. +//! +//! [`paint.wrap()`]: Paint::wrap() +//! [`style.wrap()`]: Style::wrap() +//! +//! One use for this feature is to ensure that styling is consistently set +//! across items that may already be styled, such as when logging. +//! +//! ```rust +//! use yansi::{Paint, Color}; +//! +//! let inner = format!("{} and {}", Paint::red("Stop"), Paint::green("Go")); +//! println!("Hey! {}", Paint::wrapping(inner).fg(Color::Blue)); +//! ``` +//! +//! This will print 'Hey!' unstyled, "Stop" in red, "and" in blue, and "Go" in +//! green. Without wrapping, "and" would be unstyled as `Paint::red()` resets +//! the style after printing the internal item. +//! +//! # Windows +//! +//! Coloring is supported on Windows beginning with the Windows 10 anniversary +//! update. Since this update, Windows consoles support ANSI escape sequences. +//! This support, however, must be explicitly enabled. `yansi` provides the +//! [`Paint::enable_windows_ascii()`] method to enable ASCII support on Windows +//! consoles when available. +//! +//! ```rust +//! use yansi::Paint; +//! +//! // Enable ASCII escape sequence support on Windows consoles. +//! Paint::enable_windows_ascii(); +//! ``` +//! +//! You may wish to disable coloring on unsupported Windows consoles to avoid +//! emitting unrecognized ASCII escape sequences: +//! +//! ```rust +//! use yansi::Paint; +//! +//! if cfg!(windows) && !Paint::enable_windows_ascii() { +//! Paint::disable(); +//! } +//! ``` +//! +//! [`Paint::enable_windows_ascii()`]: Paint::enable_windows_ascii() +//! +//! # Why? +//! +//! Several terminal coloring libraries exist ([`ansi_term`], [`colored`], +//! [`term_painter`], to name a few), begging the question: why yet another? +//! Here are a few reasons: +//! +//! * This library is _much_ simpler: there are three types! +//! * Unlike [`ansi_term`] or [`colored`], _any_ type implementing `Display` +//! or `Debug` can be stylized, not only strings. +//! * Styling can be enabled and disabled globally, on the fly. +//! * Arbitrary items can be [_masked_] for selective disabling. +//! * Styling can [_wrap_] any arbitrarily styled item. +//! * Typically only one type needs to be imported: [`Paint`]. +//! * Zero dependencies. It really is simple. +//! * The name `yansi` is pretty short. +//! +//! All that being said, this library borrows API ideas from the three libraries +//! as well as implementation details from [`ansi_term`]. +//! +//! [`ansi_term`]: https://crates.io/crates/ansi_term +//! [`colored`]: https://crates.io/crates/colored +//! [`term_painter`]: https://crates.io/crates/term-painter +//! [_masked_]: #masking +//! [_wrap_]: #wrapping + +#[macro_use] mod macros; + +#[cfg(test)] mod tests; +mod windows; +mod paint; +mod style; +mod color; + +pub use color::Color; +pub use style::Style; +pub use paint::Paint; diff --git a/vendor/yansi/src/macros.rs b/vendor/yansi/src/macros.rs new file mode 100644 index 000000000..b7c0b0339 --- /dev/null +++ b/vendor/yansi/src/macros.rs @@ -0,0 +1,19 @@ +macro_rules! style_builder_for { + ($T:ty, |$s:ident| $props:expr, $($name:ident: $property:ident),*) => ($( + #[doc = concat!( + "Enables the _", stringify!($name), "_ style on `self`.\n", + "```rust\n", + "use yansi::Paint;\n", + "\n", + "println!(\"Using ", stringify!($name), ": {}\", ", + "Paint::new(\"hi\").", stringify!($name), "());\n", + "```\n" + )] + #[inline] + pub fn $name(self) -> $T { + let mut $s = self; + $props.set(Property::$property); + $s + } + )*) +} diff --git a/vendor/yansi/src/paint.rs b/vendor/yansi/src/paint.rs new file mode 100644 index 000000000..9ead595cd --- /dev/null +++ b/vendor/yansi/src/paint.rs @@ -0,0 +1,463 @@ +use std::fmt; + +use style::{Style, Property}; +use color::Color; + +/// A structure encapsulating an item and styling. +/// +/// See the [crate level documentation](./) for usage information. +/// +/// # Method Glossary +/// +/// The `Paint` structure exposes many methods for convenience. +/// +/// ### Unstyled Constructors +/// +/// Return a new `Paint` structure with no or default styling applied. +/// +/// * [`Paint::new(item: T)`](Paint::new()) +/// * [`Paint::default(item: T)`](Paint::default()) +/// * [`Paint::masked(item: T)`](Paint::masked()) +/// * [`Paint::wrapping(item: T)`](Paint::wrapping()) +/// +/// ### Foreground Color Constructors +/// +/// Return a new `Paint` structure with a foreground color applied. +/// +/// * [`Paint::rgb(r: u8, g: u8, b: u8, item: T)`](Paint::rgb()) +/// * [`Paint::fixed(color: u8, item: T)`](Paint::fixed()) +/// * [`Paint::black(item: T)`](Paint::black()) +/// * [`Paint::red(item: T)`](Paint::red()) +/// * [`Paint::green(item: T)`](Paint::green()) +/// * [`Paint::yellow(item: T)`](Paint::yellow()) +/// * [`Paint::blue(item: T)`](Paint::blue()) +/// * [`Paint::magenta(item: T)`](Paint::magenta()) +/// * [`Paint::cyan(item: T)`](Paint::cyan()) +/// * [`Paint::white(item: T)`](Paint::white()) +/// +/// ### Getters +/// +/// Return information about the `Paint` structure. +/// +/// * [`paint.style()`](Paint::style()) +/// * [`paint.inner()`](Paint::inner()) +/// +/// ### Setters +/// +/// Set a style property on a given `Paint` structure. +/// +/// * [`paint.with_style(style: Style)`](Paint::with_style()) +/// * [`paint.mask()`](Paint::mask()) +/// * [`paint.wrap()`](Paint::wrap()) +/// * [`paint.fg(color: Color)`](Paint::fg()) +/// * [`paint.bg(color: Color)`](Paint::bg()) +/// * [`paint.bold()`](Paint::bold()) +/// * [`paint.dimmed()`](Paint::dimmed()) +/// * [`paint.italic()`](Paint::italic()) +/// * [`paint.underline()`](Paint::underline()) +/// * [`paint.blink()`](Paint::blink()) +/// * [`paint.invert()`](Paint::invert()) +/// * [`paint.hidden()`](Paint::hidden()) +/// * [`paint.strikethrough()`](Paint::strikethrough()) +/// +/// These methods can be chained: +/// +/// ```rust +/// use yansi::Paint; +/// +/// Paint::new("hi").underline().invert().italic().dimmed().bold(); +/// ``` +/// +/// ### Global Methods +/// +/// Modify or observe the global behavior of painting. +/// +/// * [`Paint::enable()`](Paint::enable()) +/// * [`Paint::disable()`](Paint::disable()) +/// * [`Paint::is_enabled()`](Paint::is_enabled()) +/// * [`Paint::enable_windows_ascii()`](Paint::enable_windows_ascii()) +#[derive(Default, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)] +pub struct Paint<T> { + item: T, + style: Style, +} + +macro_rules! constructors_for { + ($T:ty, $($name:ident: $color:ident),*) => ($( + #[doc = concat!( + "Constructs a new `Paint` structure encapsulating `item` with the foreground color\n", + "set to ", stringify!($name), ".\n", + "```rust\n", + "use yansi::Paint;\n", + "\n", + "println!(\"This is going to be ", stringify!($name), + ": {}\", Paint::", stringify!($name), "(\"yay!\"));\n", + "```\n" + )] + #[inline] + pub fn $name(item: $T) -> Paint<$T> { + Paint::new(item).fg(Color::$color) + } + )*) +} + +impl<T> Paint<T> { + /// Constructs a new `Paint` structure encapsulating `item` with no set + /// styling. + /// + /// ```rust + /// use yansi::Paint; + /// + /// assert_eq!(Paint::new("hello!").to_string(), "hello!".to_string()); + /// ``` + #[inline] + pub fn new(item: T) -> Paint<T> { + Paint { item, style: Style::default() } + } + + /// Constructs a new `Paint` structure encapsulating `item` with the active + /// terminal's default foreground and background. + /// + /// ```rust + /// use yansi::Paint; + /// + /// println!("This is going to use {}!", Paint::default("default colors")); + /// ``` + #[inline] + pub fn default(item: T) -> Paint<T> { + Paint::new(item).fg(Color::Default).bg(Color::Default) + } + + /// Constructs a new _masked_ `Paint` structure encapsulating `item` with + /// no set styling. + /// + /// A masked `Paint` is not written out when painting is disabled during + /// `Display` or `Debug` invocations. When painting is enabled, masking has + /// no effect. + /// + /// ```rust + /// use yansi::Paint; + /// + /// // The emoji won't be printed when coloring is disabled. + /// println!("{}Sprout!", Paint::masked("🌱 ")); + /// ``` + #[inline] + pub fn masked(item: T) -> Paint<T> { + Paint::new(item).mask() + } + + /// Constructs a new _wrapping_ `Paint` structure encapsulating `item` with + /// default styling. + /// + /// A wrapping `Paint` converts all color resets written out by the internal + /// value to the styling of itself. This allows for seamless color wrapping + /// of other colored text. + /// + /// # Performance + /// + /// In order to wrap an internal value, the internal value must first be + /// written out to a local buffer and examined. As a result, displaying a + /// wrapped value is likely to result in a heap allocation and copy. + /// + /// # Example + /// + /// ```rust + /// use yansi::{Paint, Color}; + /// + /// let inner = format!("{} and {}", Paint::red("Stop"), Paint::green("Go")); + /// + /// // 'Hey!' will be unstyled, "Stop" will be red, "and" will be blue, and + /// // "Go" will be green. Without a wrapping `Paint`, "and" would be + /// // unstyled. + /// println!("Hey! {}", Paint::wrapping(inner).fg(Color::Blue)); + /// ``` + #[inline] + pub fn wrapping(item: T) -> Paint<T> { + Paint::new(item).wrap() + } + + /// Constructs a new `Paint` structure encapsulating `item` with the + /// foreground color set to the RGB color `r`, `g`, `b`. + /// + /// ```rust + /// use yansi::Paint; + /// + /// println!("This is going to be funky: {}", Paint::rgb(70, 130, 122, "hi!")); + /// ``` + #[inline] + pub fn rgb(r: u8, g: u8, b: u8, item: T) -> Paint<T> { + Paint::new(item).fg(Color::RGB(r, g, b)) + } + + /// Constructs a new `Paint` structure encapsulating `item` with the + /// foreground color set to the fixed 8-bit color `color`. + /// + /// ```rust + /// use yansi::Paint; + /// + /// println!("This is going to be funky: {}", Paint::fixed(100, "hi!")); + /// ``` + #[inline] + pub fn fixed(color: u8, item: T) -> Paint<T> { + Paint::new(item).fg(Color::Fixed(color)) + } + + constructors_for!(T, black: Black, red: Red, green: Green, yellow: Yellow, + blue: Blue, magenta: Magenta, cyan: Cyan, white: White); + + /// Retrieves the style currently set on `self`. + /// + /// ```rust + /// use yansi::{Style, Color, Paint}; + /// + /// let alert = Style::new(Color::Red).bold().underline(); + /// let painted = Paint::red("hi").bold().underline(); + /// + /// assert_eq!(alert, painted.style()); + /// ``` + #[inline] + pub fn style(&self) -> Style { + self.style + } + + /// Retrieves a borrow to the inner item. + /// + /// ```rust + /// use yansi::Paint; + /// + /// let x = Paint::red("Hello, world!"); + /// assert_eq!(*x.inner(), "Hello, world!"); + /// ``` + #[inline] + pub fn inner(&self) -> &T { + &self.item + } + + /// Sets the style of `self` to `style`. + /// + /// Any styling currently set on `self` is lost. Prefer to use the + /// [`style.paint()`](Style::paint()) method to create a `Paint` struct from + /// `Style`. + /// + /// ```rust + /// use yansi::{Paint, Color, Style}; + /// + /// let s = Style::new(Color::Red).bold().underline(); + /// + /// // Using this method. + /// println!("Alert: {}", Paint::new("This thing happened!").with_style(s)); + /// + /// // Using the `style.paint()` method. + /// println!("Alert: {}", s.paint("This thing happened!")); + /// ``` + #[inline] + pub fn with_style(mut self, style: Style) -> Paint<T> { + self.style = style; + self + } + + /// Masks `self`. + /// + /// A masked `Paint` is not written out when painting is disabled during + /// `Display` or `Debug` invocations. When painting is enabled, masking has + /// no effect. + /// + /// ```rust + /// use yansi::Paint; + /// + /// // "Whoops! " will only print when coloring is enabled. + /// println!("{}Something happened.", Paint::red("Whoops! ").mask()); + /// ``` + #[inline] + pub fn mask(mut self) -> Paint<T> { + self.style.masked = true; + self + } + + /// Makes `self` a _wrapping_ `Paint`. + /// + /// A wrapping `Paint` converts all color resets written out by the internal + /// value to the styling of itself. This allows for seamless color wrapping + /// of other colored text. + /// + /// # Performance + /// + /// In order to wrap an internal value, the internal value must first be + /// written out to a local buffer and examined. As a result, displaying a + /// wrapped value is likely to result in a heap allocation and copy. + /// + /// # Example + /// + /// ```rust + /// use yansi::{Paint, Color}; + /// + /// let inner = format!("{} and {}", Paint::red("Stop"), Paint::green("Go")); + /// + /// // 'Hey!' will be unstyled, "Stop" will be red, "and" will be blue, and + /// // "Go" will be green. Without a wrapping `Paint`, "and" would be + /// // unstyled. + /// println!("Hey! {}", Paint::blue(inner).wrap()); + /// ``` + #[inline] + pub fn wrap(mut self) -> Paint<T> { + self.style.wrap = true; + self + } + + /// Sets the foreground to `color`. + /// + /// ```rust + /// use yansi::Paint; + /// use yansi::Color::Red; + /// + /// println!("Red foreground: {}", Paint::new("hi!").fg(Red)); + /// ``` + #[inline] + pub fn fg(mut self, color: Color) -> Paint<T> { + self.style.foreground = color; + self + } + + /// Sets the background to `color`. + /// + /// ```rust + /// use yansi::Paint; + /// use yansi::Color::Yellow; + /// + /// println!("Yellow background: {}", Paint::new("hi!").bg(Yellow)); + /// ``` + #[inline] + pub fn bg(mut self, color: Color) -> Paint<T> { + self.style.background = color; + self + } + + style_builder_for!(Paint<T>, |paint| paint.style.properties, + bold: BOLD, dimmed: DIMMED, italic: ITALIC, + underline: UNDERLINE, blink: BLINK, invert: INVERT, + hidden: HIDDEN, strikethrough: STRIKETHROUGH); +} + +macro_rules! impl_fmt_trait { + ($trait:ident, $fmt:expr) => ( + impl<T: fmt::$trait> fmt::$trait for Paint<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if Paint::is_enabled() && self.style.wrap { + let mut prefix = String::new(); + prefix.push_str("\x1B[0m"); + self.style.fmt_prefix(&mut prefix)?; + + self.style.fmt_prefix(f)?; + let item = format!($fmt, self.item).replace("\x1B[0m", &prefix); + fmt::$trait::fmt(&item, f)?; + self.style.fmt_suffix(f) + } else if Paint::is_enabled() { + self.style.fmt_prefix(f)?; + fmt::$trait::fmt(&self.item, f)?; + self.style.fmt_suffix(f) + } else if !self.style.masked { + fmt::$trait::fmt(&self.item, f) + } else { + Ok(()) + } + } + } + ) +} + +impl_fmt_trait!(Display, "{}"); +impl_fmt_trait!(Debug, "{:?}"); + +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering; + +static ENABLED: AtomicBool = AtomicBool::new(true); + +impl Paint<()> { + /// Disables coloring globally. + /// + /// # Example + /// + /// ```rust + /// use yansi::Paint; + /// + /// // With coloring enabled, ANSI color codes are emitted. + /// assert_ne!(Paint::green("go").to_string(), "go".to_string()); + /// + /// // With coloring disabled, ANSI color codes are _not_ emitted. + /// Paint::disable(); + /// assert_eq!(Paint::green("go").to_string(), "go".to_string()); + /// ``` + pub fn disable() { + ENABLED.store(false, Ordering::Release); + } + + /// Enables coloring globally. Coloring is enabled by default, so this + /// method should only be called to _re_ enable coloring. + /// + /// # Example + /// + /// ```rust + /// use yansi::Paint; + /// + /// // With coloring disabled, ANSI color codes are _not_ emitted. + /// Paint::disable(); + /// assert_eq!(Paint::green("go").to_string(), "go".to_string()); + /// + /// // Reenabling causes color code to be emitted. + /// Paint::enable(); + /// assert_ne!(Paint::green("go").to_string(), "go".to_string()); + /// ``` + pub fn enable() { + ENABLED.store(true, Ordering::Release); + } + + /// Returns `true` if coloring is enabled and `false` otherwise. Coloring is + /// enabled by default but can be enabled and disabled on-the-fly with the + /// [`Paint::enable()`] and [`Paint::disable()`] methods. + /// + /// [`Paint::disable()`]: struct.Paint.html#method.disable + /// [`Paint::enable()`]: struct.Paint.html#method.disable + /// + /// # Example + /// + /// ```rust + /// use yansi::Paint; + /// + /// // Coloring is enabled by default. + /// assert!(Paint::is_enabled()); + /// + /// // Disable it with `Paint::disable()`. + /// Paint::disable(); + /// assert!(!Paint::is_enabled()); + /// + /// // Reenable with `Paint::enable()`. + /// Paint::enable(); + /// assert!(Paint::is_enabled()); + /// ``` + pub fn is_enabled() -> bool { + ENABLED.load(Ordering::Acquire) + } + + /// Enables ASCII terminal escape sequences on Windows consoles when + /// possible. Returns `true` if escape sequence support was successfully + /// enabled and `false` otherwise. On non-Windows targets, this method + /// always returns `true`. + /// + /// Support for escape sequences in Windows consoles was added in the + /// Windows 10 anniversary update. For targets with older Windows + /// installations, this method is expected to return `false`. + /// + /// # Example + /// + /// ```rust + /// use yansi::Paint; + /// + /// // A best-effort Windows ASCII terminal support enabling. + /// Paint::enable_windows_ascii(); + /// ``` + #[inline] + pub fn enable_windows_ascii() -> bool { + ::windows::enable_ascii_colors() + } +} diff --git a/vendor/yansi/src/style.rs b/vendor/yansi/src/style.rs new file mode 100644 index 000000000..3c4f49a17 --- /dev/null +++ b/vendor/yansi/src/style.rs @@ -0,0 +1,480 @@ +use std::hash::{Hash, Hasher}; +use std::fmt::{self, Display}; +use std::ops::BitOr; + +use {Paint, Color}; + +#[derive(Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)] +pub struct Property(u8); + +impl Property { + pub const BOLD: Self = Property(1 << 0); + pub const DIMMED: Self = Property(1 << 1); + pub const ITALIC: Self = Property(1 << 2); + pub const UNDERLINE: Self = Property(1 << 3); + pub const BLINK: Self = Property(1 << 4); + pub const INVERT: Self = Property(1 << 5); + pub const HIDDEN: Self = Property(1 << 6); + pub const STRIKETHROUGH: Self = Property(1 << 7); + + #[inline(always)] + pub fn contains(self, other: Property) -> bool { + (other.0 & self.0) == other.0 + } + + #[inline(always)] + pub fn set(&mut self, other: Property) { + self.0 |= other.0; + } + + #[inline(always)] + pub fn iter(self) -> Iter { + Iter { index: 0, properties: self } + } +} + +impl BitOr for Property { + type Output = Self; + + #[inline(always)] + fn bitor(self, rhs: Self) -> Self { + Property(self.0 | rhs.0) + } +} + +pub struct Iter { + index: u8, + properties: Property, +} + +impl Iterator for Iter { + type Item = usize; + + fn next(&mut self) -> Option<Self::Item> { + while self.index < 8 { + let index = self.index; + self.index += 1; + + if self.properties.contains(Property(1 << index)) { + return Some(index as usize); + } + } + + None + } +} + +/// Represents a set of styling options. +/// +/// See the [crate level documentation](./) for usage information. +/// +/// # Method Glossary +/// +/// The `Style` structure exposes many methods for convenience. The majority of +/// these methods are shared with [`Paint`](Paint). +/// +/// ### Foreground Color Constructors +/// +/// Return a new `Style` structure with a foreground `color` applied. +/// +/// * [`Style::new(color: Color)`](Style::new()) +/// +/// ### Setters +/// +/// Set a style property on a given `Style` structure. +/// +/// * [`style.fg(color: Color)`](Style::fg()) +/// * [`style.bg(color: Color)`](Style::bg()) +/// * [`style.mask()`](Style::mask()) +/// * [`style.wrap()`](Style::wrap()) +/// * [`style.bold()`](Style::bold()) +/// * [`style.dimmed()`](Style::dimmed()) +/// * [`style.italic()`](Style::italic()) +/// * [`style.underline()`](Style::underline()) +/// * [`style.blink()`](Style::blink()) +/// * [`style.invert()`](Style::invert()) +/// * [`style.hidden()`](Style::hidden()) +/// * [`style.strikethrough()`](Style::strikethrough()) +/// +/// These methods can be chained: +/// +/// ```rust +/// use yansi::{Style, Color::{Red, Magenta}}; +/// +/// Style::new(Red).bg(Magenta).underline().invert().italic().dimmed().bold(); +/// ``` +/// +/// ### Converters +/// +/// Convert a `Style` into another structure. +/// +/// * [`style.paint<T>(item: T) -> Paint<T>`](Style::paint()) +/// +/// ### Getters +/// +/// Return information about a `Style` structure. +/// +/// * [`style.fg_color()`](Style::fg_color()) +/// * [`style.bg_color()`](Style::bg_color()) +/// * [`style.is_masked()`](Style::is_masked()) +/// * [`style.is_wrapping()`](Style::is_wrapping()) +/// * [`style.is_bold()`](Style::is_bold()) +/// * [`style.is_dimmed()`](Style::is_dimmed()) +/// * [`style.is_italic()`](Style::is_italic()) +/// * [`style.is_underline()`](Style::is_underline()) +/// * [`style.is_blink()`](Style::is_blink()) +/// * [`style.is_invert()`](Style::is_invert()) +/// * [`style.is_hidden()`](Style::is_hidden()) +/// * [`style.is_strikethrough()`](Style::is_strikethrough()) +/// +/// ### Raw Formatters +/// +/// Write the raw ANSI codes for a given `Style` to any `fmt::Write`. +/// +/// * [`style.fmt_prefix(f: &mut fmt::Write)`](Style::fmt_prefix()) +/// * [`style.fmt_suffix(f: &mut fmt::Write)`](Style::fmt_suffix()) +#[repr(packed)] +#[derive(Default, Debug, Eq, Ord, PartialOrd, Copy, Clone)] +pub struct Style { + pub(crate) foreground: Color, + pub(crate) background: Color, + pub(crate) properties: Property, + pub(crate) masked: bool, + pub(crate) wrap: bool, +} + +impl PartialEq for Style { + fn eq(&self, other: &Style) -> bool { + self.foreground == other.foreground + && self.background == other.background + && self.properties == other.properties + } +} + +impl Hash for Style { + fn hash<H: Hasher>(&self, state: &mut H) { + self.foreground.hash(state); + self.background.hash(state); + self.properties.hash(state); + } +} + +macro_rules! checker_for { + ($($name:ident ($fn_name:ident): $property:ident),*) => ($( + #[doc = concat!( + "Returns `true` if the _", stringify!($name), "_ property is set on `self`.\n", + "```rust\n", + "use yansi::Style;\n", + "\n", + "let plain = Style::default();\n", + "assert!(!plain.", stringify!($fn_name), "());\n", + "\n", + "let styled = plain.", stringify!($name), "();\n", + "assert!(styled.", stringify!($fn_name), "());\n", + "```\n" + )] + #[inline] + pub fn $fn_name(&self) -> bool { + self.properties.contains(Property::$property) + } + )*) +} + +#[inline] +fn write_spliced<T: Display>(c: &mut bool, f: &mut fmt::Write, t: T) -> fmt::Result { + if *c { + write!(f, ";{}", t) + } else { + *c = true; + write!(f, "{}", t) + } +} + +impl Style { + /// Default style with the foreground set to `color` and no other set + /// properties. + /// + /// ```rust + /// use yansi::Style; + /// + /// let plain = Style::default(); + /// assert_eq!(plain, Style::default()); + /// ``` + #[inline] + pub fn new(color: Color) -> Style { + Self::default().fg(color) + } + + /// Sets the foreground to `color`. + /// + /// ```rust + /// use yansi::{Color, Style}; + /// + /// let red_fg = Style::default().fg(Color::Red); + /// ``` + #[inline] + pub fn fg(mut self, color: Color) -> Style { + self.foreground = color; + self + } + + /// Sets the background to `color`. + /// + /// ```rust + /// use yansi::{Color, Style}; + /// + /// let red_bg = Style::default().bg(Color::Red); + /// ``` + #[inline] + pub fn bg(mut self, color: Color) -> Style { + self.background = color; + self + } + + /// Sets `self` to be masked. + /// + /// An item with _masked_ styling is not written out when painting is + /// disabled during `Display` or `Debug` invocations. When painting is + /// enabled, masking has no effect. + /// + /// ```rust + /// use yansi::Style; + /// + /// let masked = Style::default().mask(); + /// + /// // "Whoops! " will only print when coloring is enabled. + /// println!("{}Something happened.", masked.paint("Whoops! ")); + /// ``` + #[inline] + pub fn mask(mut self) -> Style { + self.masked = true; + self + } + + /// Sets `self` to be wrapping. + /// + /// A wrapping `Style` converts all color resets written out by the internal + /// value to the styling of itself. This allows for seamless color wrapping + /// of other colored text. + /// + /// # Performance + /// + /// In order to wrap an internal value, the internal value must first be + /// written out to a local buffer and examined. As a result, displaying a + /// wrapped value is likely to result in a heap allocation and copy. + /// + /// ```rust + /// use yansi::{Paint, Style, Color}; + /// + /// let inner = format!("{} and {}", Paint::red("Stop"), Paint::green("Go")); + /// let wrapping = Style::new(Color::Blue).wrap(); + /// + /// // 'Hey!' will be unstyled, "Stop" will be red, "and" will be blue, and + /// // "Go" will be green. Without a wrapping `Paint`, "and" would be + /// // unstyled. + /// println!("Hey! {}", wrapping.paint(inner)); + /// ``` + #[inline] + pub fn wrap(mut self) -> Style { + self.wrap = true; + self + } + + style_builder_for!(Style, |style| style.properties, + bold: BOLD, dimmed: DIMMED, italic: ITALIC, + underline: UNDERLINE, blink: BLINK, invert: INVERT, + hidden: HIDDEN, strikethrough: STRIKETHROUGH); + + /// Constructs a new `Paint` structure that encapsulates `item` with the + /// style set to `self`. + /// + /// ```rust + /// use yansi::{Style, Color}; + /// + /// let alert = Style::new(Color::Red).bold().underline(); + /// println!("Alert: {}", alert.paint("This thing happened!")); + /// ``` + #[inline] + pub fn paint<T>(self, item: T) -> Paint<T> { + Paint::new(item).with_style(self) + } + + /// Returns the foreground color of `self`. + /// + /// ```rust + /// use yansi::{Style, Color}; + /// + /// let plain = Style::default(); + /// assert_eq!(plain.fg_color(), Color::Unset); + /// + /// let red = plain.fg(Color::Red); + /// assert_eq!(red.fg_color(), Color::Red); + /// ``` + #[inline] + pub fn fg_color(&self) -> Color { + self.foreground + } + + /// Returns the foreground color of `self`. + /// + /// ```rust + /// use yansi::{Style, Color}; + /// + /// let plain = Style::default(); + /// assert_eq!(plain.bg_color(), Color::Unset); + /// + /// let white = plain.bg(Color::White); + /// assert_eq!(white.bg_color(), Color::White); + /// ``` + #[inline] + pub fn bg_color(&self) -> Color { + self.background + } + + /// Returns `true` if `self` is masked. + /// + /// ```rust + /// use yansi::Style; + /// + /// let plain = Style::default(); + /// assert!(!plain.is_masked()); + /// + /// let masked = plain.mask(); + /// assert!(masked.is_masked()); + /// ``` + #[inline] + pub fn is_masked(&self) -> bool { + self.masked + } + + /// Returns `true` if `self` is wrapping. + /// + /// ```rust + /// use yansi::Style; + /// + /// let plain = Style::default(); + /// assert!(!plain.is_wrapping()); + /// + /// let wrapping = plain.wrap(); + /// assert!(wrapping.is_wrapping()); + /// ``` + #[inline] + pub fn is_wrapping(&self) -> bool { + self.wrap + } + + checker_for!(bold (is_bold): BOLD, dimmed (is_dimmed): DIMMED, + italic (is_italic): ITALIC, underline (is_underline): UNDERLINE, + blink (is_blink): BLINK, invert (is_invert): INVERT, + hidden (is_hidden): HIDDEN, + strikethrough (is_strikethrough): STRIKETHROUGH); + + #[inline(always)] + fn is_plain(&self) -> bool { + self == &Style::default() + } + + /// Writes the ANSI code prefix for the currently set styles. + /// + /// This method is intended to be used inside of [`fmt::Display`] and + /// [`fmt::Debug`] implementations for custom or specialized use-cases. Most + /// users should use [`Paint`] for all painting needs. + /// + /// This method writes the ANSI code prefix irrespective of whether painting + /// is currently enabled or disabled. To write the prefix only if painting + /// is enabled, condition a call to this method on [`Paint::is_enabled()`]. + /// + /// [`fmt::Display`]: fmt::Display + /// [`fmt::Debug`]: fmt::Debug + /// [`Paint`]: Paint + /// [`Paint::is_enabled()`]: Paint::is_enabled() + /// + /// # Example + /// + /// ```rust + /// use std::fmt; + /// use yansi::Style; + /// + /// struct CustomItem { + /// item: u32, + /// style: Style + /// } + /// + /// impl fmt::Display for CustomItem { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// self.style.fmt_prefix(f)?; + /// write!(f, "number: {}", self.item)?; + /// self.style.fmt_suffix(f) + /// } + /// } + /// ``` + pub fn fmt_prefix(&self, f: &mut fmt::Write) -> fmt::Result { + // A user may just want a code-free string when no styles are applied. + if self.is_plain() { + return Ok(()); + } + + let mut splice = false; + write!(f, "\x1B[")?; + + for i in self.properties.iter() { + let k = if i >= 5 { i + 2 } else { i + 1 }; + write_spliced(&mut splice, f, k)?; + } + + if self.background != Color::Unset { + write_spliced(&mut splice, f, "4")?; + self.background.ascii_fmt(f)?; + } + + if self.foreground != Color::Unset { + write_spliced(&mut splice, f, "3")?; + self.foreground.ascii_fmt(f)?; + } + + // All the codes end with an `m`. + write!(f, "m") + } + + /// Writes the ANSI code suffix for the currently set styles. + /// + /// This method is intended to be used inside of [`fmt::Display`] and + /// [`fmt::Debug`] implementations for custom or specialized use-cases. Most + /// users should use [`Paint`] for all painting needs. + /// + /// This method writes the ANSI code suffix irrespective of whether painting + /// is currently enabled or disabled. To write the suffix only if painting + /// is enabled, condition a call to this method on [`Paint::is_enabled()`]. + /// + /// [`fmt::Display`]: fmt::Display + /// [`fmt::Debug`]: fmt::Debug + /// [`Paint`]: Paint + /// [`Paint::is_enabled()`]: Paint::is_enabled() + /// + /// # Example + /// + /// ```rust + /// use std::fmt; + /// use yansi::Style; + /// + /// struct CustomItem { + /// item: u32, + /// style: Style + /// } + /// + /// impl fmt::Display for CustomItem { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// self.style.fmt_prefix(f)?; + /// write!(f, "number: {}", self.item)?; + /// self.style.fmt_suffix(f) + /// } + /// } + /// ``` + pub fn fmt_suffix(&self, f: &mut fmt::Write) -> fmt::Result { + if self.is_plain() { + return Ok(()); + } + + write!(f, "\x1B[0m") + } +} diff --git a/vendor/yansi/src/tests.rs b/vendor/yansi/src/tests.rs new file mode 100644 index 000000000..f3f678140 --- /dev/null +++ b/vendor/yansi/src/tests.rs @@ -0,0 +1,182 @@ +extern crate serial_test; + +use self::serial_test::serial; + +use super::Color::*; +use super::{Paint, Style}; + +macro_rules! assert_renders { + ($($input:expr => $expected:expr,)*) => { + $( + let (input, expected) = ($input.to_string(), $expected.to_string()); + if input != expected { + panic!("expected {:?}, got {:?} from {:?} ({:?})", + expected, input, $input.inner(), $input.style()) + } + )* + }; +} + +macro_rules! assert_disabled_renders { + ($($input:expr => $expected:expr,)*) => { + $( + Paint::disable(); + let (actual, expected) = ($input.to_string(), $expected.to_string()); + Paint::enable(); + assert_eq!(actual, expected); + )* + }; +} + +#[test] +#[serial] +fn colors_enabled() { + assert_renders! { + Paint::new("text/plain") => "text/plain", + Paint::red("hi") => "\x1B[31mhi\x1B[0m", + Paint::black("hi") => "\x1B[30mhi\x1B[0m", + Paint::yellow("hi").bold() => "\x1B[1;33mhi\x1B[0m", + Paint::new("hi").fg(Yellow).bold() => "\x1B[1;33mhi\x1B[0m", + Paint::blue("hi").underline() => "\x1B[4;34mhi\x1B[0m", + Paint::green("hi").bold().underline() => "\x1B[1;4;32mhi\x1B[0m", + Paint::green("hi").underline().bold() => "\x1B[1;4;32mhi\x1B[0m", + Paint::magenta("hi").bg(White) => "\x1B[47;35mhi\x1B[0m", + Paint::red("hi").bg(Blue).fg(Yellow) => "\x1B[44;33mhi\x1B[0m", + Paint::cyan("hi").bg(Blue).fg(Yellow) => "\x1B[44;33mhi\x1B[0m", + Paint::cyan("hi").bold().bg(White) => "\x1B[1;47;36mhi\x1B[0m", + Paint::cyan("hi").underline().bg(White) => "\x1B[4;47;36mhi\x1B[0m", + Paint::cyan("hi").bold().underline().bg(White) => "\x1B[1;4;47;36mhi\x1B[0m", + Paint::cyan("hi").underline().bold().bg(White) => "\x1B[1;4;47;36mhi\x1B[0m", + Paint::fixed(100, "hi") => "\x1B[38;5;100mhi\x1B[0m", + Paint::fixed(100, "hi").bg(Magenta) => "\x1B[45;38;5;100mhi\x1B[0m", + Paint::fixed(100, "hi").bg(Fixed(200)) => "\x1B[48;5;200;38;5;100mhi\x1B[0m", + Paint::rgb(70, 130, 180, "hi") => "\x1B[38;2;70;130;180mhi\x1B[0m", + Paint::rgb(70, 130, 180, "hi").bg(Blue) => "\x1B[44;38;2;70;130;180mhi\x1B[0m", + Paint::blue("hi").bg(RGB(70, 130, 180)) => "\x1B[48;2;70;130;180;34mhi\x1B[0m", + Paint::rgb(70, 130, 180, "hi").bg(RGB(5,10,15)) => "\x1B[48;2;5;10;15;38;2;70;130;180mhi\x1B[0m", + Paint::new("hi").bold() => "\x1B[1mhi\x1B[0m", + Paint::new("hi").underline() => "\x1B[4mhi\x1B[0m", + Paint::new("hi").bold().underline() => "\x1B[1;4mhi\x1B[0m", + Paint::new("hi").dimmed() => "\x1B[2mhi\x1B[0m", + Paint::new("hi").italic() => "\x1B[3mhi\x1B[0m", + Paint::new("hi").blink() => "\x1B[5mhi\x1B[0m", + Paint::new("hi").invert() => "\x1B[7mhi\x1B[0m", + Paint::new("hi").hidden() => "\x1B[8mhi\x1B[0m", + Paint::new("hi").strikethrough() => "\x1B[9mhi\x1B[0m", + } +} + +#[test] +#[serial] +fn colors_disabled() { + assert_disabled_renders! { + Paint::new("text/plain") => "text/plain", + Paint::red("hi") => "hi", + Paint::black("hi") => "hi", + Paint::yellow("hi").bold() => "hi", + Paint::new("hi").fg(Yellow).bold() => "hi", + Paint::blue("hi").underline() => "hi", + Paint::green("hi").bold().underline() => "hi", + Paint::green("hi").underline().bold() => "hi", + Paint::magenta("hi").bg(White) => "hi", + Paint::red("hi").bg(Blue).fg(Yellow) => "hi", + Paint::cyan("hi").bg(Blue).fg(Yellow) => "hi", + Paint::cyan("hi").bold().bg(White) => "hi", + Paint::cyan("hi").underline().bg(White) => "hi", + Paint::cyan("hi").bold().underline().bg(White) => "hi", + Paint::cyan("hi").underline().bold().bg(White) => "hi", + Paint::fixed(100, "hi") => "hi", + Paint::fixed(100, "hi").bg(Magenta) => "hi", + Paint::fixed(100, "hi").bg(Fixed(200)) => "hi", + Paint::rgb(70, 130, 180, "hi") => "hi", + Paint::rgb(70, 130, 180, "hi").bg(Blue) => "hi", + Paint::blue("hi").bg(RGB(70, 130, 180)) => "hi", + Paint::blue("hi").bg(RGB(70, 130, 180)).wrap() => "hi", + Paint::rgb(70, 130, 180, "hi").bg(RGB(5,10,15)) => "hi", + Paint::new("hi").bold() => "hi", + Paint::new("hi").underline() => "hi", + Paint::new("hi").bold().underline() => "hi", + Paint::new("hi").dimmed() => "hi", + Paint::new("hi").italic() => "hi", + Paint::new("hi").blink() => "hi", + Paint::new("hi").invert() => "hi", + Paint::new("hi").hidden() => "hi", + Paint::new("hi").strikethrough() => "hi", + Paint::new("hi").strikethrough().wrap() => "hi", + } +} + +#[test] +#[serial] +fn masked_when_disabled() { + assert_disabled_renders! { + Paint::masked("text/plain") => "", + Paint::masked("text/plain").mask() => "", + Paint::new("text/plain").mask() => "", + Paint::new("text/plain").mask() => "", + Paint::red("hi").mask() => "", + Paint::black("hi").mask() => "", + Paint::yellow("hi").bold().mask() => "", + Paint::cyan("hi").bg(Blue).fg(Yellow).mask() => "", + Paint::cyan("hi").underline().bold().bg(White).mask() => "", + } +} + +#[test] +#[serial] +fn masked_when_enabled() { + assert_renders! { + Paint::masked("text/plain") => "text/plain", + Paint::masked("text/plain").mask() => "text/plain", + Paint::black("hi").mask() => "\x1B[30mhi\x1B[0m", + Paint::yellow("hi").bold().mask() => "\x1B[1;33mhi\x1B[0m", + Paint::new("hi").fg(Yellow).bold().mask() => "\x1B[1;33mhi\x1B[0m", + Paint::cyan("hi").underline().bg(White).mask() => "\x1B[4;47;36mhi\x1B[0m", + Paint::cyan("hi").bold().underline().bg(White).mask() => "\x1B[1;4;47;36mhi\x1B[0m", + Paint::rgb(70, 130, 180, "hi").mask() => "\x1B[38;2;70;130;180mhi\x1B[0m", + Paint::new("hi").underline().mask() => "\x1B[4mhi\x1B[0m", + Paint::new("hi").bold().underline().mask() => "\x1B[1;4mhi\x1B[0m", + Paint::new("hi").hidden().mask() => "\x1B[8mhi\x1B[0m", + } +} + +#[test] +#[serial] +fn wrapping() { + let inner = || format!("{} b {}", Paint::red("a"), Paint::green("c")); + let inner2 = || format!("0 {} 1", Paint::magenta(&inner()).wrap()); + assert_renders! { + Paint::new("text/plain").wrap() => "text/plain", + Paint::new(&inner()).wrap() => &inner(), + Paint::new(&inner()).wrap() => + "\u{1b}[31ma\u{1b}[0m b \u{1b}[32mc\u{1b}[0m", + Paint::new(&inner()).fg(Blue).wrap() => + "\u{1b}[34m\u{1b}[31ma\u{1b}[0m\u{1b}[34m b \ + \u{1b}[32mc\u{1b}[0m\u{1b}[34m\u{1b}[0m", + Paint::new(&inner2()).wrap() => &inner2(), + Paint::new(&inner2()).wrap() => + "0 \u{1b}[35m\u{1b}[31ma\u{1b}[0m\u{1b}[35m b \ + \u{1b}[32mc\u{1b}[0m\u{1b}[35m\u{1b}[0m 1", + Paint::new(&inner2()).fg(Blue).wrap() => + "\u{1b}[34m0 \u{1b}[35m\u{1b}[31ma\u{1b}[0m\u{1b}[34m\u{1b}[35m b \ + \u{1b}[32mc\u{1b}[0m\u{1b}[34m\u{1b}[35m\u{1b}[0m\u{1b}[34m 1\u{1b}[0m", + } +} + +#[test] +fn hash_eq() { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + fn hash<T: Hash>(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + let a = Style::default(); + let b = Style::default().mask(); + + assert_eq!(a, b); + assert_eq!(hash(&a), hash(&b)); +} diff --git a/vendor/yansi/src/windows.rs b/vendor/yansi/src/windows.rs new file mode 100644 index 000000000..324cfc39a --- /dev/null +++ b/vendor/yansi/src/windows.rs @@ -0,0 +1,69 @@ +#[cfg(windows)] +mod windows_console { + use std::os::raw::c_void; + + #[allow(non_camel_case_types)] type c_ulong = u32; + #[allow(non_camel_case_types)] type c_int = i32; + type DWORD = c_ulong; + type LPDWORD = *mut DWORD; + type HANDLE = *mut c_void; + type BOOL = c_int; + + const ENABLE_VIRTUAL_TERMINAL_PROCESSING: DWORD = 0x0004; + const STD_OUTPUT_HANDLE: DWORD = 0xFFFFFFF5; + const STD_ERROR_HANDLE: DWORD = 0xFFFFFFF4; + const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE; + const FALSE: BOOL = 0; + const TRUE: BOOL = 1; + + // This is the win32 console API, taken from the 'winapi' crate. + extern "system" { + fn GetStdHandle(nStdHandle: DWORD) -> HANDLE; + fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL; + fn SetConsoleMode(hConsoleHandle: HANDLE, dwMode: DWORD) -> BOOL; + } + + unsafe fn get_handle(handle_num: DWORD) -> Result<HANDLE, ()> { + match GetStdHandle(handle_num) { + handle if handle == INVALID_HANDLE_VALUE => Err(()), + handle => Ok(handle) + } + } + + unsafe fn enable_vt(handle: HANDLE) -> Result<(), ()> { + let mut dw_mode: DWORD = 0; + if GetConsoleMode(handle, &mut dw_mode) == FALSE { + return Err(()); + } + + dw_mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + match SetConsoleMode(handle, dw_mode) { + result if result == TRUE => Ok(()), + _ => Err(()) + } + } + + unsafe fn enable_ascii_colors_raw() -> Result<bool, ()> { + let stdout_handle = get_handle(STD_OUTPUT_HANDLE)?; + let stderr_handle = get_handle(STD_ERROR_HANDLE)?; + + enable_vt(stdout_handle)?; + if stdout_handle != stderr_handle { + enable_vt(stderr_handle)?; + } + + Ok(true) + } + + #[inline] + pub fn enable_ascii_colors() -> bool { + unsafe { enable_ascii_colors_raw().unwrap_or(false) } + } +} + +#[cfg(not(windows))] +mod windows_console { + pub fn enable_ascii_colors() -> bool { true } +} + +pub use self::windows_console::enable_ascii_colors; |