| 1 | //! Colorize and stylize strings for terminal at compile-time, by using an HTML-like syntax. |
| 2 | //! |
| 3 | //! This library provides the following macros: |
| 4 | //! |
| 5 | //! - `cformat!(<FORMAT_STRING> [, ARGS...])` |
| 6 | //! - `cprint!(<FORMAT_STRING> [, ARGS...])` |
| 7 | //! - `cprintln!(<FORMAT_STRING> [, ARGS...])` |
| 8 | //! - `ceprint!(<FORMAT_STRING> [, ARGS...])` |
| 9 | //! - `ceprintln!(<FORMAT_STRING> [, ARGS...])` |
| 10 | //! - `cwrite!(f, <FORMAT_STRING> [, ARGS...])` |
| 11 | //! - `cwriteln!(f, <FORMAT_STRING> [, ARGS...])` |
| 12 | //! - `cstr!(<FORMAT_STRING>)` |
| 13 | //! - `untagged!(<FORMAT_STRING>)` |
| 14 | //! |
| 15 | //! The macros have the same syntax as their corresponding [`std`] variants: |
| 16 | //! - [`cformat!()`] as [`format!()`] |
| 17 | //! - [`cprint!()`] as [`print!()`] |
| 18 | //! - [`cprintln!()`] as [`println!()`] |
| 19 | //! - [`ceprint!()`] as [`eprint!()`] |
| 20 | //! - [`ceprintln!()`] as [`eprintln!()`] |
| 21 | //! - [`cwrite!()`] as [`write!()`] |
| 22 | //! - [`cwriteln!()`] as [`writeln!()`] |
| 23 | //! |
| 24 | //! But they accept an additional syntax inside the |
| 25 | //! format string: HTML-like tags which add ANSI colors/styles at compile-time. |
| 26 | //! |
| 27 | //! [`cstr!()`] only transforms the given string literal into another string literal, without |
| 28 | //! formatting anything else than the colors tag. |
| 29 | //! |
| 30 | //! [`untagged!()`] removes all the tags found in the given string literal. |
| 31 | //! |
| 32 | //! ## What does it do ? |
| 33 | //! |
| 34 | //! By default, the provided macros will replace the tags found in the format string by ANSI |
| 35 | //! hexadecimal escape codes. E.g.: |
| 36 | //! |
| 37 | //! ``` |
| 38 | //! # use color_print::cprintln; |
| 39 | //! # fn main() { |
| 40 | //! cprintln!("HELLO <green>WORLD</green>" ); |
| 41 | //! cprintln!("HELLO <green>WORLD</>" ); // Alternative, shorter syntax |
| 42 | //! # } |
| 43 | //! ``` |
| 44 | //! |
| 45 | //! will be replaced by: |
| 46 | //! |
| 47 | //! ``` |
| 48 | //! # use color_print::cprintln; |
| 49 | //! # fn main() { |
| 50 | //! println!("HELLO \u{1b}[31mWORLD \u{1b}[39m" ) |
| 51 | //! # } |
| 52 | //! ``` |
| 53 | //! |
| 54 | //! *Note*: it is possible to change this behaviour by activating the feature `terminfo`. Then it |
| 55 | //! will question the `terminfo` database at runtime in order to know which sequence to write for |
| 56 | //! each kind of styling/colorizing (see below for more detail). |
| 57 | //! |
| 58 | //! # Pros/cons of this crate |
| 59 | //! |
| 60 | //! ## Pros |
| 61 | //! |
| 62 | //! * Styling is processed at compile-time, so the runtime payload is inexistant (unless the |
| 63 | //! feature `terminfo` is activated); |
| 64 | //! * Nested tags are well handled, e.g. `"<green>...<blue>...</blue>...</green>"`; |
| 65 | //! * Some optimizations are performed to avoid redundant ANSI sequences, because these |
| 66 | //! optimizations can be done at compile-time without impacting the runtime; |
| 67 | //! * Almost every tag has a short name, so colorizing can be done quickly: `"my <b>blue</> word"`; |
| 68 | //! * Each provided macro can be used exactly in the same way as the standard `format!`-like |
| 69 | //! macros; e.g., positional arguments and named arguments can be used as usual; |
| 70 | //! * Supports 16, 256 and 16M colors; |
| 71 | //! * Fine-grained error handling (errors will be given at compile-time). |
| 72 | //! |
| 73 | //! ## Cons |
| 74 | //! |
| 75 | //! * Not compatible with non-ANSI terminals. |
| 76 | //! |
| 77 | //! # Introduction |
| 78 | //! |
| 79 | //! ## Basic example |
| 80 | //! |
| 81 | //! ``` |
| 82 | //! use color_print::cprintln; |
| 83 | //! cprintln!("Hello <green>world</green>!" ); |
| 84 | //! ``` |
| 85 | //! |
| 86 | //! ## Closing a tag more simply: the `</>` tag |
| 87 | //! |
| 88 | //! Basically, tags must be closed by giving *exactly* the same colors/styles as their matching |
| 89 | //! open tag (with a slash `/` at the beginning), e.g: `<blue,bold>...</blue,bold>`. But it can be |
| 90 | //! tedious! |
| 91 | //! |
| 92 | //! So, it is also possible to close the last open tag simply with `</>`: |
| 93 | //! |
| 94 | //! ``` |
| 95 | //! # use color_print::cprintln; |
| 96 | //! # fn main() { |
| 97 | //! cprintln!("Hello <green>world</>!" ); |
| 98 | //! # } |
| 99 | //! ``` |
| 100 | //! |
| 101 | //! ## Combining colors and styles |
| 102 | //! |
| 103 | //! Multiple styles and colors can be combined into a single tag by separating them with the `,` |
| 104 | //! comma character: |
| 105 | //! |
| 106 | //! ``` |
| 107 | //! # use color_print::cprintln; |
| 108 | //! # fn main() { |
| 109 | //! cprintln!("This a <green,bold>green and bold text</green,bold>." ); |
| 110 | //! // The same, but closing with the </> tag: |
| 111 | //! cprintln!("This a <green,bold>green and bold text</>." ); |
| 112 | //! # } |
| 113 | //! ``` |
| 114 | //! |
| 115 | //! ## Nesting tags |
| 116 | //! |
| 117 | //! Any tag can be nested with any other. |
| 118 | //! |
| 119 | //! *Note*: The closing tags must match correctly (following the basic rules of nesting for HTML |
| 120 | //! tags), but it can always be simplified by using the tag `</>`. |
| 121 | //! |
| 122 | //! Example of nested tags: |
| 123 | //! |
| 124 | //! ``` |
| 125 | //! # use color_print::cprintln; |
| 126 | //! # fn main() { |
| 127 | //! cprintln!("<green>This is green, <bold>then green and bold</bold>, then green again</green>" ); |
| 128 | //! cprintln!("<green>This is green, <bold>then green and bold</>, then green again</>" ); |
| 129 | //! |
| 130 | //! // Colors can be nested as well: |
| 131 | //! cprintln!("<green>This is green, <blue>then blue</blue>, then green again</green>" ); |
| 132 | //! cprintln!("<green>This is green, <blue>then blue</>, then green again</>" ); |
| 133 | //! # } |
| 134 | //! ``` |
| 135 | //! |
| 136 | //! ## Unclosed tags are automatically closed at the end of the format string |
| 137 | //! |
| 138 | //! Tags which have not been closed manually will be closed automatically, which means that the |
| 139 | //! ANSI sequences needed to go back to the original state will be added: |
| 140 | //! |
| 141 | //! ``` |
| 142 | //! # use color_print::cprintln; |
| 143 | //! # fn main() { |
| 144 | //! // The two following lines are strictly equivalent: |
| 145 | //! cprintln!("<green><bold>Hello" ); |
| 146 | //! cprintln!("<green><bold>Hello</></>" ); |
| 147 | //! # } |
| 148 | //! ``` |
| 149 | //! |
| 150 | //! ## How to display the chars `<` and `>` verbatim |
| 151 | //! |
| 152 | //! As for `{` and `}` in standard format strings, the chars `<` and `>` have to be doubled in |
| 153 | //! order to display them verbatim: |
| 154 | //! |
| 155 | //! ``` |
| 156 | //! # use color_print::cprintln; |
| 157 | //! # fn main() { |
| 158 | //! cprintln!("This is an angle bracket character: <<, and here is another one: >>" ); |
| 159 | //! # } |
| 160 | //! ``` |
| 161 | //! |
| 162 | //! # Optimization: no redundant ANSI codes |
| 163 | //! |
| 164 | //! The expanded format string will only contain the *needed* ANSI codes. This is done by making a |
| 165 | //! diff of the different style attributes, each time a tag is encountered, instead of mechanically |
| 166 | //! adding the ANSI codes. |
| 167 | //! |
| 168 | //! E.g., several nested `<bold>` tags will only produce one bold ANSI sequence: |
| 169 | //! |
| 170 | //! ``` |
| 171 | //! # use color_print::cprintln; |
| 172 | //! # fn main() { |
| 173 | //! cprintln!("<bold><bold> A <bold,blue> B </> C </></>" ) |
| 174 | //! # } |
| 175 | //! ``` |
| 176 | //! |
| 177 | //! will be replaced by: |
| 178 | //! |
| 179 | //! ``` |
| 180 | //! # use color_print::cprintln; |
| 181 | //! # fn main() { |
| 182 | //! println!(" \u{1b}[1m A \u{1b}[34m B \u{1b}[39m C \u{1b}[22m" ) |
| 183 | //! // ^-------^ ^--------^ ^--------^ ^--------^ |
| 184 | //! // bold blue color bold |
| 185 | //! // reset reset |
| 186 | //! # } |
| 187 | //! ``` |
| 188 | //! |
| 189 | //! # The feature `terminfo` |
| 190 | //! |
| 191 | //! Instead of inserting ANSI sequences directly into the format string, it is possible to activate |
| 192 | //! the feature `terminfo`: this will add the format sequences at runtime, by consulting the |
| 193 | //! `terminfo` database. |
| 194 | //! |
| 195 | //! This has one pro and several cons: |
| 196 | //! |
| 197 | //! #### Pros |
| 198 | //! |
| 199 | //! * This adds a level of compatibility for some terminals. |
| 200 | //! |
| 201 | //! #### Cons |
| 202 | //! |
| 203 | //! * This adds a little runtime payload; |
| 204 | //! * This adds two dependencies: [`lazy_static`] and [`terminfo`]; |
| 205 | //! * The styles `<strike>` and `<conceal>` are not handled; |
| 206 | //! * With `terminfo`, many styles are not resettable individually, which implies longer format |
| 207 | //! sequences for the same result; |
| 208 | //! * For now, the provided macros can only be used in one thread. |
| 209 | //! |
| 210 | //! [`lazy_static`]: https://crates.io/crates/lazy_static |
| 211 | //! [`terminfo`]: https://crates.io/crates/terminfo |
| 212 | //! |
| 213 | //! # Naming rules of the tags: |
| 214 | //! |
| 215 | //! Each tag has at least a **long name**, like `<magenta>` or `<underline>`. |
| 216 | //! |
| 217 | //! The tags directly relative to *colors* (like `<red>`, `<bg:blue>`, `<bg:bright-green>`..., as |
| 218 | //! opposed to *style* tags like `<bold>`, `<italics>`...) have some common naming rules: |
| 219 | //! |
| 220 | //! * Each tag has four variants: |
| 221 | //! - `<mycolor>`: the normal, foreground color; |
| 222 | //! - `<bright-mycolor>` or `<mycolor!>`: the bright, foreground color; |
| 223 | //! - `<bg:mycolor>`, `<MYCOLOR>`: the normal, background color; |
| 224 | //! - `<bg:bright-mycolor>`, `<bg:mycolor!>`, `<BRIGHT-MYCOLOR>` or `<MYCOLOR!>`: the bright, |
| 225 | //! background color; |
| 226 | //! * Each tag has a *shortcut*, with a base letter for each color; example with the `x` letter: |
| 227 | //! - `<x>`: the normal, foreground color; |
| 228 | //! - `<x!>`: the bright, foreground color; |
| 229 | //! - `<bg:x>`, `<X>`: the normal, background color; |
| 230 | //! - `<bg:x!>`, `<X!>`: the bright, background color; |
| 231 | //! * Each color's shortcut letter is simply the **first letter of its name** (excepted for `<k>` |
| 232 | //! which is the shortcut for `<black>`), e.g. `<y>` is the shortcut for `<yellow>`; |
| 233 | //! * Each color's tag which is uppercase is a **background color**; |
| 234 | //! * Each tag which has a trailing exclamation point `!` is a **bright color**; |
| 235 | //! |
| 236 | //! # List of accepted tags: |
| 237 | //! |
| 238 | //! The two first columns show which styles are supported, respectively with the default crate |
| 239 | //! features (ANSI column), and with the feature `terminfo` being activated. |
| 240 | //! |
| 241 | //! | ANSI | Terminfo | Shortcuts | Long names | Aliases | |
| 242 | //! | ---- | -------- | --------- | ----------------------- | ----------------------------------------------- | |
| 243 | //! | X | X | `<s>` | `<strong>` | `<em>` `<bold>` | |
| 244 | //! | X | X | | `<dim>` | | |
| 245 | //! | X | X | `<u>` | `<underline>` | | |
| 246 | //! | X | | | `<strike>` | | |
| 247 | //! | X | X | | `<reverse>` | `<rev>` | |
| 248 | //! | X | | | `<conceal>` | `<hide>` | |
| 249 | //! | X | X | `<i>` | `<italics>` | `<italic>` | |
| 250 | //! | X | X | | `<blink>` | | |
| 251 | //! | X | X | `<k>` | `<black>` | | |
| 252 | //! | X | X | `<r>` | `<red>` | | |
| 253 | //! | X | X | `<g>` | `<green>` | | |
| 254 | //! | X | X | `<y>` | `<yellow>` | | |
| 255 | //! | X | X | `<b>` | `<blue>` | | |
| 256 | //! | X | X | `<m>` | `<magenta>` | | |
| 257 | //! | X | X | `<c>` | `<cyan>` | | |
| 258 | //! | X | X | `<w>` | `<white>` | | |
| 259 | //! | X | X | `<k!>` | `<bright-black>` | `<black!>` | |
| 260 | //! | X | X | `<r!>` | `<bright-red>` | `<red!>` | |
| 261 | //! | X | X | `<g!>` | `<bright-green>` | `<green!>` | |
| 262 | //! | X | X | `<y!>` | `<bright-yellow>` | `<yellow!>` | |
| 263 | //! | X | X | `<b!>` | `<bright-blue>` | `<blue!>` | |
| 264 | //! | X | X | `<m!>` | `<bright-magenta>` | `<magenta!>` | |
| 265 | //! | X | X | `<c!>` | `<bright-cyan>` | `<cyan!>` | |
| 266 | //! | X | X | `<w!>` | `<bright-white>` | `<white!>` | |
| 267 | //! | X | X | `<K>` | `<bg:black>` | `<BLACK>` | |
| 268 | //! | X | X | `<R>` | `<bg:red>` | `<RED>` | |
| 269 | //! | X | X | `<G>` | `<bg:green>` | `<GREEN>` | |
| 270 | //! | X | X | `<Y>` | `<bg:yellow>` | `<YELLOW>` | |
| 271 | //! | X | X | `<B>` | `<bg:blue>` | `<BLUE>` | |
| 272 | //! | X | X | `<M>` | `<bg:magenta>` | `<MAGENTA>` | |
| 273 | //! | X | X | `<C>` | `<bg:cyan>` | `<CYAN>` | |
| 274 | //! | X | X | `<W>` | `<bg:white>` | `<WHITE>` | |
| 275 | //! | X | X | `<K!>` | `<bg:bright-black>` | `<BLACK!>` `<bg:black!>` `<BRIGHT-BLACK>` | |
| 276 | //! | X | X | `<R!>` | `<bg:bright-red>` | `<RED!>` `<bg:red!>` `<BRIGHT-RED>` | |
| 277 | //! | X | X | `<G!>` | `<bg:bright-green>` | `<GREEN!>` `<bg:green!>` `<BRIGHT-GREEN>` | |
| 278 | //! | X | X | `<Y!>` | `<bg:bright-yellow>` | `<YELLOW!>` `<bg:yellow!>` `<BRIGHT-YELLOW>` | |
| 279 | //! | X | X | `<B!>` | `<bg:bright-blue>` | `<BLUE!>` `<bg:blue!>` `<BRIGHT-BLUE>` | |
| 280 | //! | X | X | `<M!>` | `<bg:bright-magenta>` | `<MAGENTA!>` `<bg:magenta!>` `<BRIGHT-MAGENTA>` | |
| 281 | //! | X | X | `<C!>` | `<bg:bright-cyan>` | `<CYAN!>` `<bg:cyan!>` `<BRIGHT-CYAN>` | |
| 282 | //! | X | X | `<W!>` | `<bg:bright-white>` | `<WHITE!>` `<bg:white!>` `<BRIGHT-WHITE>` | |
| 283 | //! | X | | | `<rgb(r,g,b)>` | `<#RRGGBB>` | |
| 284 | //! | X | | | `<bg:rgb(r,g,b)>` | `<bg:#RRGGBB>` `<RGB(r,g,b)>` | |
| 285 | //! | X | | `<0>`...`<255>` | `<palette(...)>` | `<p(...)>` `<pal(...)>` | |
| 286 | //! | X | | `<P(...)>` | `<bg:palette(...)>` | `<PALETTE(...)>` `<PAL(...)>` `<bg:p(...)>` `<bg:pal(...)>` | |
| 287 | |
| 288 | pub use color_print_proc_macro::{ |
| 289 | ceprint, ceprintln, cformat, cprint, cprintln, cstr, cwrite, cwriteln, untagged, |
| 290 | }; |
| 291 | |
| 292 | #[cfg (feature = "terminfo" )] |
| 293 | mod terminfo; |
| 294 | #[cfg (feature = "terminfo" )] |
| 295 | pub use terminfo::*; |
| 296 | |
| 297 | #[cfg (test)] |
| 298 | mod tests { |
| 299 | use std::fmt::Write as _; |
| 300 | |
| 301 | use super::*; |
| 302 | |
| 303 | #[cfg (feature = "terminfo" )] |
| 304 | pub mod color_print { |
| 305 | pub use super::*; |
| 306 | } |
| 307 | |
| 308 | #[test ] |
| 309 | fn format_no_arg() { |
| 310 | assert_eq!(cformat!(), "" ); |
| 311 | cprint!(); |
| 312 | cprintln!(); |
| 313 | } |
| 314 | |
| 315 | #[test ] |
| 316 | fn format_no_color() { |
| 317 | assert_eq!(cformat!("" ), "" ); |
| 318 | assert_eq!(cformat!("Hi" ), "Hi" ); |
| 319 | assert_eq!(cformat!("Hi {}" , 12), "Hi 12" ); |
| 320 | assert_eq!(cformat!("Hi {n} {}" , 12, n = 24), "Hi 24 12" ); |
| 321 | |
| 322 | let mut s = String::new(); |
| 323 | cwrite!(&mut s, "" ).unwrap(); |
| 324 | assert_eq!(s, "" ); |
| 325 | |
| 326 | let mut s = String::new(); |
| 327 | cwrite!(&mut s, "Hi" ).unwrap(); |
| 328 | assert_eq!(s, "Hi" ); |
| 329 | |
| 330 | let mut s = String::new(); |
| 331 | cwrite!(&mut s, "Hi {}" , 12).unwrap(); |
| 332 | assert_eq!(s, "Hi 12" ); |
| 333 | |
| 334 | let mut s = String::new(); |
| 335 | cwrite!(&mut s, "Hi {n} {}" , 12, n = 24).unwrap(); |
| 336 | assert_eq!(s, "Hi 24 12" ); |
| 337 | } |
| 338 | |
| 339 | #[test ] |
| 340 | #[cfg (not(feature = "terminfo" ))] |
| 341 | #[rustfmt::skip] |
| 342 | fn format_basic() { |
| 343 | assert_eq!(cformat!("<red>Hi</red>" ), " \u{1b}[31mHi \u{1b}[39m" ); |
| 344 | assert_eq!(cformat!("<red>Hi</r>" ), " \u{1b}[31mHi \u{1b}[39m" ); |
| 345 | assert_eq!(cformat!("<red>Hi</>" ), " \u{1b}[31mHi \u{1b}[39m" ); |
| 346 | |
| 347 | assert_eq!(cformat!("<bg:red>Hi</bg:red>" ), " \u{1b}[41mHi \u{1b}[49m" ); |
| 348 | assert_eq!(cformat!("<bg:red>Hi</R>" ), " \u{1b}[41mHi \u{1b}[49m" ); |
| 349 | assert_eq!(cformat!("<bg:red>Hi</>" ), " \u{1b}[41mHi \u{1b}[49m" ); |
| 350 | |
| 351 | assert_eq!( |
| 352 | cformat!("Hi <bold>word</bold> !" ), |
| 353 | "Hi \u{1b}[1mword \u{1b}[22m !" |
| 354 | ); |
| 355 | assert_eq!(cformat!("Hi <em>word</em> !" ), "Hi \u{1b}[1mword \u{1b}[22m !" ); |
| 356 | assert_eq!(cformat!("Hi <em>word</> !" ), "Hi \u{1b}[1mword \u{1b}[22m !" ); |
| 357 | |
| 358 | assert_eq!( |
| 359 | cformat!(" |
| 360 | <bold>bold</> |
| 361 | <dim>dim</> |
| 362 | <underline>underline</> |
| 363 | <strike>strike</> |
| 364 | <reverse>reverse</> |
| 365 | <conceal>conceal</> |
| 366 | <italics>italics</> |
| 367 | <blink>blink</> |
| 368 | " ), |
| 369 | " |
| 370 | \u{1b}[1mbold \u{1b}[22m |
| 371 | \u{1b}[2mdim \u{1b}[22m |
| 372 | \u{1b}[4munderline \u{1b}[24m |
| 373 | \u{1b}[9mstrike \u{1b}[29m |
| 374 | \u{1b}[7mreverse \u{1b}[27m |
| 375 | \u{1b}[8mconceal \u{1b}[28m |
| 376 | \u{1b}[3mitalics \u{1b}[23m |
| 377 | \u{1b}[5mblink \u{1b}[25m |
| 378 | " |
| 379 | ); |
| 380 | |
| 381 | let mut s = String::new(); |
| 382 | cwrite!(&mut s, "Hi <r>{v}</> {}" , 12, v = "Hi" ).unwrap(); |
| 383 | assert_eq!(s, "Hi \u{1b}[31mHi \u{1b}[39m 12" ); |
| 384 | |
| 385 | let mut s = String::new(); |
| 386 | cwriteln!(&mut s, "Hi <r>{v} {}" , 12, v = "Hi" ).unwrap(); |
| 387 | assert_eq!(s, "Hi \u{1b}[31mHi 12 \u{1b}[39m \n" ); |
| 388 | } |
| 389 | |
| 390 | #[test ] |
| 391 | #[ignore ] |
| 392 | #[cfg (not(feature = "terminfo" ))] |
| 393 | fn bold_and_dim_should_be_optimized() { |
| 394 | assert_eq!( |
| 395 | cformat!("<bold>BOLD</><dim>DIM</>" ), |
| 396 | " \u{1b}[1mBOLD \u{1b}[2mDIM \u{1b}[22m" |
| 397 | ); |
| 398 | } |
| 399 | |
| 400 | #[test ] |
| 401 | #[cfg (not(feature = "terminfo" ))] |
| 402 | fn format_multiple() { |
| 403 | assert_eq!( |
| 404 | cformat!("Hi <bold>word</bold> <red>red</red> !" ), |
| 405 | "Hi \u{1b}[1mword \u{1b}[22m \u{1b}[31mred \u{1b}[39m !" |
| 406 | ); |
| 407 | } |
| 408 | |
| 409 | #[test ] |
| 410 | #[cfg (not(feature = "terminfo" ))] |
| 411 | fn format_optimization() { |
| 412 | assert_eq!( |
| 413 | cformat!("<red>RED<blue>BLUE</>RED</>" ), |
| 414 | " \u{1b}[31mRED \u{1b}[34mBLUE \u{1b}[31mRED \u{1b}[39m" |
| 415 | ); |
| 416 | assert_eq!( |
| 417 | cformat!("<red><blue>BLUE</>RED</>" ), |
| 418 | " \u{1b}[34mBLUE \u{1b}[31mRED \u{1b}[39m" |
| 419 | ); |
| 420 | assert_eq!(cformat!("<red></>Text" ), "Text" ); |
| 421 | } |
| 422 | |
| 423 | #[test ] |
| 424 | #[cfg (not(feature = "terminfo" ))] |
| 425 | #[rustfmt::skip] |
| 426 | fn format_auto_close_tag() { |
| 427 | assert_eq!( |
| 428 | cformat!("<red>RED<blue>BLUE" ), |
| 429 | " \u{1b}[31mRED \u{1b}[34mBLUE \u{1b}[39m" |
| 430 | ); |
| 431 | assert!( |
| 432 | cformat!("<red>RED<em>BOLD" ) == " \u{1b}[31mRED \u{1b}[1mBOLD \u{1b}[22m \u{1b}[39m" |
| 433 | || |
| 434 | cformat!("<red>RED<em>BOLD" ) == " \u{1b}[31mRED \u{1b}[1mBOLD \u{1b}[39m \u{1b}[22m" |
| 435 | ); |
| 436 | } |
| 437 | |
| 438 | #[test ] |
| 439 | #[cfg (feature = "terminfo" )] |
| 440 | fn terminfo_format_basic() { |
| 441 | assert_eq!(cformat!("<red>Hi</red>" ), format!("{}Hi{}" , *RED, *CLEAR)); |
| 442 | assert_eq!( |
| 443 | cformat!("Hi <bold>word</bold> !" ), |
| 444 | format!("Hi {}word{} !" , *BOLD, *CLEAR) |
| 445 | ); |
| 446 | |
| 447 | let mut s = String::new(); |
| 448 | cwrite!(&mut s, "<r>Hi</> {}" , 12).unwrap(); |
| 449 | assert_eq!(s, format!("{}Hi{} 12" , *RED, *CLEAR)); |
| 450 | } |
| 451 | |
| 452 | #[test ] |
| 453 | #[cfg (feature = "terminfo" )] |
| 454 | fn terminfo_format_multiple() { |
| 455 | assert_eq!( |
| 456 | cformat!("Hi <bold>word</bold> <red>red</red> !" ), |
| 457 | format!("Hi {}word{} {}red{} !" , *BOLD, *CLEAR, *RED, *CLEAR) |
| 458 | ); |
| 459 | } |
| 460 | |
| 461 | #[test ] |
| 462 | #[cfg (feature = "terminfo" )] |
| 463 | fn terminfo_format_auto_close_tag() { |
| 464 | assert_eq!( |
| 465 | cformat!("<red>RED<blue>BLUE" ), |
| 466 | format!("{}RED{}BLUE{}" , *RED, *BLUE, *CLEAR) |
| 467 | ); |
| 468 | assert_eq!( |
| 469 | cformat!("<red>RED<em>BOLD" ), |
| 470 | format!("{}RED{}BOLD{}" , *RED, *BOLD, *CLEAR) |
| 471 | ); |
| 472 | } |
| 473 | |
| 474 | #[test ] |
| 475 | fn untagged() { |
| 476 | assert_eq!(untagged!("" ), "" ); |
| 477 | assert_eq!(untagged!("hi" ), "hi" ); |
| 478 | assert_eq!(untagged!("<red>hi" ), "hi" ); |
| 479 | assert_eq!(untagged!("<red>hi</>" ), "hi" ); |
| 480 | assert_eq!(untagged!("<red>hi <em,blue>all" ), "hi all" ); |
| 481 | assert_eq!(untagged!("<red>hi <em>all</></>" ), "hi all" ); |
| 482 | } |
| 483 | } |
| 484 | |