From 80c849763165e6bbe56f75913ef76de9a9daae5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Tue, 25 Jul 2017 10:08:04 +0200 Subject: [PATCH 1/7] use termion for all non-windows platforms --- Cargo.toml | 6 +++-- src/tty/mod.rs | 9 ++------ src/tty/redox.rs | 13 ----------- src/tty/unix.rs | 57 +++++++++++++++++++++++++----------------------- 4 files changed, 36 insertions(+), 49 deletions(-) delete mode 100644 src/tty/redox.rs 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/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() { From f54b4d7eea90c7551988ff815e1b024b9675f92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Tue, 25 Jul 2017 10:08:55 +0200 Subject: [PATCH 2/7] time crate has no macros --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) 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; From 4bf287f4b50351a0b3fbff0471ef53585f2685ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Thu, 27 Jul 2017 14:02:48 +0200 Subject: [PATCH 3/7] fix doc tests or ignore them --- src/multi.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/multi.rs b/src/multi.rs index 86707ea7..c39dc4d1 100644 --- a/src/multi.rs +++ b/src/multi.rs @@ -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; From eef0de82cfc45a376238435ab702eb5a373f6588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Thu, 27 Jul 2017 12:28:51 +0200 Subject: [PATCH 4/7] avoid temporary String allocation --- src/multi.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/multi.rs b/src/multi.rs index c39dc4d1..941798cb 100644 --- a/src/multi.rs +++ b/src/multi.rs @@ -212,7 +212,9 @@ impl MultiBar { 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); } From f08b41ef6ddd614f9963ca2b3b2e20893cc63094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Thu, 27 Jul 2017 12:31:20 +0200 Subject: [PATCH 5/7] use tty with module name in multi.rs --- src/multi.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/multi.rs b/src/multi.rs index 941798cb..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}; @@ -207,7 +207,7 @@ 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; } From 7c8dc7cbe24f24b4c8c963938f2a41967bf01671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Thu, 27 Jul 2017 12:36:48 +0200 Subject: [PATCH 6/7] drop pb handle after finish* --- src/pb.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/pb.rs b/src/pb.rs index 461823f7..b78598c7 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,7 @@ 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)); } @@ -451,7 +450,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) From 316924c268e188575d5ba5b6739ba9af5e6c1c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Wed, 2 Aug 2017 21:52:28 +0200 Subject: [PATCH 7/7] fix multibar resource leak --- src/pb.rs | 5 ++++- tests/lib.rs | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/pb.rs b/src/pb.rs index b78598c7..ef204036 100644 --- a/src/pb.rs +++ b/src/pb.rs @@ -435,7 +435,10 @@ impl ProgressBar { if s.len() < width { out += repeat!(" ", width - s.len()); }; - self.handle.take().map(|mut h| printfl!(h, "\r{}", out)); + self.handle.take().map(|mut h| { + printfl!(h, "\r{}", out); + printfl!(h, ""); + }); } 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(); +}