colored_print/lib.rs
1//! This crate provides an easy and concise way to
2//! print colored and styled text to the console using
3//! ANSI escape sequences.
4//!
5//! It provides modified printing and formatting macros
6//! that process colors and styles at compile time:
7//! * `format!` --> `cformat!`
8//! * `println!` --> `cprintln!`
9//! * `print!` --> `cprint!`
10//! * `eprintln!` --> `ceprintln!`
11//! * `eprint!` --> `ceprint!`
12//!
13//! # What makes this crate useful?
14//!
15//! The standard go-to crate for coloring output in a terminal is
16//! the [`colored`](https://crates.io/crates/colored) crate.
17//! However, this crate requires you to use methods on strings
18//! to add colors to them, which can bloat your print and format macro invocations:
19//! ```no_run
20//! use colored::Colorize;
21//!
22//! println!(
23//! "{}",
24//! format!(
25//! "You won {} because the dealer busted with a sum of {}!",
26//! format!("{bet}$").bold(),
27//! dealer_sum.bold()
28//! )
29//! .bright_green()
30//! );
31//! ```
32//!
33//! This library makes using colors and styles a lot more concise:
34//! ```
35//! use colored_print::cprintln;
36//!
37//! cprintln!("%G:You won %b^{bet}$%_^ because the dealer busted with a sum of %b^{dealer_sum}%_^!");
38//! ```
39//!
40//! Albeit, the syntax does look a little confusing.
41//! You'll get used to it, though (probably).
42//!
43//! The alternative [`color-print`](https://crates.io/crates/color-print) crate
44//! is similar to my crate, except it uses XML tags instead.
45//! This syntax does look more readable, however it is a lot longer than
46//! my crate's 3 character syntax.
47//! You can choose whether you prefer concision over slightly poor readability.
48//!
49//! # Syntax Guide
50//! The style escape character is `%` (percent).
51//! It should be followed by a letter indicating the color or style
52//! and then a character indicating your desired action.
53//!
54//! To type a literal `%`, use `%%` (repeat the escape character twice).
55//! To type a literal `%%`, use `%%%%` (you get the point).
56//!
57//! ## Actions
58//! * `:` - Foreground Color (aka Font Color)
59//! * `#` - Background Color
60//! * `^` - Style Effect
61//! * `_` - Wildcard; can clear all styles
62//!
63//! ## Colors
64//! * `k` - Black (Black is 'k', not 'b')
65//! * `r` - Red
66//! * `g` - Green
67//! * `y` - Yellow
68//! * `b` - Blue
69//! * `m` - Magenta
70//! * `c` - Cyan
71//! * `w` - White
72//!
73//! These colors have **bright** variants, which causes the letters to be capitalized:
74//! * `K` - Bright Black (Black is 'K', not 'B')
75//! * `R` - Bright Red
76//! * `G` - Bright Green
77//! * `Y` - Bright Yellow
78//! * `B` - Bright Blue
79//! * `M` - Bright Magenta
80//! * `C` - Bright Cyan
81//! * `W` - Bright White
82//!
83//! To reset the foreground/background color to its original terminal color,
84//! you can use the special `_` character in place of the color character.
85//!
86//! ## Style Effects
87//!
88//! * `b` - **Bold** (makes text stand out)
89//! * `d` - Dim (reduces brightness, less prominent)
90//! * `i` - *Italic* (slanted text for emphasis)
91//! * `u` - <u>Underline</u> (adds line beneath text)
92//! * `s` - ~~Strikethrough~~ (draws line through text)
93//!
94//! These style effects are **stackable**;
95//! you can activate as many as you want at the same time.
96//! To reset them, you can use the special `_` character in place of
97//! the style character which resets/deactivates **all** style effects.
98//!
99//! **Note**: Not all terminals support every style effect. Some common limitations:
100//! * Windows terminals may not support dim or italic.
101//! * Some terminals render italic as inverse video (swapped foreground and background colors).
102//! * Some terminals may not render italic at all.
103//! * Strikethrough is the least widely supported.
104//! * There are more ANSI style effects than available in this library,
105//! but I will not allow things like `blink` for the sanity of end users.
106//!
107//! # Examples
108//!
109//! ### Basic usage
110//! ```
111//! use colored_print::*;
112//!
113//! // Red text
114//! cprintln!("%r:Hello, world!");
115//! // Output: Hello, world! (in red)
116//!
117//! // Green background
118//! ceprintln!("%#gText on green");
119//! // Output (in stderr): Text on green (with green background)
120//!
121//! // Bold blue text
122//! cprint!("%b^%b:Important notice");
123//! // Output (without newline): Important notice (bold blue)
124//! ```
125//!
126//! ### Multiple styles
127//! ```
128//! // Red text on yellow background
129//! cprintln!("%r:%#yWarning!");
130//! // Output: Warning! (red text on yellow background)
131//!
132//! // Bold, underlined cyan
133//! cprintln!("%b^%u^%c:Alert");
134//! // Output: Alert (bold, underlined cyan)
135//! ```
136//!
137//! ### Bright colors
138//! ```
139//! // Bright magenta text
140//! let foo: String = cformat!("%M:Vibrant!");
141//!
142//! // Bright white on bright blue
143//! let bar: String = cformat!("%W:%B#Highlight");
144//! ```
145//!
146//! ### Clearing styles
147//! ```
148//! // Make text red, then clear foreground color
149//! cprintln!("%r:Error%_:Justkidding");
150//! // Output: "Error" in red, then "Justkidding" in default color
151//!
152//! // Note: Since there is no background color or style effects set,
153//! // this is equivalent to clearing all styles in this scenario:
154//! cprintln!("%r:Error%__Justkidding");
155//! ```
156//!
157//! ### Mixing formatted and plain text
158//! ```
159//! ceprint!("Status: %g:OK%_:, %r:FAIL");
160//! // Output (stderr, without newline): "Status: OK, FAIL" (with OK in green, FAIL in red)
161//! ```
162//!
163//! ### Escaping the escape character
164//! ```
165//! cprintln!("10%% discount");
166//! // Output: 10% discount
167//!
168//! cprintln!("Path: %%AppData%%");
169//! // Output: Path: %AppData%
170//! ```
171//!
172//! # Pros of this crate
173//! * Styling is processed entirely at compile time;
174//! there is no runtime overhead at all.
175//! * Short and concise syntax.
176//!
177//! # Cons of this crate
178//! * If the terminal does not support ANSI,
179//! it will most likely print out weird looking arrows:
180//! `←[31mRed Text←[0m`.
181//!
182//! However, the terminal emulator cannot be detected at compile time
183//! since any terminal could run any CLI binary.
184//! Since this library functions purely in compile-time, this is unavoidable.
185//!
186//! On the flip side, most terminals do support ANSI (even modern Windows!).
187//!
188//! # Crate features
189//! There is one opt-in feature available: `no-color`.
190//! When this feature is activated, no ANSI escape sequences will generated,
191//! leading to normal output without any colors or styles.
192//!
193//! Note the following things:
194//! * Your format string still has to be valid, otherwise it will not compile.
195//! * Escape sequences such as `%r:` will not be part of the output, just like in normal mode.
196//! * `%%` will still be needed to output a literal `%`.
197//!
198//! Basically, your format style string should stay the same,
199//! only the generated output is different.
200//!
201//! # Ye end
202//! That's all! If you found a bug, have a feature request or want to improve my code,
203//! feel free to create a GitHub Issue or Pull Request in the
204//! [attached repository](https://github.com/BioTomateDE/ColoredPrint).
205
206#![allow(clippy::negative_feature_names)]
207
208mod editing;
209
210#[cfg_attr(
211 feature = "no-color",
212 allow(dead_code, unused_variables, unused_imports)
213)]
214mod styling;
215
216use editing::format_color_impl;
217use proc_macro::TokenStream;
218
219#[proc_macro]
220pub fn cformat(input: TokenStream) -> TokenStream {
221 format_color_impl(input, "format")
222}
223
224#[proc_macro]
225pub fn cprint(input: TokenStream) -> TokenStream {
226 format_color_impl(input, "print")
227}
228
229#[proc_macro]
230pub fn cprintln(input: TokenStream) -> TokenStream {
231 format_color_impl(input, "println")
232}
233
234#[proc_macro]
235pub fn ceprint(input: TokenStream) -> TokenStream {
236 format_color_impl(input, "eprint")
237}
238
239#[proc_macro]
240pub fn ceprintln(input: TokenStream) -> TokenStream {
241 format_color_impl(input, "eprintln")
242}