@@ -17,6 +17,7 @@ use crossbeam_channel::Receiver;
17
17
use crossbeam_channel:: Sender ;
18
18
use crossbeam_channel:: bounded;
19
19
use crossbeam_channel:: unbounded;
20
+ use crossterm:: tty:: IsTty ;
20
21
21
22
use crate :: Dimensions ;
22
23
@@ -29,6 +30,10 @@ pub enum OutputTarget {
29
30
Aux ,
30
31
}
31
32
33
+ pub trait IsTtyWrite : IsTty + Write { }
34
+
35
+ impl < T : IsTty + Write > IsTtyWrite for T { }
36
+
32
37
pub trait SuperConsoleOutput : Send + Sync + ' static {
33
38
/// Called before rendering will occur. This has a chance to prevent rendering by returning
34
39
/// false.
@@ -46,6 +51,11 @@ pub trait SuperConsoleOutput: Send + Sync + 'static {
46
51
self . output ( buffer)
47
52
}
48
53
54
+ /// Check if auxillary stream is tty
55
+ fn aux_stream_is_tty ( & self ) -> bool {
56
+ true
57
+ }
58
+
49
59
/// How big is the terminal to write to.
50
60
fn terminal_size ( & self ) -> anyhow:: Result < Dimensions > {
51
61
Ok ( crossterm:: terminal:: size ( ) ?. into ( ) )
@@ -66,13 +76,13 @@ pub struct BlockingSuperConsoleOutput {
66
76
/// Stream to write to.
67
77
stream : Box < dyn Write + Send + ' static + Sync > ,
68
78
/// Auxiliary stream to write to.
69
- aux_stream : Box < dyn Write + Send + ' static + Sync > ,
79
+ aux_stream : Box < dyn IsTtyWrite + Send + ' static + Sync > ,
70
80
}
71
81
72
82
impl BlockingSuperConsoleOutput {
73
83
pub fn new (
74
84
stream : Box < dyn Write + Send + ' static + Sync > ,
75
- aux_stream : Box < dyn Write + Send + ' static + Sync > ,
85
+ aux_stream : Box < dyn IsTtyWrite + Send + ' static + Sync > ,
76
86
) -> Self {
77
87
Self { stream, aux_stream }
78
88
}
@@ -87,6 +97,10 @@ impl SuperConsoleOutput for BlockingSuperConsoleOutput {
87
97
self . output_to ( buffer, OutputTarget :: Main )
88
98
}
89
99
100
+ fn aux_stream_is_tty ( & self ) -> bool {
101
+ self . aux_stream . is_tty ( )
102
+ }
103
+
90
104
fn output_to ( & mut self , buffer : Vec < u8 > , target : OutputTarget ) -> anyhow:: Result < ( ) > {
91
105
match target {
92
106
OutputTarget :: Main => {
@@ -127,30 +141,33 @@ pub(crate) struct NonBlockingSuperConsoleOutput {
127
141
/// The thread doing the writing. It owns the other end of the aforementioned channels and will
128
142
/// exit when the data sender is closed.
129
143
handle : JoinHandle < ( ) > ,
144
+ /// The auxillary output is compatible with tty
145
+ aux_compatible : bool ,
130
146
}
131
147
132
148
impl NonBlockingSuperConsoleOutput {
133
149
pub fn new (
134
150
stream : Box < dyn Write + Send + ' static + Sync > ,
135
- aux_stream : Box < dyn Write + Send + ' static + Sync > ,
151
+ aux_stream : Box < dyn IsTtyWrite + Send + ' static + Sync > ,
136
152
) -> anyhow:: Result < Self > {
137
153
Self :: new_for_writer ( stream, aux_stream)
138
154
}
139
155
140
156
fn new_for_writer (
141
157
mut stream : Box < dyn Write + Send + ' static + Sync > ,
142
- mut aux_stream : Box < dyn Write + Send + ' static + Sync > ,
158
+ mut aux_stream : Box < dyn IsTtyWrite + Send + ' static + Sync > ,
143
159
) -> anyhow:: Result < Self > {
144
160
let ( sender, receiver) = bounded :: < ( Vec < u8 > , OutputTarget ) > ( 1 ) ;
145
161
let ( error_sender, errors) = unbounded :: < io:: Error > ( ) ;
162
+ let aux_compatible = aux_stream. is_tty ( ) ;
146
163
147
164
let handle = std:: thread:: Builder :: new ( )
148
165
. name ( "superconsole-io" . to_owned ( ) )
149
166
. spawn ( move || {
150
167
for ( data, output_target) in receiver. into_iter ( ) {
151
168
let out_stream = match output_target {
152
169
OutputTarget :: Main => & mut stream,
153
- OutputTarget :: Aux => & mut aux_stream,
170
+ OutputTarget :: Aux => & mut aux_stream as & mut dyn Write ,
154
171
} ;
155
172
match out_stream. write_all ( & data) . and_then ( |( ) | stream. flush ( ) ) {
156
173
Ok ( ( ) ) => { }
@@ -168,6 +185,7 @@ impl NonBlockingSuperConsoleOutput {
168
185
sender,
169
186
errors,
170
187
handle,
188
+ aux_compatible,
171
189
} )
172
190
}
173
191
}
@@ -198,12 +216,17 @@ impl SuperConsoleOutput for NonBlockingSuperConsoleOutput {
198
216
Ok ( ( ) )
199
217
}
200
218
219
+ fn aux_stream_is_tty ( & self ) -> bool {
220
+ self . aux_compatible
221
+ }
222
+
201
223
/// Notify our writer thread that no further writes are expected. Wait for it to flush.
202
224
fn finalize ( self : Box < Self > ) -> anyhow:: Result < ( ) > {
203
225
let Self {
204
226
sender,
205
227
errors,
206
228
handle,
229
+ aux_compatible : _,
207
230
} = * self ;
208
231
drop ( sender) ;
209
232
@@ -247,6 +270,12 @@ mod tests {
247
270
}
248
271
}
249
272
273
+ impl IsTty for TestWriter {
274
+ fn is_tty ( & self ) -> bool {
275
+ true
276
+ }
277
+ }
278
+
250
279
impl Write for TestWriter {
251
280
fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
252
281
self . sender
0 commit comments