1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
use StyledDisplay;
use ToStyledString;
pub use StyledString;
use crateAnsi;
use fmt;
use Deref;
/// Associates a [`Display`](std::fmt::Display) *target* with an [`Ansi`] *style*,
/// such that formatting produces the result of formatting the *target*
/// with the *style's* ANSI codes wrapped around it.
///
/// Instances of `Styled<T>`:
///
/// - are usually created using the [`styled!`](crate::styled!) or
/// [`styled_format_args!`](crate::styled_format_args!) macros.
/// - can be converted to a plain [`String`] with [`to_string`](std::string::ToString::to_string),
/// or by using the [`format!`] macro.
///
/// *Note: this library provides a similarly-named [`StyledString`], which offers the same
/// functionality as `Styled<T>` but wraps a plain [`String`] internally. While this offers
/// more convenience for certain use cases, there is additional runtime overhead.*
///
/// ## Discussion
///
/// At first glance, it may seem this struct is not strictly necessary.
/// Without relying on `Styled<T>`, an [`Ansi`] instance can be converted
/// into a simple ANSI code in the form of a `&'static str` using the
/// [`ansi_code`](crate::ansi_code) macro. For example:
///
/// ```
/// use ansiconst::ansi_code;
///
/// const RED: &str = ansi_code!(Red);
/// const NOT_RED: &str = ansi_code!(Color::reset());
///
/// assert_eq!(RED, "\x1B[31m");
/// assert_eq!(NOT_RED, "\x1B[39m");
///
/// println!("{RED}Hello{NOT_RED}");
/// ```
///
/// However, there are two key advantages of using a `Styled<T>` struct over using
/// ANSI styles in their `&'static str` form:
///
/// ## 1. Automatic Nesting
///
/// Nesting of ANSI styles is *automatically handled*.
/// Specifically, during formatting of nested `Styled<T>` instances, the parent's
/// ANSI style is restored when the child finishes formatting (i.e. by writing
/// into the output any ANSI codes necessary to restore the parent's style).
///
/// By contrast, if a programmer were to use ANSI codes in the form of simple
/// `&'static str`s, that individual would have to manage the nesting transitions
/// manually, which would be unwieldy and potentially error-prone.
///
/// ##### Examples
///
/// ```
/// use ansiconst::{ansi_code, paintln, styled, Styled};
///
/// // -------------------------------
/// // Approach #1: using &'static str
/// // -------------------------------
///
/// const RED: &str = ansi_code!(Red); // "\x1B[31m"
/// const NOT_RED: &str = ansi_code!(Color::reset()); // "\x1B[39m"
/// const GREEN_BOLD: &str = ansi_code!(Green, Bold); // "\x1B[1;32m"
/// const NOT_GREEN_BOLD: &str = ansi_code!(Color::reset(), Bold.not()); // "\x1B[22;39m"
///
/// let inner = format!("{GREEN_BOLD}this is green bold{NOT_GREEN_BOLD}");
/// // Notice how {RED} has to be re-printed after {inner},
/// // because NOT_GREEN_BOLD resets the foreground color.
/// println!("{RED}This is red {inner}{RED} this is red again{NOT_RED}");
///
/// // ----------------------------
/// // Approach #2: using Styled<T>
/// // ----------------------------
///
/// const INNER: Styled<&str> = styled!(Green, Bold, "this is green bold");
/// // Notice how the outer Red is automatically restored after {INNER}
/// paintln!(Red, "This is red {INNER} this is red again");
/// ```
///
/// ## 2. Disabling ANSI
///
/// Nested ANSI styles can be *disabled entirely*, or else have specific ANSI attributes
/// suppressed. This is achieved by using any of this crate's printing/writing/styling macros
/// to style output with an [`Ansi`] style that has [`important`](Ansi::important())
/// attributes set. Under the hood, the macros create an outer [`Styled<Arguments`>]
/// containing an [`Ansi`] with `important` attributes that override those
/// same attributes in any nested `Styled` whose attributes are not `important`.
///
/// ##### Examples
///
/// ```
/// use ansiconst::{Styled, styled, styled_format_args, paintln};
///
/// const RED_MSG: Styled<&str> = styled!(Red, "Hello world!");
///
/// // Prints "\x1B[31mHello world!\x1B[39m\n"
/// println!("{}", RED_MSG);
///
/// // Prints "Hello world!\n"
/// // I.e. ANSI codes are disabled
/// println!("{}", styled_format_args!(Ansi::no_ansi(), "{}", RED_MSG));
///
/// // Prints "Hello world!\n"
/// // I.e. ANSI codes are disabled
/// paintln!(Ansi::no_ansi(), "{}", RED_MSG);
///
/// // Prints "\x1B[34mHello world!\x1B[39m\n"
/// // I.e. in Blue, because outer Blue is important so nested Red is ignored
/// paintln!(Blue.important(), "{}", RED_MSG);
///
/// // --------------------------------------------------
/// // Check the above is correct by capturing the output
/// // --------------------------------------------------
///
/// // Red
/// assert_eq!("\x1B[31mHello world!\x1B[39m",
/// format!("{}", RED_MSG));
///
/// // Plain
/// assert_eq!("Hello world!",
/// styled_format_args!(Ansi::no_ansi(), "{}", RED_MSG).to_string());
///
/// // Blue
/// assert_eq!("\x1B[34mHello world!\x1B[39m",
/// styled_format_args!(Blue.important(), "{}", RED_MSG).to_string());
/// ```
///
/// ## How It Works
///
/// When a `Styled<T>` is formatted, it has no knowledge of whether or
/// not its nested target also contains `Styled<XYZ>` instances that
/// may want to write ANSI codes to the output. And yet, in order to calculate
/// the ANSI codes necessary to transition between parent and child styles,
/// there needs to be some kind of communication of the last-formatted style
/// between the nesting levels.
///
/// Ideally, Rust's standard library would allow specifying a custom [`Formatter`](std::fmt::Formatter)
/// with the ability to hold arbitrary state. This way, it would be possible
/// for a parent `Styled<T>` to pass the current [`Ansi`] style to its children
/// during formatting, so that they could determine the ANSI codes required
/// to handle the transtion from parent style → child style → parent style.
///
/// Since [`Formatter`](std::fmt::Formatter) does not provide this functionality currently,
/// the desired automatic handling of ANSI code transitions for nested `Styled<T>`s
/// is achieved using [`thread_local!`] to pass [`Ansi`] instances between
/// parents and children.
///
/// However, any associated overhead is likely minimal because the only value being
/// stored in [`thread_local!`] is a single [`Ansi`], which is relatively small.
///
/// # Examples
///
/// ```
/// use ansiconst::styled_format_args;
///
/// assert_eq!(
/// styled_format_args!(Red, "Red {} Red",
/// styled_format_args!(Green, "Green {} Green",
/// styled_format_args!(Blue, "Blue")
/// )
/// ).to_string(),
/// "\x1B[31mRed \x1B[32mGreen \x1B[34mBlue\x1B[32m Green\x1B[31m Red\x1B[39m"
/// );
///
/// assert_eq!(
/// styled_format_args!(Italic, "Italic {} Italic",
/// styled_format_args!(Faint, "Both {} Both",
/// styled_format_args!(Italic.not(), "Faint-only")
/// )
/// ).to_string(),
/// "\x1B[3mItalic \x1B[2mBoth \x1B[23mFaint-only\x1B[3m Both\x1B[22m Italic\x1B[23m"
/// );
/// ```