diff options
Diffstat (limited to 'cli/util/progress_bar/mod.rs')
-rw-r--r-- | cli/util/progress_bar/mod.rs | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/cli/util/progress_bar/mod.rs b/cli/util/progress_bar/mod.rs new file mode 100644 index 000000000..122db7a59 --- /dev/null +++ b/cli/util/progress_bar/mod.rs @@ -0,0 +1,123 @@ +// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. + +use crate::colors; + +use self::draw_thread::DrawThread; +use self::draw_thread::ProgressBarEntry; + +use super::console::console_size; + +mod draw_thread; +mod renderer; + +// Inspired by Indicatif, but this custom implementation allows +// for more control over what's going on under the hood. + +pub struct UpdateGuard { + maybe_entry: Option<ProgressBarEntry>, +} + +impl Drop for UpdateGuard { + fn drop(&mut self) { + if let Some(entry) = &self.maybe_entry { + entry.finish(); + } + } +} + +impl UpdateGuard { + pub fn set_position(&self, value: u64) { + if let Some(entry) = &self.maybe_entry { + entry.set_position(value); + } + } + + pub fn set_total_size(&self, value: u64) { + if let Some(entry) = &self.maybe_entry { + entry.set_total_size(value); + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ProgressBarStyle { + DownloadBars, + TextOnly, +} + +#[derive(Clone, Debug)] +pub struct ProgressBar { + draw_thread: Option<DrawThread>, +} + +impl ProgressBar { + /// Checks if progress bars are supported + pub fn are_supported() -> bool { + atty::is(atty::Stream::Stderr) + && log::log_enabled!(log::Level::Info) + && console_size() + .map(|s| s.cols > 0 && s.rows > 0) + .unwrap_or(false) + } + + pub fn new(style: ProgressBarStyle) -> Self { + Self { + draw_thread: match Self::are_supported() { + true => Some(DrawThread::new(match style { + ProgressBarStyle::DownloadBars => { + Box::new(renderer::BarProgressBarRenderer) + } + ProgressBarStyle::TextOnly => { + Box::new(renderer::TextOnlyProgressBarRenderer) + } + })), + false => None, + }, + } + } + + pub fn is_enabled(&self) -> bool { + self.draw_thread.is_some() + } + + pub fn update(&self, msg: &str) -> UpdateGuard { + match &self.draw_thread { + Some(draw_thread) => { + let entry = draw_thread.add_entry(msg.to_string()); + UpdateGuard { + maybe_entry: Some(entry), + } + } + None => { + // if we're not running in TTY, fallback to using logger crate + if !msg.is_empty() { + log::log!(log::Level::Info, "{} {}", colors::green("Download"), msg); + } + UpdateGuard { maybe_entry: None } + } + } + } + + pub fn clear_guard(&self) -> ClearGuard { + if let Some(draw_thread) = &self.draw_thread { + draw_thread.increment_clear(); + } + ClearGuard { pb: self.clone() } + } + + fn decrement_clear(&self) { + if let Some(draw_thread) = &self.draw_thread { + draw_thread.decrement_clear(); + } + } +} + +pub struct ClearGuard { + pb: ProgressBar, +} + +impl Drop for ClearGuard { + fn drop(&mut self) { + self.pb.decrement_clear(); + } +} |