diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
commit | c23a457e72abe608715ac76f076f47dc42af07a5 (patch) | |
tree | 2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /vendor/color-print/src/lib.rs | |
parent | Releasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip |
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/color-print/src/lib.rs')
-rw-r--r-- | vendor/color-print/src/lib.rs | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/vendor/color-print/src/lib.rs b/vendor/color-print/src/lib.rs new file mode 100644 index 000000000..14535f5db --- /dev/null +++ b/vendor/color-print/src/lib.rs @@ -0,0 +1,443 @@ +//! Colorize and stylize strings at compile-time, by using an HTML-like syntax. +//! +//! This library provides the following macros: +//! +//! - `cformat!(<FORMAT_STRING> [, ARGS...])` +//! - `cprint!(<FORMAT_STRING> [, ARGS...])` +//! - `cprintln!(<FORMAT_STRING> [, ARGS...])` +//! - `cstr!(<FORMAT_STRING>)` +//! - `untagged!(<FORMAT_STRING>)` +//! +//! [`cformat!()`], [`cprint!()`], and [`cprintln!()`] have the same syntax as `format!()`, +//! `print!()` and `println!()` respectively, but they accept an additional syntax inside the +//! format string: HTML-like tags which add terminal colors/styles at compile-time. +//! +//! *Note*: these tags are commonly named "*color tags*" in the documentation below. +//! +//! [`cstr!()`] only transforms the given string literal into another string literal, without +//! formatting anything else than the colors tag. +//! +//! [`untagged!()`] removes all the color tags found in the given string literal. +//! +//! ## What does it do ? +//! +//! By default, the provided macros will replace the color tags found in the format string by ANSI +//! hexadecimal escape codes. E.g.: +//! +//! ``` +//! # use color_print::cprintln; +//! # fn main() { +//! cprintln!("HELLO <green>WORLD</green>") +//! # } +//! ``` +//! +//! will be replaced by: +//! +//! ``` +//! # use color_print::cprintln; +//! # fn main() { +//! println!("HELLO \u{1b}[31mWORLD\u{1b}[39m") +//! # } +//! ``` +//! +//! *Note*: it is possible to change this behaviour by activating the feature `terminfo`. Then it +//! will question the `terminfo` database at runtime in order to know which sequence to write for +//! each kind of styling/colorizing (see below for more detail). +//! +//! # Pros/cons of this crate +//! +//! ## Pros +//! +//! * Styling is processed at compile-time, so the runtime payload is quite inexistant (unless the +//! feature `terminfo` is activated); +//! * Nested tags are well handled, e.g. `"<green>...<blue>...</blue>...</green>"`; +//! * Some optimizations are performed to avoid redundant ANSI sequences, because these +//! optimizations can be done at compile-time without impacting the runtime; +//! * Almost every tag has a short name, so colorizing can be done quickly: `"my <b>blue</> word"`; +//! * Each provided macro can be used exactly in the same way as the standard `format!`-like +//! macros; e.g., positional arguments and named arguments can be used as usual; +//! * Fine-grained error handling. +//! +//! ## Cons +//! +//! * Many CLI programs detect on runtime if they are actually piped to another command or not, and +//! decide to colorize their output based on this information. As `color-print` formats strings at +//! compile-time, this is not possible to do that easily; +//! * Not compatible with non-ANSI Windows terminals (and not tested at all on Windows, feedbacks +//! are welcome); +//! * Not tested on Mac, feedbacks are welcome. +//! +//! # Introduction +//! +//! ## Basic example +//! +//! ``` +//! use color_print::cprintln; +//! cprintln!("Hello <green>world</green>!"); +//! ``` +//! +//! ## Closing a tag more simply: the `</>` tag +//! +//! Basically, tags must be closed by giving exactly the same colors/styles of the matching open +//! tag (with a slash `/` at the beginning). But it can be tedious! +//! +//! So, it is also possible to close the last open tag simply with `</>`: +//! +//! ``` +//! # use color_print::cprintln; +//! # fn main() { +//! cprintln!("Hello <green>world</>!"); +//! # } +//! ``` +//! +//! ## Combining colors and styles +//! +//! Multiple styles and color(s) can be combined into a single tag by separating them with the `,` +//! comma character: +//! +//! ``` +//! # use color_print::cprintln; +//! # fn main() { +//! cprintln!("This a <green,bold>green and bold text</green,bold>."); +//! // The same, but closing with the </> tag: +//! cprintln!("This a <green,bold>green and bold text</>."); +//! # } +//! ``` +//! +//! Of course, combining multiple foreground colors or multiple background colors into the same tag +//! is useless (in such a case, only the last one is taken into account). +//! +//! ## Nesting tags +//! +//! Any tag can be nested with any other, as long as the closing tags match correctly (following +//! the basic rules of nesting for HTML tags): +//! +//! ``` +//! # use color_print::cprintln; +//! # fn main() { +//! cprintln!("<green>This is green, <bold>then green and bold</bold>, then green again</green>"); +//! cprintln!("<green>This is green, <bold>then green and bold</>, then green again</>"); +//! +//! // Colors can be nested as well: +//! cprintln!("<green>This is green, <blue>then blue</blue>, then green again</green>"); +//! cprintln!("<green>This is green, <blue>then blue</>, then green again</>"); +//! # } +//! ``` +//! +//! ## Unclosed tags are automatically closed at the end of the format string +//! +//! Tags which have not been closed manually will be closed automatically, which means that the +//! ANSI sequences needed to go back to the original state will be added: +//! +//! ``` +//! # use color_print::cprintln; +//! # fn main() { +//! // The two following lines are strictly equivalent: +//! cprintln!("<green><bold>Hello"); +//! cprintln!("<green><bold>Hello</></>"); +//! # } +//! ``` +//! +//! ## How to display the chars `<` and `>` verbatim +//! +//! As for `{` and `}`, the chars `<` and `>` have to be doubled in order to display them verbatim: +//! +//! ``` +//! # use color_print::cprintln; +//! # fn main() { +//! cprintln!("This is an angle bracket character: <<, and here is another one: >>"); +//! # } +//! ``` +//! +//! # Optimization: no redundant ANSI codes +//! +//! The expanded format string will only contain the *needed* ANSI codes. This is done by making a +//! diff of the different style attributes, each time a color tag is encountered, instead of +//! mechanically adding the ANSI codes. +//! +//! E.g., several nested `<bold>` tags will only produce one bold ANSI sequence: +//! +//! ``` +//! # use color_print::cprintln; +//! # fn main() { +//! cprintln!("<bold><bold>A <bold,blue>B C D</> E</></>") +//! # } +//! ``` +//! +//! will be replaced by: +//! +//! ``` +//! # use color_print::cprintln; +//! # fn main() { +//! println!("\u{1b}[1mA \u{1b}[34mB C D\u{1b}[39m E\u{1b}[22m") +//! // ^-------^ ^--------^ ^--------^ ^--------^ +//! // bold blue color bold +//! // reset reset +//! # } +//! ``` +//! +//! # The feature `terminfo` +//! +//! Instead of inserting ANSI sequences directly into the format string, it is possible to activate +//! the feature `terminfo`: this will add the format sequences at runtime, by consulting the +//! `terminfo` database. +//! +//! This has one pro and several cons: +//! +//! #### Pros +//! +//! * This adds a level of compatibility for some terminals. +//! +//! #### Cons +//! +//! * This adds a little runtime payload; +//! * This adds two dependencies: [`lazy_static`] and [`terminfo`]; +//! * The styles `<strike>` and `<conceal>` are not handled; +//! * With `terminfo`, many styles are not resettable individually, which implies longer format +//! sequences for the same result; +//! * For now, the provided macros can only be used in one thread. +//! +//! [`lazy_static`]: https://crates.io/crates/lazy_static +//! [`terminfo`]: https://crates.io/crates/terminfo +//! +//! # Naming rules of the color tags: +//! +//! Each color/style tag has at least a long name, like `<magenta>` or `<underline>`. +//! +//! The tags directly relative to *colors* (like `<red>`, `<bg:blue>`, `<bg:bright-green>`..., as +//! opposed to *style* tags like `<bold>`, `<italics>`...) have some common naming rules: +//! +//! * Each color tag has four variants: +//! - `<mycolor>`: the normal, foreground color; +//! - `<bright-mycolor>` or `<mycolor!>`: the bright, foreground color; +//! - `<bg:mycolor>`: the normal, background color; +//! - `<bg:bright-mycolor>`, `<bg:mycolor!>`, `<BRIGHT-MYCOLOR>` or `<MYCOLOR!>`: the bright, +//! background color; +//! * Each color tag has a *shortcut*, with a base letter for each color (example with the `x` +//! letter): +//! - `<x>`: the normal, foreground color; +//! - `<x!>`: the bright, foreground color; +//! - `<bg:x>` or `<X>`: the normal, background color; +//! - `<bg:x!>` or `<X!>`: the bright, background color; +//! * Except for the color `<black>`, each color's shortcut letter is simply the first letter of +//! its name, e.g. `<y>` is the shortcut for `<yellow>`; +//! * Each color's tag which is uppercase is a background color; +//! * Each tag which has a trailing exclamation point `!` is a bright color; +//! +//! # List of accepted color/style tags: +//! +//! The two first columns show which styles are supported, respectively with the default crate +//! features (ANSI column), and with the feature `terminfo` being activated. +//! +//! | ANSI | Terminfo | Shortcuts | Long names | Aliases | +//! | ---- | -------- | --------- | ----------------------- | ----------------------------------------------- | +//! | X | X | `<s>` | `<bold>` | `<em>` `<strong>` | +//! | X | X | | `<dim>` | | +//! | X | X | `<u>` | `<underline>` | | +//! | X | | | `<strike>` | | +//! | X | X | | `<reverse>` | `<rev>` | +//! | X | | | `<conceal>` | `<hide>` | +//! | X | X | `<i>` | `<italics>` | `<italic>` | +//! | X | X | | `<blink>` | | +//! | X | X | `<k>` | `<black>` | | +//! | X | X | `<r>` | `<red>` | | +//! | X | X | `<g>` | `<green>` | | +//! | X | X | `<y>` | `<yellow>` | | +//! | X | X | `<b>` | `<blue>` | | +//! | X | X | `<m>` | `<magenta>` | | +//! | X | X | `<c>` | `<cyan>` | | +//! | X | X | `<w>` | `<white>` | | +//! | X | X | `<k!>` | `<bright-black>` | `<black!>` | +//! | X | X | `<r!>` | `<bright-red>` | `<red!>` | +//! | X | X | `<g!>` | `<bright-green>` | `<green!>` | +//! | X | X | `<y!>` | `<bright-yellow>` | `<yellow!>` | +//! | X | X | `<b!>` | `<bright-blue>` | `<blue!>` | +//! | X | X | `<m!>` | `<bright-magenta>` | `<magenta!>` | +//! | X | X | `<c!>` | `<bright-cyan>` | `<cyan!>` | +//! | X | X | `<w!>` | `<bright-white>` | `<white!>` | +//! | X | X | `<K>` | `<bg:black>` | `<BLACK>` | +//! | X | X | `<R>` | `<bg:red>` | `<RED>` | +//! | X | X | `<G>` | `<bg:green>` | `<GREEN>` | +//! | X | X | `<Y>` | `<bg:yellow>` | `<YELLOW>` | +//! | X | X | `<B>` | `<bg:blue>` | `<BLUE>` | +//! | X | X | `<M>` | `<bg:magenta>` | `<MAGENTA>` | +//! | X | X | `<C>` | `<bg:cyan>` | `<CYAN>` | +//! | X | X | `<W>` | `<bg:white>` | `<WHITE>` | +//! | X | X | `<K!>` | `<bg:bright-black>` | `<BLACK!>` `<bg:black!>` `<BRIGHT-BLACK>` | +//! | X | X | `<R!>` | `<bg:bright-red>` | `<RED!>` `<bg:red!>` `<BRIGHT-RED>` | +//! | X | X | `<G!>` | `<bg:bright-green>` | `<GREEN!>` `<bg:green!>` `<BRIGHT-GREEN>` | +//! | X | X | `<Y!>` | `<bg:bright-yellow>` | `<YELLOW!>` `<bg:yellow!>` `<BRIGHT-YELLOW>` | +//! | X | X | `<B!>` | `<bg:bright-blue>` | `<BLUE!>` `<bg:blue!>` `<BRIGHT-BLUE>` | +//! | X | X | `<M!>` | `<bg:bright-magenta>` | `<MAGENTA!>` `<bg:magenta!>` `<BRIGHT-MAGENTA>` | +//! | X | X | `<C!>` | `<bg:bright-cyan>` | `<CYAN!>` `<bg:cyan!>` `<BRIGHT-CYAN>` | +//! | X | X | `<W!>` | `<bg:bright-white>` | `<WHITE!>` `<bg:white!>` `<BRIGHT-WHITE>` | +//! | X | | | `<rgb(r,g,b)>` | `<#RRGGBB>` | +//! | X | | | `<bg:rgb(r,g,b)>` | `<bg:#RRGGBB>` `<RGB(r,g,b)>` | +//! | X | | `<0>`...`<255>` | `<palette(...)>` | `<p(...)>` `<pal(...)>` | +//! | X | | `<P(...)>` | `<bg:palette(...)>` | `<PALETTE(...)>` `<PAL(...)>` `<bg:p(...)>` `<bg:pal(...)>` | + +pub use color_print_proc_macro::{cformat, cprint, cprintln, untagged}; +#[cfg(not(feature = "terminfo"))] +pub use color_print_proc_macro::cstr; + +#[cfg(feature = "terminfo")] +mod terminfo; +#[cfg(feature = "terminfo")] +pub use terminfo::*; + +#[cfg(test)] +mod tests { + use super::*; + + pub mod color_print { + pub use super::*; + } + + #[test] + fn format_no_arg() { + assert_eq!(cformat!(), ""); + cprint!(); + cprintln!(); + } + + #[test] + fn format_no_color() { + assert_eq!(cformat!(""), ""); + assert_eq!(cformat!("Hi"), "Hi"); + assert_eq!(cformat!("Hi {}", 12), "Hi 12"); + assert_eq!(cformat!("Hi {n} {}", 12, n = 24), "Hi 24 12"); + } + + #[test] + #[cfg(not(feature = "terminfo"))] + #[rustfmt::skip] + fn format_basic() { + assert_eq!(cformat!("<red>Hi</red>"), "\u{1b}[31mHi\u{1b}[39m"); + assert_eq!(cformat!("<red>Hi</r>"), "\u{1b}[31mHi\u{1b}[39m"); + assert_eq!(cformat!("<red>Hi</>"), "\u{1b}[31mHi\u{1b}[39m"); + + assert_eq!(cformat!("<bg:red>Hi</bg:red>"), "\u{1b}[41mHi\u{1b}[49m"); + assert_eq!(cformat!("<bg:red>Hi</R>"), "\u{1b}[41mHi\u{1b}[49m"); + assert_eq!(cformat!("<bg:red>Hi</>"), "\u{1b}[41mHi\u{1b}[49m"); + + assert_eq!( + cformat!("Hi <bold>word</bold> !"), + "Hi \u{1b}[1mword\u{1b}[22m !" + ); + assert_eq!(cformat!("Hi <em>word</em> !"), "Hi \u{1b}[1mword\u{1b}[22m !"); + assert_eq!(cformat!("Hi <em>word</> !"), "Hi \u{1b}[1mword\u{1b}[22m !"); + + assert_eq!( + cformat!(" + <bold>bold</> + <dim>dim</> + <underline>underline</> + <strike>strike</> + <reverse>reverse</> + <conceal>conceal</> + <italics>italics</> + <blink>blink</> + "), + " + \u{1b}[1mbold\u{1b}[22m + \u{1b}[2mdim\u{1b}[22m + \u{1b}[4munderline\u{1b}[24m + \u{1b}[9mstrike\u{1b}[29m + \u{1b}[7mreverse\u{1b}[27m + \u{1b}[8mconceal\u{1b}[28m + \u{1b}[3mitalics\u{1b}[23m + \u{1b}[5mblink\u{1b}[25m + " + ); + } + + #[test] + #[ignore] + #[cfg(not(feature = "terminfo"))] + fn bold_and_dim_should_be_optimized() { + assert_eq!( + cformat!("<bold>BOLD</><dim>DIM</>"), + "\u{1b}[1mBOLD\u{1b}[2mDIM\u{1b}[22m" + ); + } + + #[test] + #[cfg(not(feature = "terminfo"))] + fn format_multiple() { + assert_eq!( + cformat!("Hi <bold>word</bold> <red>red</red> !"), + "Hi \u{1b}[1mword\u{1b}[22m \u{1b}[31mred\u{1b}[39m !" + ); + } + + #[test] + #[cfg(not(feature = "terminfo"))] + fn format_optimization() { + assert_eq!( + cformat!("<red>RED<blue>BLUE</>RED</>"), + "\u{1b}[31mRED\u{1b}[34mBLUE\u{1b}[31mRED\u{1b}[39m" + ); + assert_eq!( + cformat!("<red><blue>BLUE</>RED</>"), + "\u{1b}[34mBLUE\u{1b}[31mRED\u{1b}[39m" + ); + assert_eq!(cformat!("<red></>Text"), "Text"); + } + + #[test] + #[cfg(not(feature = "terminfo"))] + #[rustfmt::skip] + fn format_auto_close_tag() { + assert_eq!( + cformat!("<red>RED<blue>BLUE"), + "\u{1b}[31mRED\u{1b}[34mBLUE\u{1b}[39m" + ); + assert!( + cformat!("<red>RED<em>BOLD") == "\u{1b}[31mRED\u{1b}[1mBOLD\u{1b}[22m\u{1b}[39m" + || + cformat!("<red>RED<em>BOLD") == "\u{1b}[31mRED\u{1b}[1mBOLD\u{1b}[39m\u{1b}[22m" + ); + } + + #[test] + #[cfg(feature = "terminfo")] + fn terminfo_format_basic() { + assert_eq!(cformat!("<red>Hi</red>"), format!("{}Hi{}", *RED, *CLEAR)); + assert_eq!( + cformat!("Hi <bold>word</bold> !"), + format!("Hi {}word{} !", *BOLD, *CLEAR) + ); + } + + #[test] + #[cfg(feature = "terminfo")] + fn terminfo_format_multiple() { + assert_eq!( + cformat!("Hi <bold>word</bold> <red>red</red> !"), + format!("Hi {}word{} {}red{} !", *BOLD, *CLEAR, *RED, *CLEAR) + ); + } + + #[test] + #[cfg(feature = "terminfo")] + fn terminfo_format_auto_close_tag() { + assert_eq!( + cformat!("<red>RED<blue>BLUE"), + format!("{}RED{}BLUE{}", *RED, *BLUE, *CLEAR) + ); + assert_eq!( + cformat!("<red>RED<em>BOLD"), + format!("{}RED{}BOLD{}", *RED, *BOLD, *CLEAR) + ); + } + + #[test] + fn untagged() { + assert_eq!(untagged!(""), ""); + assert_eq!(untagged!("hi"), "hi"); + assert_eq!(untagged!("<red>hi"), "hi"); + assert_eq!(untagged!("<red>hi</>"), "hi"); + assert_eq!(untagged!("<red>hi <em,blue>all"), "hi all"); + assert_eq!(untagged!("<red>hi <em>all</></>"), "hi all"); + } +} |