diff --git a/Cargo.toml b/Cargo.toml index 6c388767..2e6b20de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,11 +11,13 @@ license = "MIT" [dependencies] libc = "0.2.9" time = "0.1.35" + +[target.'cfg(target_os = "windows")'.dependencies] winapi = "0.2" kernel32-sys = "0.2" -[target.'cfg(target_os = "redox")'.dependencies] -termion = "1.4" +[target.'cfg(not(target_os = "windows"))'.dependencies] +termion = "1.5" [dev-dependencies] rand = "0.3.14" diff --git a/src/lib.rs b/src/lib.rs index 236f7035..0057850e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,7 +111,6 @@ macro_rules! printfl { }} } -#[macro_use] extern crate time; mod tty; mod pb; diff --git a/src/multi.rs b/src/multi.rs index 86707ea7..d644b94f 100644 --- a/src/multi.rs +++ b/src/multi.rs @@ -1,6 +1,6 @@ use pb::ProgressBar; use std::str::from_utf8; -use tty::move_cursor_up; +use tty; use std::io::{Stdout, Result, Write}; use std::sync::mpsc; use std::sync::mpsc::{Sender, Receiver}; @@ -22,7 +22,7 @@ impl MultiBar { /// /// # Examples /// - /// ```no_run + /// ```ignore /// use std::thread; /// use pbr::MultiBar; /// @@ -91,7 +91,7 @@ impl MultiBar { /// /// # Examples /// - /// ```no_run + /// ```ignore /// use pbr::MultiBar; /// /// let mut mb = MultiBar::new(); @@ -127,7 +127,7 @@ impl MultiBar { /// /// # Examples /// - /// ```no_run + /// ```ignore /// use pbr::MultiBar; /// /// let mut mb = MultiBar::new(); @@ -171,8 +171,11 @@ impl MultiBar { /// /// # Examples /// - /// ```no_run - /// use pbr::MultiBar; + /// ``` + /// # extern crate pbr; + /// # use std::thread; + /// # fn main() { + /// use ::pbr::MultiBar; /// /// let mut mb = MultiBar::new(); /// @@ -186,6 +189,7 @@ impl MultiBar { /// }); /// /// // ... + /// # } /// ``` pub fn listen(&mut self) { let mut first = true; @@ -203,12 +207,14 @@ impl MultiBar { // and draw let mut out = String::new(); if !first { - out += &move_cursor_up(self.nlines); + out += &tty::move_cursor_up(self.nlines); } else { first = false; } for l in self.lines.iter() { - out.push_str(&format!("\r{}\n", l)); + out += "\r"; + out += &l; + out += "\n"; } printfl!(self.handle, "{}", out); } diff --git a/src/pb.rs b/src/pb.rs index 461823f7..ef204036 100644 --- a/src/pb.rs +++ b/src/pb.rs @@ -61,7 +61,7 @@ pub struct ProgressBar { pub show_time_left: bool, pub show_tick: bool, pub show_message: bool, - handle: T, + handle: Option, } impl ProgressBar { @@ -134,7 +134,7 @@ impl ProgressBar { message: String::new(), last_refresh_time: SteadyTime::now(), max_refresh_rate: None, - handle: handle, + handle: Some(handle), }; pb.format(FORMAT); pb.tick_format(TICK_FORMAT); @@ -264,7 +264,7 @@ impl ProgressBar { /// ``` pub fn tick(&mut self) { self.tick_state = (self.tick_state + 1) % self.tick.len(); - if self.current <= self.total { + if self.handle.is_some() && self.current <= self.total { self.draw() } } @@ -391,7 +391,7 @@ impl ProgressBar { out = out + repeat!(" ", gap); } // print - printfl!(self.handle, "\r{}", out); + self.handle.as_mut().map(|h| printfl!(h, "\r{}", out)); self.last_refresh_time = SteadyTime::now(); } @@ -413,7 +413,7 @@ impl ProgressBar { redraw = true; } - if redraw { + if self.handle.is_some() && redraw { self.draw(); } self.is_finish = true; @@ -423,7 +423,7 @@ impl ProgressBar { /// the last time pub fn finish(&mut self) { self.finish_draw(); - printfl!(self.handle, ""); + self.handle.take().map(|mut h| printfl!(h, "")); } @@ -435,8 +435,10 @@ impl ProgressBar { if s.len() < width { out += repeat!(" ", width - s.len()); }; - printfl!(self.handle, "\r{}", out); - self.finish(); + self.handle.take().map(|mut h| { + printfl!(h, "\r{}", out); + printfl!(h, ""); + }); } @@ -451,7 +453,7 @@ impl ProgressBar { return self.finish_print(s); } self.finish_draw(); - printfl!(self.handle, "\n{}", s); + self.handle.take().map(|mut h| printfl!(h, "\n{}", s)); } /// Get terminal width, from configuration, terminal size, or default(80) diff --git a/src/tty/mod.rs b/src/tty/mod.rs index db9dfa55..5af63a81 100644 --- a/src/tty/mod.rs +++ b/src/tty/mod.rs @@ -12,17 +12,12 @@ pub struct Width(pub u16); #[derive(Debug)] pub struct Height(pub u16); -#[cfg(unix)] +#[cfg(not(windows))] mod unix; -#[cfg(unix)] +#[cfg(not(windows))] pub use self::unix::*; #[cfg(windows)] mod windows; #[cfg(windows)] pub use self::windows::*; - -#[cfg(target_os = "redox")] -mod redox; -#[cfg(target_os = "redox")] -pub use self::redox::*; diff --git a/src/tty/redox.rs b/src/tty/redox.rs deleted file mode 100644 index 2f9bd8c2..00000000 --- a/src/tty/redox.rs +++ /dev/null @@ -1,13 +0,0 @@ -extern crate termion; -use super::{Width, Height}; - -pub fn terminal_size() -> Option<(Width, Height)> { - match termion::terminal_size() { - Ok((cols, rows)) => Some((Width(cols), Height(rows))), - Err(..) => None - } -} - -pub fn move_cursor_up(n: usize) -> String { - format!("{}", termion::cursor::Up(n as u16)) -} diff --git a/src/tty/unix.rs b/src/tty/unix.rs index 8330cd80..65e491df 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -1,40 +1,41 @@ +extern crate termion; extern crate libc; use super::{Width, Height}; /// Returns the size of the terminal, if available. /// /// If STDOUT is not a tty, returns `None` +#[cfg(target_os = "redox")] pub fn terminal_size() -> Option<(Width, Height)> { - use self::libc::{ioctl, isatty, STDOUT_FILENO, TIOCGWINSZ, winsize}; - let is_tty: bool = unsafe { isatty(STDOUT_FILENO) == 1 }; - - if !is_tty { - return None; + match termion::terminal_size() { + Ok((cols, rows)) => Some((Width(cols), Height(rows))), + Err(..) => None } +} - let (rows, cols) = unsafe { - let mut winsize = winsize { - ws_row: 0, - ws_col: 0, - ws_xpixel: 0, - ws_ypixel: 0, - }; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut winsize); - let rows = if winsize.ws_row > 0 { - winsize.ws_row - } else { - 0 - }; - let cols = if winsize.ws_col > 0 { - winsize.ws_col +#[cfg(not(target_os = "redox"))] +fn terminal_size_fd(fd: libc::c_int) -> Option<(Width, Height)> { + use std::mem; + + unsafe { + let mut size: libc::winsize = mem::zeroed(); + if libc::ioctl(fd, libc::TIOCGWINSZ, &mut size as *mut _) == 0 { + Some((Width(size.ws_col), Height(size.ws_row))) } else { - 0 - }; - (rows as u16, cols as u16) - }; + None + } + } +} - if rows > 0 && cols > 0 { - Some((Width(cols), Height(rows))) +/// Returns the size of the terminal, if available. +/// +/// If neither STDOUT nor STDERR is a tty, returns `None` +#[cfg(not(target_os = "redox"))] +pub fn terminal_size() -> Option<(Width, Height)> { + if unsafe { libc::isatty(libc::STDOUT_FILENO) == 1 } { + terminal_size_fd(libc::STDOUT_FILENO) + } else if unsafe { libc::isatty(libc::STDERR_FILENO) == 1 }{ + terminal_size_fd(libc::STDERR_FILENO) } else { None } @@ -42,9 +43,11 @@ pub fn terminal_size() -> Option<(Width, Height)> { /// Return string that move the cursor `n` lines up. pub fn move_cursor_up(n: usize) -> String { - format!("\x1B[{}A", n) + assert!(n < 0x10000); + format!("{}", termion::cursor::Up(n as u16)) } +#[cfg(not(target_os = "redox"))] #[test] /// Compare with the output of `stty size` fn compare_with_stty() { diff --git a/tests/lib.rs b/tests/lib.rs index 4c291343..65a9f293 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,6 +1,6 @@ extern crate pbr; -use pbr::{ProgressBar, PbIter}; +use pbr::{ProgressBar, PbIter, MultiBar}; use std::time::Duration; use std::thread; @@ -107,3 +107,20 @@ fn npm_bar() { } pb.finish_println("done!"); } + +#[test] +fn multi_finish_print() { + let count = 10; + let mut mb = MultiBar::new(); + let mut pb = mb.create_bar(10); + pb.tick(); + let t = thread::spawn(move || { + mb.listen(); + }); + for _ in 0..count { + thread::sleep(Duration::from_millis(30)); + pb.tick(); + } + pb.finish_print("done"); + t.join().unwrap(); +}