11use pb:: ProgressBar ;
2+ use std:: str:: from_utf8;
23use tty;
3- use std:: io:: { Stdout , Write } ;
4+ use std:: io:: { self , Stdout , Write } ;
45use std:: sync:: mpsc;
56use std:: sync:: mpsc:: { Sender , Receiver } ;
67
@@ -158,6 +159,12 @@ impl<T: Write> MultiBar<T> {
158159 p
159160 }
160161
162+ pub fn create_log_target ( & mut self ) -> LogTarget {
163+ LogTarget {
164+ buf : Vec :: new ( ) ,
165+ chan : self . chan . 0 . clone ( ) ,
166+ }
167+ }
161168
162169 /// listen start listen to all bars changes.
163170 ///
@@ -194,21 +201,30 @@ impl<T: Write> MultiBar<T> {
194201 let mut first = true ;
195202 let mut nbars = self . nbars ;
196203 while nbars > 0 {
204+ let mut log_line = None ;
205+
197206 // receive message
198207 let msg = self . chan . 1 . recv ( ) . unwrap ( ) ;
199208 match msg {
200209 WriteMsg :: ProgressUpdate { level, line} => {
201210 self . lines [ level] = line;
202211 } ,
203212 WriteMsg :: ProgressClear { level, line} => {
204- self . lines [ level] = tty:: clear_current_line ( ) + & line;
213+ self . lines [ level] = tty:: clear_until_newline ( ) + & line;
205214 nbars -= 1 ;
206215 } ,
207216 WriteMsg :: ProgressFinish { level, line} => {
208- // writing lines below progress not supported;
209- // replace progress instead
210- self . lines [ level ] = tty :: clear_current_line ( ) + & line ;
217+ // writing lines below progress not supported; treat
218+ // as log message
219+ let _ = level ;
211220 nbars -= 1 ;
221+ if line. is_empty ( ) { continue ; }
222+ log_line = Some ( line) ;
223+ } ,
224+ WriteMsg :: Log { level, line} => {
225+ let _ = level;
226+ if line. is_empty ( ) { continue ; }
227+ log_line = Some ( line) ;
212228 } ,
213229 }
214230
@@ -219,6 +235,12 @@ impl<T: Write> MultiBar<T> {
219235 } else {
220236 first = false ;
221237 }
238+ if let Some ( line) = log_line {
239+ out += "\r " ;
240+ out += & tty:: clear_after_cursor ( ) ;
241+ out += & line;
242+ out += "\n " ;
243+ }
222244 for l in self . lines . iter ( ) {
223245 out += "\r " ;
224246 out += & l;
@@ -234,6 +256,45 @@ pub struct Pipe {
234256 chan : Sender < WriteMsg > ,
235257}
236258
259+ pub struct LogTarget {
260+ buf : Vec < u8 > ,
261+ chan : Sender < WriteMsg > ,
262+ }
263+
264+ impl Write for LogTarget {
265+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
266+ use std:: mem:: replace;
267+
268+ self . buf . extend_from_slice ( buf) ;
269+ // find last newline and flush the part before it
270+ for pos in ( 0 ..self . buf . len ( ) ) . rev ( ) {
271+ if self . buf [ pos] == b'\n' {
272+ let rem = self . buf . split_off ( pos+1 ) ;
273+ let msg = replace ( & mut self . buf , rem) ;
274+ self . chan . send ( WriteMsg :: Log {
275+ level : 0 ,
276+ line : from_utf8 ( & msg[ ..pos] ) . unwrap ( ) . to_owned ( ) ,
277+ } )
278+ . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: Other , e) ) ?;
279+ break ;
280+ }
281+ }
282+ Ok ( buf. len ( ) )
283+ }
284+
285+ fn flush ( & mut self ) -> io:: Result < ( ) > {
286+ use std:: mem:: replace;
287+
288+ let msg = replace ( & mut self . buf , Vec :: new ( ) ) ;
289+ self . chan . send ( WriteMsg :: Log {
290+ level : 0 ,
291+ line : from_utf8 ( & msg) . unwrap ( ) . to_owned ( ) ,
292+ } )
293+ . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: Other , e) ) ?;
294+ Ok ( ( ) )
295+ }
296+ }
297+
237298impl :: private:: SealedProgressReceiver for Pipe {
238299 fn update_progress ( & mut self , line : & str ) {
239300 self . chan . send ( WriteMsg :: ProgressUpdate {
@@ -278,4 +339,8 @@ enum WriteMsg {
278339 level : usize ,
279340 line : String ,
280341 } ,
342+ Log {
343+ level : usize ,
344+ line : String ,
345+ } ,
281346}
0 commit comments