Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ macro_rules! printfl {
}}
}

macro_rules! repeat {
($s: expr, $n: expr) => {{
&repeat($s).take($n).collect::<String>()
}}
}

const PBR_LOG_BOUNDARY: &'static str = "--PBR-LOG-BOUNDARY";

#[macro_use]
extern crate time;
mod tty;
Expand Down
73 changes: 69 additions & 4 deletions src/multi.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use pb::ProgressBar;
use std::str::from_utf8;
use tty::move_cursor_up;
use tty::{Width, terminal_size, move_cursor_up};
use std::io::{Stdout, Result, Write};
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};
use std::iter::repeat;

use ::PBR_LOG_BOUNDARY;

pub struct MultiBar<T: Write> {
nlines: usize,
Expand All @@ -15,6 +18,8 @@ pub struct MultiBar<T: Write> {
chan: (Sender<WriteMsg>, Receiver<WriteMsg>),

handle: T,

width: Option<usize>,
}

impl MultiBar<Stdout> {
Expand Down Expand Up @@ -82,6 +87,7 @@ impl<T: Write> MultiBar<T> {
lines: Vec::new(),
chan: mpsc::channel(),
handle: handle,
width: None,
}
}

Expand Down Expand Up @@ -112,7 +118,16 @@ impl<T: Write> MultiBar<T> {
/// mb.listen();
/// ```
pub fn println(&mut self, s: &str) {
self.lines.push(s.to_owned());
let mut out = format!("{}", s);

let width = self.width();

if out.len() < width {
let gap = width - out.len();
out = out + repeat!(" ", gap);
}

self.lines.push(out);
self.nlines += 1;
}

Expand Down Expand Up @@ -154,6 +169,7 @@ impl<T: Write> MultiBar<T> {
chan: self.chan.0.clone(),
},
total);
p.set_width(self.width);
p.is_multibar = true;
p.add(0);
p
Expand Down Expand Up @@ -207,12 +223,42 @@ impl<T: Write> MultiBar<T> {
} else {
first = false;
}

// draw the log line if we have one & scroll the log message upward to prevent it from
// being overwritten by the progress bar(s) and message strings
if let Some(log_line) = msg.log_line {
out.push_str(&format!("\r{}\n", log_line));
}

for l in self.lines.iter() {
out.push_str(&format!("\r{}\n", l));
}
printfl!(self.handle, "{}", out);
}
}

/// Set width, or `None` for default.
///
/// # Examples
///
/// ```ignore
/// let mut mb = MultiBar::new(...);
/// mb.set_width(Some(80));
/// ```
pub fn set_width(&mut self, w: Option<usize>) {
self.width = w;
}

/// Get terminal width, from configuration, terminal size, or default(80)
fn width(&mut self) -> usize {
if let Some(w) = self.width {
w
} else if let Some((Width(w), _)) = terminal_size() {
w as usize
} else {
80
}
}
}

pub struct Pipe {
Expand All @@ -223,12 +269,30 @@ pub struct Pipe {
impl Write for Pipe {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
let s = from_utf8(buf).unwrap().to_owned();

// check to see if ProgressBar set a logging boundary & split out the log if we find it
let (log_line, bar) = match s.contains(PBR_LOG_BOUNDARY) {
true => {
let v: Vec<&str> = s.split(PBR_LOG_BOUNDARY).collect();
let log_line = Some(v[0].to_owned());

let bar = v[1].to_owned();

(log_line, bar)
},
false => {
(None, s)
}

};

self.chan
.send(WriteMsg {
// finish method emit empty string
done: s == "",
done: bar == "",
level: self.level,
string: s,
string: bar,
log_line: log_line,
})
.unwrap();
Ok(1)
Expand All @@ -245,4 +309,5 @@ struct WriteMsg {
done: bool,
level: usize,
string: String,
log_line: Option<String>,
}
53 changes: 47 additions & 6 deletions src/pb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use time::{self, SteadyTime};
use std::io::Stdout;
use tty::{Width, terminal_size};

use ::PBR_LOG_BOUNDARY;

macro_rules! kb_fmt {
($n: ident) => {{
let kb = 1024f64;
Expand All @@ -18,12 +20,6 @@ macro_rules! kb_fmt {
}}
}

macro_rules! repeat {
($s: expr, $n: expr) => {{
&repeat($s).take($n).collect::<String>()
}}
}

const FORMAT: &'static str = "[=>-]";
const TICK_FORMAT: &'static str = "\\|/-";
const NANOS_PER_SEC: u32 = 1_000_000_000;
Expand All @@ -50,6 +46,7 @@ pub struct ProgressBar<T: Write> {
tick_state: usize,
width: Option<usize>,
message: String,
log_line: Option<String>,
last_refresh_time: SteadyTime,
max_refresh_rate: Option<time::Duration>,
pub is_finish: bool,
Expand Down Expand Up @@ -132,6 +129,7 @@ impl<T: Write> ProgressBar<T> {
tick_state: 0,
width: None,
message: String::new(),
log_line: None,
last_refresh_time: SteadyTime::now(),
max_refresh_rate: None,
handle: handle,
Expand Down Expand Up @@ -390,6 +388,32 @@ impl<T: Write> ProgressBar<T> {
let gap = width - out.len();
out = out + repeat!(" ", gap);
}

// handle a log line waiting to be printed
if let Some(ref log_line) = self.log_line {

// overwrite the current line with our log message + whitespace
let mut log_out = format!("\r{}", log_line);

if log_line.len() < width {
log_out += repeat!(" ", width - log_line.len());
};

// if writing to a MultiBar, use a boundary string to allow MultiBar to print the log
// and bar separately.
//
// otherwise print a newline to scroll the log message upward to prevent it from being
// overwritten by the progress bar
if self.is_multibar {
log_out = log_out + PBR_LOG_BOUNDARY;
} else {
log_out = log_out + "\n";
}

out = log_out + &out;
}
self.log_line = None;

// print
printfl!(self.handle, "\r{}", out);

Expand All @@ -413,6 +437,10 @@ impl<T: Write> ProgressBar<T> {
redraw = true;
}

if let Some(_) = self.log_line {
redraw = true;
}

if redraw {
self.draw();
}
Expand Down Expand Up @@ -440,6 +468,19 @@ impl<T: Write> ProgressBar<T> {
}


/// Write string `s` above the progress bar for logging
///
/// Log messages will appear to scroll upward while the progress bar(s) stay in place.
///
/// Behavior should be the same whether the bar is part of a MultiBar or not
///
pub fn log(&mut self, s: &str) {
self.log_line = Some(s.to_owned());
self.draw();
}



/// Call finish and write string `s` below the progress bar.
///
/// If the ProgressBar is part of MultiBar instance, you should use
Expand Down