trybuild_internals_api/
term.rs1use std::io::{Result, Write};
2use std::sync::{Mutex, MutexGuard, OnceLock, PoisonError};
3use termcolor::{Color, ColorChoice, ColorSpec, StandardStream as Stream, WriteColor};
4
5static TERM: OnceLock<Mutex<Term>> = OnceLock::new();
6
7pub fn lock() -> MutexGuard<'static, Term> {
8 TERM.get_or_init(|| Mutex::new(Term::new()))
9 .lock()
10 .unwrap_or_else(PoisonError::into_inner)
11}
12
13pub fn bold() {
14 lock().set_color(ColorSpec::new().set_bold(true));
15}
16
17pub fn color(color: Color) {
18 lock().set_color(ColorSpec::new().set_fg(Some(color)));
19}
20
21pub fn bold_color(color: Color) {
22 lock().set_color(ColorSpec::new().set_bold(true).set_fg(Some(color)));
23}
24
25pub fn reset() {
26 lock().reset();
27}
28
29#[deny(unused_macros)]
30macro_rules! print {
31 ($($args:tt)*) => {{
32 use std::io::Write;
33 let _ = std::write!($crate::term::lock(), $($args)*);
34 }};
35}
36
37#[deny(unused_macros)]
38macro_rules! println {
39 ($($args:tt)*) => {{
40 use std::io::Write;
41 let _ = std::writeln!($crate::term::lock(), $($args)*);
42 }};
43}
44
45pub struct Term {
46 spec: ColorSpec,
47 stream: Stream,
48 start_of_line: bool,
49}
50
51impl Term {
52 fn new() -> Self {
53 Term {
54 spec: ColorSpec::new(),
55 stream: Stream::stderr(ColorChoice::Auto),
56 start_of_line: true,
57 }
58 }
59
60 fn set_color(&mut self, spec: &ColorSpec) {
61 if self.spec != *spec {
62 self.spec = spec.clone();
63 self.start_of_line = true;
64 }
65 }
66
67 fn reset(&mut self) {
68 self.spec = ColorSpec::new();
69 let _ = self.stream.reset();
70 }
71}
72
73impl Write for Term {
74 fn write(&mut self, mut buf: &[u8]) -> Result<usize> {
77 if self.spec.is_none() {
78 return self.stream.write(buf);
79 }
80
81 let len = buf.len();
82 while !buf.is_empty() {
83 if self.start_of_line {
84 let _ = self.stream.set_color(&self.spec);
85 }
86 match buf.iter().position(|byte| *byte == b'\n') {
87 Some(line_len) => {
88 self.stream.write_all(&buf[..line_len + 1])?;
89 self.start_of_line = true;
90 buf = &buf[line_len + 1..];
91 }
92 None => {
93 self.stream.write_all(buf)?;
94 self.start_of_line = false;
95 break;
96 }
97 }
98 }
99 Ok(len)
100 }
101
102 fn flush(&mut self) -> Result<()> {
103 self.stream.flush()
104 }
105}