]> git.proxmox.com Git - rustc.git/blame - vendor/anstyle-wincon/src/console.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / vendor / anstyle-wincon / src / console.rs
CommitLineData
353b0b11
FG
1/// Write colored text to the screen
2#[derive(Debug)]
3pub struct Console<S>
4where
5 S: crate::WinconStream + std::io::Write,
6{
7 stream: Option<S>,
8 initial_fg: Option<anstyle::AnsiColor>,
9 initial_bg: Option<anstyle::AnsiColor>,
10 last_fg: Option<anstyle::AnsiColor>,
11 last_bg: Option<anstyle::AnsiColor>,
12}
13
14impl<S> Console<S>
15where
16 S: crate::WinconStream + std::io::Write,
17{
18 pub fn new(stream: S) -> Result<Self, S> {
19 // HACK: Assuming the error from `get_colors()` will be present on `write` and doing basic
20 // ops on the stream will cause the same result
21 let (initial_fg, initial_bg) = match stream.get_colors() {
22 Ok(ok) => ok,
23 Err(_) => {
24 return Err(stream);
25 }
26 };
27 Ok(Self {
28 stream: Some(stream),
29 initial_fg,
30 initial_bg,
31 last_fg: initial_fg,
32 last_bg: initial_bg,
33 })
34 }
35
36 /// Write colored text to the screen
37 pub fn write(
38 &mut self,
39 fg: Option<anstyle::AnsiColor>,
40 bg: Option<anstyle::AnsiColor>,
41 data: &[u8],
42 ) -> std::io::Result<usize> {
43 self.apply(fg, bg)?;
44 let written = self.as_stream_mut().write(data)?;
45 Ok(written)
46 }
47
48 pub fn flush(&mut self) -> std::io::Result<()> {
49 self.as_stream_mut().flush()
50 }
51
52 /// Change the terminal back to the initial colors
53 pub fn reset(&mut self) -> std::io::Result<()> {
54 self.apply(self.initial_fg, self.initial_bg)
55 }
56
57 /// Close the stream, reporting any errors
58 pub fn close(mut self) -> std::io::Result<()> {
59 self.reset()
60 }
61
62 /// Allow changing the stream
63 pub fn map<S1: crate::WinconStream + std::io::Write>(
64 mut self,
65 op: impl FnOnce(S) -> S1,
66 ) -> Console<S1> {
67 Console {
68 stream: Some(op(self.stream.take().unwrap())),
69 initial_fg: self.initial_fg,
70 initial_bg: self.initial_bg,
71 last_fg: self.last_fg,
72 last_bg: self.last_bg,
73 }
74 }
75
76 /// Get the inner writer
77 #[inline]
78 pub fn into_inner(mut self) -> S {
79 let _ = self.reset();
80 self.stream.take().unwrap()
81 }
82
83 fn apply(
84 &mut self,
85 fg: Option<anstyle::AnsiColor>,
86 bg: Option<anstyle::AnsiColor>,
87 ) -> std::io::Result<()> {
88 let fg = fg.or(self.initial_fg);
89 let bg = bg.or(self.initial_bg);
90 if fg == self.last_fg && bg == self.last_bg {
91 return Ok(());
92 }
93
94 // Ensure everything is written with the last set of colors before applying the next set
95 self.as_stream_mut().flush()?;
96
97 self.as_stream_mut().set_colors(fg, bg)?;
98 self.last_fg = fg;
99 self.last_bg = bg;
100
101 Ok(())
102 }
103
104 fn as_stream_mut(&mut self) -> &mut S {
105 self.stream.as_mut().unwrap()
106 }
107}
108
109impl<S> Console<S>
110where
111 S: crate::WinconStream + std::io::Write,
112 S: crate::Lockable,
113 <S as crate::Lockable>::Locked: crate::WinconStream + std::io::Write,
114{
115 /// Get exclusive access to the `Console`
116 ///
117 /// Why?
118 /// - Faster performance when writing in a loop
119 /// - Avoid other threads interleaving output with the current thread
120 #[inline]
121 pub fn lock(mut self) -> <Self as crate::Lockable>::Locked {
122 Console {
123 stream: Some(self.stream.take().unwrap().lock()),
124 initial_fg: self.initial_fg,
125 initial_bg: self.initial_bg,
126 last_fg: self.last_fg,
127 last_bg: self.last_bg,
128 }
129 }
130}
131
132impl<S> crate::Lockable for Console<S>
133where
134 S: crate::WinconStream + std::io::Write,
135 S: crate::Lockable,
136 <S as crate::Lockable>::Locked: crate::WinconStream + std::io::Write,
137{
138 type Locked = Console<<S as crate::Lockable>::Locked>;
139
140 #[inline]
141 fn lock(self) -> Self::Locked {
142 self.lock()
143 }
144}
145
146impl<S> Drop for Console<S>
147where
148 S: crate::WinconStream + std::io::Write,
149{
150 fn drop(&mut self) {
151 // Otherwise `Console::lock` took it
152 if self.stream.is_some() {
153 let _ = self.reset();
154 }
155 }
156}