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
114use std::{
115 env,
116 fmt::{self, Display},
117};
118
119use crate::command::execute_fmt;
120use crate::{csi, impl_display, Command};
121
122pub use self::{
123 attributes::Attributes,
124 content_style::ContentStyle,
125 styled_content::StyledContent,
126 stylize::Stylize,
127 types::{Attribute, Color, Colored, Colors},
128};
129
130mod attributes;
131mod content_style;
132mod styled_content;
133mod stylize;
134mod sys;
135mod 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/// ```
154pub 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.
163pub 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.
177pub 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)]
192pub struct SetForegroundColor(pub Color);
193
194impl 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)]
216pub struct SetBackgroundColor(pub Color);
217
218impl 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)]
240pub struct SetUnderlineColor(pub Color);
241
242impl 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)]
278pub struct SetColors(pub Colors);
279
280impl 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)]
311pub struct SetAttribute(pub Attribute);
312
313impl 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)]
333pub struct SetAttributes(pub Attributes);
334
335impl 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)]
358pub struct SetStyle(pub ContentStyle);
359
360impl 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)]
397pub struct PrintStyledContent<D: Display>(pub StyledContent<D>);
398
399impl<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)]
457pub struct ResetColor;
458
459impl 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)]
474pub struct Print<T: Display>(pub T);
475
476impl<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
492impl<T: Display> Display for Print<T> {
493 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494 self.0.fmt(f)
495 }
496}
497
498impl_display!(for SetForegroundColor);
499impl_display!(for SetBackgroundColor);
500impl_display!(for SetColors);
501impl_display!(for SetAttribute);
502impl_display!(for PrintStyledContent<String>);
503impl_display!(for PrintStyledContent<&'static str>);
504impl_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`.
508fn 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