1
+ use console:: Term ;
2
+ use indicatif:: TermLike ;
1
3
use std:: {
2
4
io:: { self , Write } ,
3
5
mem:: MaybeUninit ,
@@ -6,8 +8,8 @@ use std::{
6
8
sync:: { Arc , Mutex , MutexGuard } ,
7
9
} ;
8
10
9
- pub ( crate ) use termcolor:: Color ;
10
- use termcolor:: { ColorChoice , ColorSpec , StandardStream , StandardStreamLock , WriteColor } ;
11
+ pub ( crate ) use termcolor:: { Color , ColorChoice } ;
12
+ use termcolor:: { ColorSpec , StandardStream , StandardStreamLock , WriteColor } ;
11
13
12
14
use super :: Process ;
13
15
#[ cfg( feature = "test" ) ]
@@ -53,6 +55,8 @@ pub struct ColorableTerminal {
53
55
// source is important because otherwise parallel constructed terminals
54
56
// would not be locked out.
55
57
inner : Arc < Mutex < TerminalInner > > ,
58
+ is_a_tty : bool ,
59
+ color_choice : ColorChoice ,
56
60
}
57
61
58
62
/// Internal state for ColorableTerminal
@@ -84,10 +88,11 @@ impl ColorableTerminal {
84
88
/// then color commands will be sent to the stream.
85
89
/// Otherwise color commands are discarded.
86
90
pub ( super ) fn new ( stream : StreamSelector , process : & Process ) -> Self {
91
+ let is_a_tty = stream. is_a_tty ( process) ;
87
92
let choice = match process. var ( "RUSTUP_TERM_COLOR" ) {
88
93
Ok ( s) if s. eq_ignore_ascii_case ( "always" ) => ColorChoice :: Always ,
89
94
Ok ( s) if s. eq_ignore_ascii_case ( "never" ) => ColorChoice :: Never ,
90
- _ if stream . is_a_tty ( process ) => ColorChoice :: Auto ,
95
+ _ if is_a_tty => ColorChoice :: Auto ,
91
96
_ => ColorChoice :: Never ,
92
97
} ;
93
98
let inner = match stream {
@@ -104,6 +109,8 @@ impl ColorableTerminal {
104
109
} ;
105
110
ColorableTerminal {
106
111
inner : Arc :: new ( Mutex :: new ( inner) ) ,
112
+ is_a_tty,
113
+ color_choice : choice,
107
114
}
108
115
}
109
116
@@ -179,6 +186,14 @@ impl ColorableTerminal {
179
186
} ;
180
187
Ok ( ( ) )
181
188
}
189
+
190
+ pub fn is_a_tty ( & self ) -> bool {
191
+ self . is_a_tty
192
+ }
193
+
194
+ pub fn color_choice ( & self ) -> ColorChoice {
195
+ self . color_choice
196
+ }
182
197
}
183
198
184
199
#[ derive( Copy , Clone , Debug ) ]
@@ -223,6 +238,81 @@ impl io::Write for ColorableTerminalLocked {
223
238
}
224
239
}
225
240
241
+ impl TermLike for ColorableTerminal {
242
+ fn width ( & self ) -> u16 {
243
+ Term :: stdout ( ) . size ( ) . 1
244
+ }
245
+
246
+ fn move_cursor_up ( & self , n : usize ) -> io:: Result < ( ) > {
247
+ // As the ProgressBar may try to move the cursor up by 0 lines,
248
+ // we need to handle that case to avoid writing an escape sequence
249
+ // that would mess up the terminal.
250
+ if n == 0 {
251
+ return Ok ( ( ) ) ;
252
+ }
253
+ let mut t = self . lock ( ) ;
254
+ write ! ( t, "\x1b [{n}A" ) ?;
255
+ t. flush ( )
256
+ }
257
+
258
+ fn move_cursor_down ( & self , n : usize ) -> io:: Result < ( ) > {
259
+ if n == 0 {
260
+ return Ok ( ( ) ) ;
261
+ }
262
+ let mut t = self . lock ( ) ;
263
+ write ! ( t, "\x1b [{n}B" ) ?;
264
+ t. flush ( )
265
+ }
266
+
267
+ fn move_cursor_right ( & self , n : usize ) -> io:: Result < ( ) > {
268
+ if n == 0 {
269
+ return Ok ( ( ) ) ;
270
+ }
271
+ let mut t = self . lock ( ) ;
272
+ write ! ( t, "\x1b [{n}C" ) ?;
273
+ t. flush ( )
274
+ }
275
+
276
+ fn move_cursor_left ( & self , n : usize ) -> io:: Result < ( ) > {
277
+ if n == 0 {
278
+ return Ok ( ( ) ) ;
279
+ }
280
+ let mut t = self . lock ( ) ;
281
+ write ! ( t, "\x1b [{n}D" ) ?;
282
+ t. flush ( )
283
+ }
284
+
285
+ fn write_line ( & self , line : & str ) -> io:: Result < ( ) > {
286
+ let mut t = self . lock ( ) ;
287
+ t. write_all ( line. as_bytes ( ) ) ?;
288
+ t. write_all ( b"\n " ) ?;
289
+ t. flush ( )
290
+ }
291
+
292
+ fn write_str ( & self , s : & str ) -> io:: Result < ( ) > {
293
+ let mut t = self . lock ( ) ;
294
+ t. write_all ( s. as_bytes ( ) ) ?;
295
+ t. flush ( )
296
+ }
297
+
298
+ fn clear_line ( & self ) -> io:: Result < ( ) > {
299
+ let mut t = self . lock ( ) ;
300
+ t. write_all ( b"\r \x1b [2K" ) ?;
301
+ t. flush ( )
302
+ }
303
+
304
+ fn flush ( & self ) -> io:: Result < ( ) > {
305
+ let mut t = self . lock ( ) ;
306
+ t. flush ( )
307
+ }
308
+ }
309
+
310
+ impl std:: fmt:: Debug for ColorableTerminal {
311
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
312
+ write ! ( f, "ColorableTerminal {{ inner: ... }}" )
313
+ }
314
+ }
315
+
226
316
#[ cfg( test) ]
227
317
mod tests {
228
318
use std:: collections:: HashMap ;
0 commit comments