Skip to content

Commit aadb45f

Browse files
author
Stefan Bühler
committed
support logging [WIP, missing windows]
1 parent 8151995 commit aadb45f

File tree

3 files changed

+79
-10
lines changed

3 files changed

+79
-10
lines changed

src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ mod tty;
116116
mod pb;
117117
mod multi;
118118
pub use pb::{ProgressBar, Units};
119-
pub use multi::{MultiBar, Pipe};
119+
pub use multi::{MultiBar, Pipe, LogTarget};
120120
use std::io::{Write, Stdout, stdout};
121121

122122
pub struct PbIter<T, I>
@@ -189,14 +189,14 @@ pub trait ProgressReceiver: private::SealedProgressReceiver {
189189

190190
impl<T: Write> private::SealedProgressReceiver for T {
191191
fn update_progress(&mut self, line: &str) {
192-
self.write(tty::clear_current_line().as_bytes()).expect("write() fail");
193192
self.write(b"\r").expect("write() fail");
194193
self.write(line.as_bytes()).expect("write() fail");
195194
self.flush().expect("flush() fail");
196195
}
197196

198197
fn clear_progress(&mut self, line: &str) {
199-
self.write(tty::clear_current_line().as_bytes()).expect("write() fail");
198+
self.write(b"\r").expect("write() fail");
199+
self.write(tty::clear_until_newline().as_bytes()).expect("write() fail");
200200
self.write(line.as_bytes()).expect("write() fail");
201201
self.write(b"\n").expect("write() fail");
202202
self.flush().expect("flush() fail");

src/multi.rs

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use pb::ProgressBar;
2+
use std::str::from_utf8;
23
use tty;
3-
use std::io::{Stdout, Write};
4+
use std::io::{self, Stdout, Write};
45
use std::sync::mpsc;
56
use 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+
237298
impl ::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
}

src/tty/unix.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,12 @@ pub fn move_cursor_up(n: usize) -> String {
4747
format!("{}", termion::cursor::Up(n as u16))
4848
}
4949

50-
pub fn clear_current_line() -> String {
51-
format!("{}", termion::clear::CurrentLine)
50+
pub fn clear_until_newline() -> String {
51+
format!("{}", termion::clear::UntilNewline)
52+
}
53+
54+
pub fn clear_after_cursor() -> String {
55+
format!("{}", termion::clear::AfterCursor)
5256
}
5357

5458
#[cfg(not(target_os = "redox"))]

0 commit comments

Comments
 (0)