Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_text/tests/annealer_corpus/crossterm_style.rs

17.8 KiB, 1 run

created by r1870400018:11716, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

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 hyperlink::{EndHyperlink, StartHyperlink},
126 styled_content::StyledContent,
127 stylize::Stylize,
128 types::{Attribute, Color, Colored, Colors},
129};
130
131mod attributes;
132mod content_style;
133mod hyperlink;
134mod styled_content;
135mod stylize;
136mod sys;
137mod types;
138
139/// Creates a `StyledContent`.
140///
141/// This could be used to style any type that implements `Display` with colors and text attributes.
142///
143/// See [`StyledContent`](struct.StyledContent.html) for more info.
144///
145/// # Examples
146///
147/// ```no_run
148/// use crossterm::style::{style, Stylize, Color};
149///
150/// let styled_content = style("Blue colored text on yellow background")
151/// .with(Color::Blue)
152/// .on(Color::Yellow);
153///
154/// println!("{}", styled_content);
155/// ```
156pub fn style<D: Display>(val: D) -> StyledContent<D> {
157 ContentStyle::new().apply(val)
158}
159
160/// Returns available color count.
161///
162/// # Notes
163///
164/// This does not always provide a good result.
165pub fn available_color_count() -> u16 {
166 #[cfg(windows)]
167 {
168 // Check if we're running in a pseudo TTY, which supports true color.
169 // Fall back to env vars otherwise for other terminals on Windows.
170 if crate::ansi_support::supports_ansi() {
171 return u16::MAX;
172 }
173 }
174
175 const DEFAULT: u16 = 8;
176 env::var("COLORTERM")
177 .or_else(|_| env::var("TERM"))
178 .map_or(DEFAULT, |x| match x {
179 _ if x.contains("24bit") || x.contains("truecolor") => u16::MAX,
180 _ if x.contains("256") => 256,
181 _ => DEFAULT,
182 })
183}
184
185/// Forces colored output on or off globally, overriding NO_COLOR.
186///
187/// # Notes
188///
189/// crossterm supports NO_COLOR (<https://no-color.org/>) to disabled colored output.
190///
191/// This API allows applications to override that behavior and force colorized output
192/// even if NO_COLOR is set.
193pub fn force_color_output(enabled: bool) {
194 Colored::set_ansi_color_disabled(!enabled)
195}
196
197/// A command that sets the the foreground color.
198///
199/// See [`Color`](enum.Color.html) for more info.
200///
201/// [`SetColors`](struct.SetColors.html) can also be used to set both the foreground and background
202/// color in one command.
203///
204/// # Notes
205///
206/// Commands must be executed/queued for execution otherwise they do nothing.
207#[derive(Debug, Clone, Copy, PartialEq, Eq)]
208pub struct SetForegroundColor(pub Color);
209
210impl Command for SetForegroundColor {
211 fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
212 write!(f, csi!("{}m"), Colored::ForegroundColor(self.0))
213 }
214
215 #[cfg(windows)]
216 fn execute_winapi(&self) -> std::io::Result<()> {
217 sys::windows::set_foreground_color(self.0)
218 }
219}
220
221/// A command that sets the the background color.
222///
223/// See [`Color`](enum.Color.html) for more info.
224///
225/// [`SetColors`](struct.SetColors.html) can also be used to set both the foreground and background
226/// color with one command.
227///
228/// # Notes
229///
230/// Commands must be executed/queued for execution otherwise they do nothing.
231#[derive(Debug, Clone, Copy, PartialEq, Eq)]
232pub struct SetBackgroundColor(pub Color);
233
234impl Command for SetBackgroundColor {
235 fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
236 write!(f, csi!("{}m"), Colored::BackgroundColor(self.0))
237 }
238
239 #[cfg(windows)]
240 fn execute_winapi(&self) -> std::io::Result<()> {
241 sys::windows::set_background_color(self.0)
242 }
243}
244
245/// A command that sets the the underline color.
246///
247/// See [`Color`](enum.Color.html) for more info.
248///
249/// [`SetColors`](struct.SetColors.html) can also be used to set both the foreground and background
250/// color with one command.
251///
252/// # Notes
253///
254/// Commands must be executed/queued for execution otherwise they do nothing.
255#[derive(Debug, Clone, Copy, PartialEq, Eq)]
256pub struct SetUnderlineColor(pub Color);
257
258impl Command for SetUnderlineColor {
259 fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
260 write!(f, csi!("{}m"), Colored::UnderlineColor(self.0))
261 }
262
263 #[cfg(windows)]
264 fn execute_winapi(&self) -> std::io::Result<()> {
265 Err(std::io::Error::new(
266 std::io::ErrorKind::Other,
267 "SetUnderlineColor not supported by winapi.",
268 ))
269 }
270}
271
272/// A command that optionally sets the foreground and/or background color.
273///
274/// For example:
275/// ```no_run
276/// use std::io::{stdout, Write};
277///
278/// use crossterm::execute;
279/// use crossterm::style::{Color::{Green, Black}, Colors, Print, SetColors};
280///
281/// execute!(
282/// stdout(),
283/// SetColors(Colors::new(Green, Black)),
284/// Print("Hello, world!".to_string()),
285/// ).unwrap();
286/// ```
287///
288/// See [`Colors`](struct.Colors.html) for more info.
289///
290/// # Notes
291///
292/// Commands must be executed/queued for execution otherwise they do nothing.
293#[derive(Debug, Clone, Copy, PartialEq, Eq)]
294pub struct SetColors(pub Colors);
295
296impl Command for SetColors {
297 fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
298 // Writing both foreground and background colors in one command resulted in about 20% more
299 // FPS (20 to 24 fps) on a fullscreen (171x51) app that writes every cell with a different
300 // foreground and background color, compared to separately using the SetForegroundColor and
301 // SetBackgroundColor commands (iTerm2, M2 Macbook Pro). `Esc[38;5;<fg>mEsc[48;5;<bg>m` (16
302 // chars) vs `Esc[38;5;<fg>;48;5;<bg>m` (14 chars)
303 match (self.0.foreground, self.0.background) {
304 (Some(fg), Some(bg)) => {
305 write!(
306 f,
307 csi!("{};{}m"),
308 Colored::ForegroundColor(fg),
309 Colored::BackgroundColor(bg)
310 )
311 }
312 (Some(fg), None) => write!(f, csi!("{}m"), Colored::ForegroundColor(fg)),
313 (None, Some(bg)) => write!(f, csi!("{}m"), Colored::BackgroundColor(bg)),
314 (None, None) => Ok(()),
315 }
316 }
317
318 #[cfg(windows)]
319 fn execute_winapi(&self) -> std::io::Result<()> {
320 if let Some(color) = self.0.foreground {
321 sys::windows::set_foreground_color(color)?;
322 }
323 if let Some(color) = self.0.background {
324 sys::windows::set_background_color(color)?;
325 }
326 Ok(())
327 }
328}
329
330/// A command that sets an attribute.
331///
332/// See [`Attribute`](enum.Attribute.html) for more info.
333///
334/// # Notes
335///
336/// Commands must be executed/queued for execution otherwise they do nothing.
337#[derive(Debug, Clone, Copy, PartialEq, Eq)]
338pub struct SetAttribute(pub Attribute);
339
340impl Command for SetAttribute {
341 fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
342 write!(f, csi!("{}m"), self.0.sgr())
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 several attributes.
353///
354/// See [`Attributes`](struct.Attributes.html) for more info.
355///
356/// # Notes
357///
358/// Commands must be executed/queued for execution otherwise they do nothing.
359#[derive(Debug, Clone, Copy, PartialEq, Eq)]
360pub struct SetAttributes(pub Attributes);
361
362impl Command for SetAttributes {
363 fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
364 for attr in Attribute::iterator() {
365 if self.0.has(attr) {
366 SetAttribute(attr).write_ansi(f)?;
367 }
368 }
369 Ok(())
370 }
371
372 #[cfg(windows)]
373 fn execute_winapi(&self) -> std::io::Result<()> {
374 // attributes are not supported by WinAPI.
375 Ok(())
376 }
377}
378
379/// A command that sets a style (colors and attributes).
380///
381/// # Notes
382///
383/// Commands must be executed/queued for execution otherwise they do nothing.
384#[derive(Debug, Clone, Copy, PartialEq, Eq)]
385pub struct SetStyle(pub ContentStyle);
386
387impl Command for SetStyle {
388 fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
389 if let Some(bg) = self.0.background_color {
390 execute_fmt(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?;
391 }
392 if let Some(fg) = self.0.foreground_color {
393 execute_fmt(f, SetForegroundColor(fg)).map_err(|_| fmt::Error)?;
394 }
395 if let Some(ul) = self.0.underline_color {
396 execute_fmt(f, SetUnderlineColor(ul)).map_err(|_| fmt::Error)?;
397 }
398 if !self.0.attributes.is_empty() {
399 execute_fmt(f, SetAttributes(self.0.attributes)).map_err(|_| fmt::Error)?;
400 }
401
402 Ok(())
403 }
404
405 #[cfg(windows)]
406 fn execute_winapi(&self) -> std::io::Result<()> {
407 panic!("tried to execute SetStyle command using WinAPI, use ANSI instead");
408 }
409
410 #[cfg(windows)]
411 fn is_ansi_code_supported(&self) -> bool {
412 true
413 }
414}
415
416/// A command that prints styled content.
417///
418/// See [`StyledContent`](struct.StyledContent.html) for more info.
419///
420/// # Notes
421///
422/// Commands must be executed/queued for execution otherwise they do nothing.
423#[derive(Debug, Copy, Clone)]
424pub struct PrintStyledContent<D: Display>(pub StyledContent<D>);
425
426impl<D: Display> Command for PrintStyledContent<D> {
427 fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
428 let style = self.0.style();
429
430 let mut reset_background = false;
431 let mut reset_foreground = false;
432 let mut reset = false;
433
434 if let Some(bg) = style.background_color {
435 execute_fmt(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?;
436 reset_background = true;
437 }
438 if let Some(fg) = style.foreground_color {
439 execute_fmt(f, SetForegroundColor(fg)).map_err(|_| fmt::Error)?;
440 reset_foreground = true;
441 }
442 if let Some(ul) = style.underline_color {
443 execute_fmt(f, SetUnderlineColor(ul)).map_err(|_| fmt::Error)?;
444 reset_foreground = true;
445 }
446
447 if !style.attributes.is_empty() {
448 execute_fmt(f, SetAttributes(style.attributes)).map_err(|_| fmt::Error)?;
449 reset = true;
450 }
451
452 write!(f, "{}", self.0.content())?;
453
454 if reset {
455 // NOTE: This will reset colors even though self has no colors, hence produce unexpected
456 // resets.
457 // TODO: reset the set attributes only.
458 execute_fmt(f, ResetColor).map_err(|_| fmt::Error)?;
459 } else {
460 // NOTE: Since the above bug, we do not need to reset colors when we reset attributes.
461 if reset_background {
462 execute_fmt(f, SetBackgroundColor(Color::Reset)).map_err(|_| fmt::Error)?;
463 }
464 if reset_foreground {
465 execute_fmt(f, SetForegroundColor(Color::Reset)).map_err(|_| fmt::Error)?;
466 }
467 }
468
469 Ok(())
470 }
471
472 #[cfg(windows)]
473 fn execute_winapi(&self) -> std::io::Result<()> {
474 Ok(())
475 }
476}
477
478/// A command that resets the colors back to default.
479///
480/// # Notes
481///
482/// Commands must be executed/queued for execution otherwise they do nothing.
483#[derive(Debug, Clone, Copy, PartialEq, Eq)]
484pub struct ResetColor;
485
486impl Command for ResetColor {
487 fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
488 f.write_str(csi!("0m"))
489 }
490
491 #[cfg(windows)]
492 fn execute_winapi(&self) -> std::io::Result<()> {
493 sys::windows::reset()
494 }
495}
496
497/// A command that prints the given displayable type.
498///
499/// Commands must be executed/queued for execution otherwise they do nothing.
500#[derive(Debug, Clone, Copy, PartialEq, Eq)]
501pub struct Print<T: Display>(pub T);
502
503impl<T: Display> Command for Print<T> {
504 fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
505 write!(f, "{}", self.0)
506 }
507
508 #[cfg(windows)]
509 fn execute_winapi(&self) -> std::io::Result<()> {
510 panic!("tried to execute Print command using WinAPI, use ANSI instead");
511 }
512
513 #[cfg(windows)]
514 fn is_ansi_code_supported(&self) -> bool {
515 true
516 }
517}
518
519impl<T: Display> Display for Print<T> {
520 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
521 self.0.fmt(f)
522 }
523}
524
525impl_display!(for SetForegroundColor);
526impl_display!(for SetBackgroundColor);
527impl_display!(for SetColors);
528impl_display!(for SetAttribute);
529impl_display!(for PrintStyledContent<String>);
530impl_display!(for PrintStyledContent<&'static str>);
531impl_display!(for ResetColor);
532
533/// Utility function for ANSI parsing in Color and Colored.
534/// Gets the next element of `iter` and tries to parse it as a `u8`.
535fn parse_next_u8<'a>(iter: &mut impl Iterator<Item = &'a str>) -> Option<u8> {
536 iter.next().and_then(|s| s.parse().ok())
537}
538
539#[cfg(test)]
540mod tests {
541 use super::*;
542
543 // On Windows many env var tests will fail so we need to conditionally check for ANSI support.
544 // This allows other terminals on Windows to still assert env var support.
545 macro_rules! skip_windows_ansi_supported {
546 () => {
547 #[cfg(windows)]
548 {
549 if crate::ansi_support::supports_ansi() {
550 return;
551 }
552 }
553 };
554 }
555
556 #[cfg_attr(windows, test)]
557 #[cfg(windows)]
558 fn windows_always_truecolor() {
559 // This should always be true on supported Windows 10+,
560 // but downlevel Windows clients and other terminals may fail `cargo test` otherwise.
561 if crate::ansi_support::supports_ansi() {
562 assert_eq!(u16::MAX, available_color_count());
563 };
564 }
565
566 #[test]
567 fn colorterm_overrides_term() {
568 skip_windows_ansi_supported!();
569 temp_env::with_vars(
570 [
571 ("COLORTERM", Some("truecolor")),
572 ("TERM", Some("xterm-256color")),
573 ],
574 || {
575 assert_eq!(u16::MAX, available_color_count());
576 },
577 );
578 }
579
580 #[test]
581 fn term_24bits() {
582 skip_windows_ansi_supported!();
583 temp_env::with_vars(
584 [("COLORTERM", None), ("TERM", Some("xterm-24bits"))],
585 || {
586 assert_eq!(u16::MAX, available_color_count());
587 },
588 );
589 }
590
591 #[test]
592 fn term_256color() {
593 skip_windows_ansi_supported!();
594 temp_env::with_vars(
595 [("COLORTERM", None), ("TERM", Some("xterm-256color"))],
596 || {
597 assert_eq!(256u16, available_color_count());
598 },
599 );
600 }
601
602 #[test]
603 fn default_color_count() {
604 skip_windows_ansi_supported!();
605 temp_env::with_vars([("COLORTERM", None::<&str>), ("TERM", None)], || {
606 assert_eq!(8, available_color_count());
607 });
608 }
609
610 #[test]
611 fn unsupported_term_colorterm_values() {
612 skip_windows_ansi_supported!();
613 temp_env::with_vars(
614 [
615 ("COLORTERM", Some("gibberish")),
616 ("TERM", Some("gibberish")),
617 ],
618 || {
619 assert_eq!(8u16, available_color_count());
620 },
621 );
622 }
623}