]>
Commit | Line | Data |
---|---|---|
353b0b11 FG |
1 | /// Extend `std::io::Write` with wincon styling |
2 | /// | |
3 | /// Generally, you will want to use [`Console`][crate::Console] instead | |
4 | pub trait WinconStream { | |
5 | /// Change the foreground/background | |
6 | /// | |
7 | /// A common pitfall is to forget to flush writes to | |
8 | /// stdout before setting new text attributes. | |
9 | fn set_colors( | |
10 | &mut self, | |
11 | fg: Option<anstyle::AnsiColor>, | |
12 | bg: Option<anstyle::AnsiColor>, | |
13 | ) -> std::io::Result<()>; | |
14 | ||
15 | /// Get the current foreground/background colors | |
16 | fn get_colors( | |
17 | &self, | |
18 | ) -> std::io::Result<(Option<anstyle::AnsiColor>, Option<anstyle::AnsiColor>)>; | |
19 | } | |
20 | ||
21 | impl WinconStream for std::io::Stdout { | |
22 | fn set_colors( | |
23 | &mut self, | |
24 | fg: Option<anstyle::AnsiColor>, | |
25 | bg: Option<anstyle::AnsiColor>, | |
26 | ) -> std::io::Result<()> { | |
27 | inner::set_colors(self, fg, bg) | |
28 | } | |
29 | ||
30 | fn get_colors( | |
31 | &self, | |
32 | ) -> std::io::Result<(Option<anstyle::AnsiColor>, Option<anstyle::AnsiColor>)> { | |
33 | inner::get_colors(self) | |
34 | } | |
35 | } | |
36 | ||
37 | impl<'s> WinconStream for std::io::StdoutLock<'s> { | |
38 | fn set_colors( | |
39 | &mut self, | |
40 | fg: Option<anstyle::AnsiColor>, | |
41 | bg: Option<anstyle::AnsiColor>, | |
42 | ) -> std::io::Result<()> { | |
43 | inner::set_colors(self, fg, bg) | |
44 | } | |
45 | ||
46 | fn get_colors( | |
47 | &self, | |
48 | ) -> std::io::Result<(Option<anstyle::AnsiColor>, Option<anstyle::AnsiColor>)> { | |
49 | inner::get_colors(self) | |
50 | } | |
51 | } | |
52 | ||
53 | impl WinconStream for std::io::Stderr { | |
54 | fn set_colors( | |
55 | &mut self, | |
56 | fg: Option<anstyle::AnsiColor>, | |
57 | bg: Option<anstyle::AnsiColor>, | |
58 | ) -> std::io::Result<()> { | |
59 | inner::set_colors(self, fg, bg) | |
60 | } | |
61 | ||
62 | fn get_colors( | |
63 | &self, | |
64 | ) -> std::io::Result<(Option<anstyle::AnsiColor>, Option<anstyle::AnsiColor>)> { | |
65 | inner::get_colors(self) | |
66 | } | |
67 | } | |
68 | ||
69 | impl<'s> WinconStream for std::io::StderrLock<'s> { | |
70 | fn set_colors( | |
71 | &mut self, | |
72 | fg: Option<anstyle::AnsiColor>, | |
73 | bg: Option<anstyle::AnsiColor>, | |
74 | ) -> std::io::Result<()> { | |
75 | inner::set_colors(self, fg, bg) | |
76 | } | |
77 | ||
78 | fn get_colors( | |
79 | &self, | |
80 | ) -> std::io::Result<(Option<anstyle::AnsiColor>, Option<anstyle::AnsiColor>)> { | |
81 | inner::get_colors(self) | |
82 | } | |
83 | } | |
84 | ||
85 | #[cfg(windows)] | |
86 | mod inner { | |
87 | use std::os::windows::io::{AsHandle, AsRawHandle}; | |
88 | ||
89 | pub(super) fn set_colors<S: AsHandle>( | |
90 | stream: &mut S, | |
91 | fg: Option<anstyle::AnsiColor>, | |
92 | bg: Option<anstyle::AnsiColor>, | |
93 | ) -> std::io::Result<()> { | |
94 | let handle = stream.as_handle(); | |
95 | let handle = handle.as_raw_handle(); | |
96 | if let (Some(fg), Some(bg)) = (fg, bg) { | |
97 | let attributes = crate::windows::set_colors(fg, bg); | |
98 | crate::windows::set_console_text_attributes(handle, attributes) | |
99 | } else { | |
100 | Ok(()) | |
101 | } | |
102 | } | |
103 | ||
104 | pub(super) fn get_colors<S: AsHandle>( | |
105 | stream: &S, | |
106 | ) -> std::io::Result<(Option<anstyle::AnsiColor>, Option<anstyle::AnsiColor>)> { | |
107 | let handle = stream.as_handle(); | |
108 | let handle = handle.as_raw_handle(); | |
109 | let info = crate::windows::get_screen_buffer_info(handle)?; | |
110 | let (fg, bg) = crate::windows::get_colors(&info); | |
111 | Ok((Some(fg), Some(bg))) | |
112 | } | |
113 | } | |
114 | ||
115 | #[cfg(not(windows))] | |
116 | mod inner { | |
117 | pub(super) fn set_colors<S: std::io::Write>( | |
118 | stream: &mut S, | |
119 | fg: Option<anstyle::AnsiColor>, | |
120 | bg: Option<anstyle::AnsiColor>, | |
121 | ) -> std::io::Result<()> { | |
122 | if let Some(fg) = fg { | |
123 | write!(stream, "{}", fg.render_fg())?; | |
124 | } | |
125 | if let Some(bg) = bg { | |
126 | write!(stream, "{}", bg.render_bg())?; | |
127 | } | |
128 | if fg.is_none() && bg.is_none() { | |
129 | write!(stream, "{}", anstyle::Reset.render())?; | |
130 | } | |
131 | Ok(()) | |
132 | } | |
133 | ||
134 | pub(super) fn get_colors<S>( | |
135 | _stream: &S, | |
136 | ) -> std::io::Result<(Option<anstyle::AnsiColor>, Option<anstyle::AnsiColor>)> { | |
137 | Ok((None, None)) | |
138 | } | |
139 | } |