1 | //! # Style
|
2 | //!
|
3 | //! The `style` module provides a functionality to apply attributes and colors on your text.
|
4 | //!
|
5 | //! This documentation does not contain a lot of examples. The reason is that it's fairly
|
6 | //! obvious how to use this crate. Although, we do provide
|
7 | //! [examples](https://github.com/crossterm-rs/crossterm/tree/master/examples) repository
|
8 | //! to demonstrate the capabilities.
|
9 | //!
|
10 | //! ## Platform-specific Notes
|
11 | //!
|
12 | //! Not all features are supported on all terminals/platforms. You should always consult
|
13 | //! platform-specific notes of the following types:
|
14 | //!
|
15 | //! * [Color](enum.Color.html#platform-specific-notes)
|
16 | //! * [Attribute](enum.Attribute.html#platform-specific-notes)
|
17 | //!
|
18 | //! ## Examples
|
19 | //!
|
20 | //! A few examples of how to use the style module.
|
21 | //!
|
22 | //! ### Colors
|
23 | //!
|
24 | //! How to change the terminal text color.
|
25 | //!
|
26 | //! Command API:
|
27 | //!
|
28 | //! Using the Command API to color text.
|
29 | //!
|
30 | //! ```no_run
|
31 | //! use std::io::{self, Write};
|
32 | //! use crossterm::execute;
|
33 | //! use crossterm::style::{Print, SetForegroundColor, SetBackgroundColor, ResetColor, Color, Attribute};
|
34 | //!
|
35 | //! fn main() -> io::Result<()> {
|
36 | //! execute!(
|
37 | //! io::stdout(),
|
38 | //! // Blue foreground
|
39 | //! SetForegroundColor(Color::Blue),
|
40 | //! // Red background
|
41 | //! SetBackgroundColor(Color::Red),
|
42 | //! // Print text
|
43 | //! Print("Blue text on Red." .to_string()),
|
44 | //! // Reset to default colors
|
45 | //! ResetColor
|
46 | //! )
|
47 | //! }
|
48 | //! ```
|
49 | //!
|
50 | //! Functions:
|
51 | //!
|
52 | //! Using functions from [`Stylize`](crate::style::Stylize) on a `String` or `&'static str` to color
|
53 | //! it.
|
54 | //!
|
55 | //! ```no_run
|
56 | //! use crossterm::style::Stylize;
|
57 | //!
|
58 | //! println!("{}" , "Red foreground color & blue background." .red().on_blue());
|
59 | //! ```
|
60 | //!
|
61 | //! ### Attributes
|
62 | //!
|
63 | //! How to apply terminal attributes to text.
|
64 | //!
|
65 | //! Command API:
|
66 | //!
|
67 | //! Using the Command API to set attributes.
|
68 | //!
|
69 | //! ```no_run
|
70 | //! use std::io::{self, Write};
|
71 | //!
|
72 | //! use crossterm::execute;
|
73 | //! use crossterm::style::{Attribute, Print, SetAttribute};
|
74 | //!
|
75 | //! fn main() -> io::Result<()> {
|
76 | //! execute!(
|
77 | //! io::stdout(),
|
78 | //! // Set to bold
|
79 | //! SetAttribute(Attribute::Bold),
|
80 | //! Print("Bold text here." .to_string()),
|
81 | //! // Reset all attributes
|
82 | //! SetAttribute(Attribute::Reset)
|
83 | //! )
|
84 | //! }
|
85 | //! ```
|
86 | //!
|
87 | //! Functions:
|
88 | //!
|
89 | //! Using [`Stylize`](crate::style::Stylize) functions on a `String` or `&'static str` to set
|
90 | //! attributes to it.
|
91 | //!
|
92 | //! ```no_run
|
93 | //! use crossterm::style::Stylize;
|
94 | //!
|
95 | //! println!("{}" , "Bold" .bold());
|
96 | //! println!("{}" , "Underlined" .underlined());
|
97 | //! println!("{}" , "Negative" .negative());
|
98 | //! ```
|
99 | //!
|
100 | //! Displayable:
|
101 | //!
|
102 | //! [`Attribute`](enum.Attribute.html) implements [Display](https://doc.rust-lang.org/beta/std/fmt/trait.Display.html) and therefore it can be formatted like:
|
103 | //!
|
104 | //! ```no_run
|
105 | //! use crossterm::style::Attribute;
|
106 | //!
|
107 | //! println!(
|
108 | //! "{} Underlined {} No Underline" ,
|
109 | //! Attribute::Underlined,
|
110 | //! Attribute::NoUnderline
|
111 | //! );
|
112 | //! ```
|
113 |
|
114 | use std::{
|
115 | env,
|
116 | fmt::{self, Display},
|
117 | };
|
118 |
|
119 | use crate::command::execute_fmt;
|
120 | use crate::{csi, impl_display, Command};
|
121 |
|
122 | pub use self::{
|
123 | attributes::Attributes,
|
124 | content_style::ContentStyle,
|
125 | styled_content::StyledContent,
|
126 | stylize::Stylize,
|
127 | types::{Attribute, Color, Colored, Colors},
|
128 | };
|
129 |
|
130 | mod attributes;
|
131 | mod content_style;
|
132 | mod styled_content;
|
133 | mod stylize;
|
134 | mod sys;
|
135 | mod types;
|
136 |
|
137 | /// Creates a `StyledContent`.
|
138 | ///
|
139 | /// This could be used to style any type that implements `Display` with colors and text attributes.
|
140 | ///
|
141 | /// See [`StyledContent`](struct.StyledContent.html) for more info.
|
142 | ///
|
143 | /// # Examples
|
144 | ///
|
145 | /// ```no_run
|
146 | /// use crossterm::style::{style, Stylize, Color};
|
147 | ///
|
148 | /// let styled_content = style("Blue colored text on yellow background" )
|
149 | /// .with(Color::Blue)
|
150 | /// .on(Color::Yellow);
|
151 | ///
|
152 | /// println!("{}" , styled_content);
|
153 | /// ```
|
154 | pub fn style<D: Display>(val: D) -> StyledContent<D> {
|
155 | ContentStyle::new().apply(val)
|
156 | }
|
157 |
|
158 | /// Returns available color count.
|
159 | ///
|
160 | /// # Notes
|
161 | ///
|
162 | /// This does not always provide a good result.
|
163 | pub fn available_color_count() -> u16 {
|
164 | env::var("TERM" )
|
165 | .map(|x| if x.contains("256color" ) { 256 } else { 8 })
|
166 | .unwrap_or(default:8)
|
167 | }
|
168 |
|
169 | /// Forces colored output on or off globally, overriding NO_COLOR.
|
170 | ///
|
171 | /// # Notes
|
172 | ///
|
173 | /// crossterm supports NO_COLOR (https://no-color.org/) to disabled colored output.
|
174 | ///
|
175 | /// This API allows applications to override that behavior and force colorized output
|
176 | /// even if NO_COLOR is set.
|
177 | pub fn force_color_output(enabled: bool) {
|
178 | Colored::set_ansi_color_disabled(!enabled)
|
179 | }
|
180 |
|
181 | /// A command that sets the the foreground color.
|
182 | ///
|
183 | /// See [`Color`](enum.Color.html) for more info.
|
184 | ///
|
185 | /// [`SetColors`](struct.SetColors.html) can also be used to set both the foreground and background
|
186 | /// color in one command.
|
187 | ///
|
188 | /// # Notes
|
189 | ///
|
190 | /// Commands must be executed/queued for execution otherwise they do nothing.
|
191 | #[derive (Debug, Clone, Copy, PartialEq, Eq)]
|
192 | pub struct SetForegroundColor(pub Color);
|
193 |
|
194 | impl Command for SetForegroundColor {
|
195 | fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
196 | write!(f, csi!("{}m" ), Colored::ForegroundColor(self.0))
|
197 | }
|
198 |
|
199 | #[cfg (windows)]
|
200 | fn execute_winapi(&self) -> std::io::Result<()> {
|
201 | sys::windows::set_foreground_color(self.0)
|
202 | }
|
203 | }
|
204 |
|
205 | /// A command that sets the the background color.
|
206 | ///
|
207 | /// See [`Color`](enum.Color.html) for more info.
|
208 | ///
|
209 | /// [`SetColors`](struct.SetColors.html) can also be used to set both the foreground and background
|
210 | /// color with one command.
|
211 | ///
|
212 | /// # Notes
|
213 | ///
|
214 | /// Commands must be executed/queued for execution otherwise they do nothing.
|
215 | #[derive (Debug, Clone, Copy, PartialEq, Eq)]
|
216 | pub struct SetBackgroundColor(pub Color);
|
217 |
|
218 | impl Command for SetBackgroundColor {
|
219 | fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
220 | write!(f, csi!("{}m" ), Colored::BackgroundColor(self.0))
|
221 | }
|
222 |
|
223 | #[cfg (windows)]
|
224 | fn execute_winapi(&self) -> std::io::Result<()> {
|
225 | sys::windows::set_background_color(self.0)
|
226 | }
|
227 | }
|
228 |
|
229 | /// A command that sets the the underline color.
|
230 | ///
|
231 | /// See [`Color`](enum.Color.html) for more info.
|
232 | ///
|
233 | /// [`SetColors`](struct.SetColors.html) can also be used to set both the foreground and background
|
234 | /// color with one command.
|
235 | ///
|
236 | /// # Notes
|
237 | ///
|
238 | /// Commands must be executed/queued for execution otherwise they do nothing.
|
239 | #[derive (Debug, Clone, Copy, PartialEq, Eq)]
|
240 | pub struct SetUnderlineColor(pub Color);
|
241 |
|
242 | impl Command for SetUnderlineColor {
|
243 | fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
244 | write!(f, csi!("{}m" ), Colored::UnderlineColor(self.0))
|
245 | }
|
246 |
|
247 | #[cfg (windows)]
|
248 | fn execute_winapi(&self) -> std::io::Result<()> {
|
249 | Err(std::io::Error::new(
|
250 | std::io::ErrorKind::Other,
|
251 | "SetUnderlineColor not supported by winapi." ,
|
252 | ))
|
253 | }
|
254 | }
|
255 |
|
256 | /// A command that optionally sets the foreground and/or background color.
|
257 | ///
|
258 | /// For example:
|
259 | /// ```no_run
|
260 | /// use std::io::{stdout, Write};
|
261 | ///
|
262 | /// use crossterm::execute;
|
263 | /// use crossterm::style::{Color::{Green, Black}, Colors, Print, SetColors};
|
264 | ///
|
265 | /// execute!(
|
266 | /// stdout(),
|
267 | /// SetColors(Colors::new(Green, Black)),
|
268 | /// Print("Hello, world!" .to_string()),
|
269 | /// ).unwrap();
|
270 | /// ```
|
271 | ///
|
272 | /// See [`Colors`](struct.Colors.html) for more info.
|
273 | ///
|
274 | /// # Notes
|
275 | ///
|
276 | /// Commands must be executed/queued for execution otherwise they do nothing.
|
277 | #[derive (Debug, Clone, Copy, PartialEq, Eq)]
|
278 | pub struct SetColors(pub Colors);
|
279 |
|
280 | impl Command for SetColors {
|
281 | fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
282 | if let Some(color: Color) = self.0.foreground {
|
283 | SetForegroundColor(color).write_ansi(f)?;
|
284 | }
|
285 | if let Some(color: Color) = self.0.background {
|
286 | SetBackgroundColor(color).write_ansi(f)?;
|
287 | }
|
288 | Ok(())
|
289 | }
|
290 |
|
291 | #[cfg (windows)]
|
292 | fn execute_winapi(&self) -> std::io::Result<()> {
|
293 | if let Some(color) = self.0.foreground {
|
294 | sys::windows::set_foreground_color(color)?;
|
295 | }
|
296 | if let Some(color) = self.0.background {
|
297 | sys::windows::set_background_color(color)?;
|
298 | }
|
299 | Ok(())
|
300 | }
|
301 | }
|
302 |
|
303 | /// A command that sets an attribute.
|
304 | ///
|
305 | /// See [`Attribute`](enum.Attribute.html) for more info.
|
306 | ///
|
307 | /// # Notes
|
308 | ///
|
309 | /// Commands must be executed/queued for execution otherwise they do nothing.
|
310 | #[derive (Debug, Clone, Copy, PartialEq, Eq)]
|
311 | pub struct SetAttribute(pub Attribute);
|
312 |
|
313 | impl Command for SetAttribute {
|
314 | fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
315 | write!(f, csi!("{}m" ), self.0.sgr())
|
316 | }
|
317 |
|
318 | #[cfg (windows)]
|
319 | fn execute_winapi(&self) -> std::io::Result<()> {
|
320 | // attributes are not supported by WinAPI.
|
321 | Ok(())
|
322 | }
|
323 | }
|
324 |
|
325 | /// A command that sets several attributes.
|
326 | ///
|
327 | /// See [`Attributes`](struct.Attributes.html) for more info.
|
328 | ///
|
329 | /// # Notes
|
330 | ///
|
331 | /// Commands must be executed/queued for execution otherwise they do nothing.
|
332 | #[derive (Debug, Clone, Copy, PartialEq, Eq)]
|
333 | pub struct SetAttributes(pub Attributes);
|
334 |
|
335 | impl Command for SetAttributes {
|
336 | fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
337 | for attr: Attribute in Attribute::iterator() {
|
338 | if self.0.has(attribute:attr) {
|
339 | SetAttribute(attr).write_ansi(f)?;
|
340 | }
|
341 | }
|
342 | Ok(())
|
343 | }
|
344 |
|
345 | #[cfg (windows)]
|
346 | fn execute_winapi(&self) -> std::io::Result<()> {
|
347 | // attributes are not supported by WinAPI.
|
348 | Ok(())
|
349 | }
|
350 | }
|
351 |
|
352 | /// A command that sets a style (colors and attributes).
|
353 | ///
|
354 | /// # Notes
|
355 | ///
|
356 | /// Commands must be executed/queued for execution otherwise they do nothing.
|
357 | #[derive (Debug, Clone, Copy, PartialEq, Eq)]
|
358 | pub struct SetStyle(pub ContentStyle);
|
359 |
|
360 | impl Command for SetStyle {
|
361 | fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
362 | if let Some(bg) = self.0.background_color {
|
363 | execute_fmt(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?;
|
364 | }
|
365 | if let Some(fg) = self.0.foreground_color {
|
366 | execute_fmt(f, SetForegroundColor(fg)).map_err(|_| fmt::Error)?;
|
367 | }
|
368 | if let Some(ul) = self.0.underline_color {
|
369 | execute_fmt(f, SetUnderlineColor(ul)).map_err(|_| fmt::Error)?;
|
370 | }
|
371 | if !self.0.attributes.is_empty() {
|
372 | execute_fmt(f, SetAttributes(self.0.attributes)).map_err(|_| fmt::Error)?;
|
373 | }
|
374 |
|
375 | Ok(())
|
376 | }
|
377 |
|
378 | #[cfg (windows)]
|
379 | fn execute_winapi(&self) -> std::io::Result<()> {
|
380 | panic!("tried to execute SetStyle command using WinAPI, use ANSI instead" );
|
381 | }
|
382 |
|
383 | #[cfg (windows)]
|
384 | fn is_ansi_code_supported(&self) -> bool {
|
385 | true
|
386 | }
|
387 | }
|
388 |
|
389 | /// A command that prints styled content.
|
390 | ///
|
391 | /// See [`StyledContent`](struct.StyledContent.html) for more info.
|
392 | ///
|
393 | /// # Notes
|
394 | ///
|
395 | /// Commands must be executed/queued for execution otherwise they do nothing.
|
396 | #[derive (Debug, Copy, Clone)]
|
397 | pub struct PrintStyledContent<D: Display>(pub StyledContent<D>);
|
398 |
|
399 | impl<D: Display> Command for PrintStyledContent<D> {
|
400 | fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
401 | let style = self.0.style();
|
402 |
|
403 | let mut reset_background = false;
|
404 | let mut reset_foreground = false;
|
405 | let mut reset = false;
|
406 |
|
407 | if let Some(bg) = style.background_color {
|
408 | execute_fmt(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?;
|
409 | reset_background = true;
|
410 | }
|
411 | if let Some(fg) = style.foreground_color {
|
412 | execute_fmt(f, SetForegroundColor(fg)).map_err(|_| fmt::Error)?;
|
413 | reset_foreground = true;
|
414 | }
|
415 | if let Some(ul) = style.underline_color {
|
416 | execute_fmt(f, SetUnderlineColor(ul)).map_err(|_| fmt::Error)?;
|
417 | reset_foreground = true;
|
418 | }
|
419 |
|
420 | if !style.attributes.is_empty() {
|
421 | execute_fmt(f, SetAttributes(style.attributes)).map_err(|_| fmt::Error)?;
|
422 | reset = true;
|
423 | }
|
424 |
|
425 | write!(f, " {}" , self.0.content())?;
|
426 |
|
427 | if reset {
|
428 | // NOTE: This will reset colors even though self has no colors, hence produce unexpected
|
429 | // resets.
|
430 | // TODO: reset the set attributes only.
|
431 | execute_fmt(f, ResetColor).map_err(|_| fmt::Error)?;
|
432 | } else {
|
433 | // NOTE: Since the above bug, we do not need to reset colors when we reset attributes.
|
434 | if reset_background {
|
435 | execute_fmt(f, SetBackgroundColor(Color::Reset)).map_err(|_| fmt::Error)?;
|
436 | }
|
437 | if reset_foreground {
|
438 | execute_fmt(f, SetForegroundColor(Color::Reset)).map_err(|_| fmt::Error)?;
|
439 | }
|
440 | }
|
441 |
|
442 | Ok(())
|
443 | }
|
444 |
|
445 | #[cfg (windows)]
|
446 | fn execute_winapi(&self) -> std::io::Result<()> {
|
447 | Ok(())
|
448 | }
|
449 | }
|
450 |
|
451 | /// A command that resets the colors back to default.
|
452 | ///
|
453 | /// # Notes
|
454 | ///
|
455 | /// Commands must be executed/queued for execution otherwise they do nothing.
|
456 | #[derive (Debug, Clone, Copy, PartialEq, Eq)]
|
457 | pub struct ResetColor;
|
458 |
|
459 | impl Command for ResetColor {
|
460 | fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
461 | f.write_str(csi!("0m" ))
|
462 | }
|
463 |
|
464 | #[cfg (windows)]
|
465 | fn execute_winapi(&self) -> std::io::Result<()> {
|
466 | sys::windows::reset()
|
467 | }
|
468 | }
|
469 |
|
470 | /// A command that prints the given displayable type.
|
471 | ///
|
472 | /// Commands must be executed/queued for execution otherwise they do nothing.
|
473 | #[derive (Debug, Clone, Copy, PartialEq, Eq)]
|
474 | pub struct Print<T: Display>(pub T);
|
475 |
|
476 | impl<T: Display> Command for Print<T> {
|
477 | fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
478 | write!(f, " {}" , self.0)
|
479 | }
|
480 |
|
481 | #[cfg (windows)]
|
482 | fn execute_winapi(&self) -> std::io::Result<()> {
|
483 | panic!("tried to execute Print command using WinAPI, use ANSI instead" );
|
484 | }
|
485 |
|
486 | #[cfg (windows)]
|
487 | fn is_ansi_code_supported(&self) -> bool {
|
488 | true
|
489 | }
|
490 | }
|
491 |
|
492 | impl<T: Display> Display for Print<T> {
|
493 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
494 | self.0.fmt(f)
|
495 | }
|
496 | }
|
497 |
|
498 | impl_display!(for SetForegroundColor);
|
499 | impl_display!(for SetBackgroundColor);
|
500 | impl_display!(for SetColors);
|
501 | impl_display!(for SetAttribute);
|
502 | impl_display!(for PrintStyledContent<String>);
|
503 | impl_display!(for PrintStyledContent<&'static str>);
|
504 | impl_display!(for ResetColor);
|
505 |
|
506 | /// Utility function for ANSI parsing in Color and Colored.
|
507 | /// Gets the next element of `iter` and tries to parse it as a `u8`.
|
508 | fn parse_next_u8<'a>(iter: &mut impl Iterator<Item = &'a str>) -> Option<u8> {
|
509 | iter.next().and_then(|s: &str| s.parse().ok())
|
510 | }
|
511 | |