summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock4
-rw-r--r--cli/Cargo.toml2
-rw-r--r--cli/util/draw_thread.rs237
-rw-r--r--cli/util/mod.rs1
-rw-r--r--cli/util/progress_bar/draw_thread.rs218
-rw-r--r--cli/util/progress_bar/mod.rs219
-rw-r--r--cli/util/progress_bar/renderer.rs2
7 files changed, 440 insertions, 243 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 48972fa8f..c194fc6e2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -501,9 +501,9 @@ dependencies = [
[[package]]
name = "console_static_text"
-version = "0.3.3"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d749e1f5316d8a15ec592516a631ab9b8099cc6d085b69b905462fc071caedb"
+checksum = "f166cdfb9db0607e2079b382ba64bc4164344006c733b95c1ecfa782a180a34a"
dependencies = [
"unicode-width",
"vte",
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index e7fc497cc..665a715ae 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -59,7 +59,7 @@ chrono = { version = "=0.4.22", default-features = false, features = ["clock"] }
clap = "=3.1.12"
clap_complete = "=3.1.2"
clap_complete_fig = "=3.1.5"
-console_static_text = "=0.3.3"
+console_static_text = "=0.3.4"
data-url.workspace = true
dissimilar = "=1.0.4"
dprint-plugin-json = "=0.17.0"
diff --git a/cli/util/draw_thread.rs b/cli/util/draw_thread.rs
new file mode 100644
index 000000000..b069a14b7
--- /dev/null
+++ b/cli/util/draw_thread.rs
@@ -0,0 +1,237 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use console_static_text::ConsoleStaticText;
+use deno_core::parking_lot::Mutex;
+use deno_runtime::ops::tty::ConsoleSize;
+use once_cell::sync::Lazy;
+use std::sync::Arc;
+use std::time::Duration;
+
+use crate::util::console::console_size;
+
+/// Renders text that will be displayed stacked in a
+/// static place on the console.
+pub trait DrawThreadRenderer: Send + Sync + std::fmt::Debug {
+ fn render(&self, data: &ConsoleSize) -> String;
+}
+
+/// Draw thread guard. Keep this alive for the duration
+/// that you wish the entry to be drawn for. Once it is
+/// dropped, then the entry will be removed from the draw
+/// thread.
+#[derive(Debug)]
+pub struct DrawThreadGuard(u16);
+
+impl Drop for DrawThreadGuard {
+ fn drop(&mut self) {
+ DrawThread::finish_entry(self.0)
+ }
+}
+
+#[derive(Debug, Clone)]
+struct InternalEntry {
+ priority: u8,
+ id: u16,
+ renderer: Arc<dyn DrawThreadRenderer>,
+}
+
+#[derive(Debug)]
+struct InternalState {
+ // this ensures only one actual draw thread is running
+ drawer_id: usize,
+ hide: bool,
+ has_draw_thread: bool,
+ next_entry_id: u16,
+ entries: Vec<InternalEntry>,
+ static_text: ConsoleStaticText,
+}
+
+impl InternalState {
+ pub fn should_exit_draw_thread(&self, drawer_id: usize) -> bool {
+ self.drawer_id != drawer_id || self.entries.is_empty()
+ }
+}
+
+static INTERNAL_STATE: Lazy<Arc<Mutex<InternalState>>> = Lazy::new(|| {
+ Arc::new(Mutex::new(InternalState {
+ drawer_id: 0,
+ hide: false,
+ has_draw_thread: false,
+ entries: Vec::new(),
+ next_entry_id: 0,
+ static_text: ConsoleStaticText::new(|| {
+ let size = console_size().unwrap();
+ console_static_text::ConsoleSize {
+ cols: Some(size.cols as u16),
+ rows: Some(size.rows as u16),
+ }
+ }),
+ }))
+});
+
+/// The draw thread is responsible for rendering multiple active
+/// `DrawThreadRenderer`s to stderr. It is global because the
+/// concept of stderr in the process is also a global concept.
+#[derive(Clone, Debug)]
+pub struct DrawThread;
+
+impl DrawThread {
+ /// Is using a draw thread supported.
+ pub fn is_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)
+ }
+
+ /// Adds a renderer to the draw thread with a given priority.
+ /// Renderers are sorted by priority with higher priority
+ /// entries appearing at the bottom of the screen.
+ pub fn add_entry(
+ priority: u8,
+ renderer: Arc<dyn DrawThreadRenderer>,
+ ) -> DrawThreadGuard {
+ let internal_state = &*INTERNAL_STATE;
+ let mut internal_state = internal_state.lock();
+ let id = internal_state.next_entry_id;
+ internal_state.entries.push(InternalEntry {
+ id,
+ priority,
+ renderer,
+ });
+ internal_state
+ .entries
+ .sort_by(|a, b| a.priority.cmp(&b.priority));
+
+ if internal_state.next_entry_id == u16::MAX {
+ internal_state.next_entry_id = 0;
+ } else {
+ internal_state.next_entry_id += 1;
+ }
+
+ Self::maybe_start_draw_thread(&mut internal_state);
+
+ DrawThreadGuard(id)
+ }
+
+ /// Hides the draw thread.
+ #[allow(dead_code)]
+ pub fn hide() {
+ let internal_state = &*INTERNAL_STATE;
+ let mut internal_state = internal_state.lock();
+ internal_state.hide = true;
+ Self::clear_and_stop_draw_thread(&mut internal_state);
+ }
+
+ /// Shows the draw thread if it was previously hidden.
+ #[allow(dead_code)]
+ pub fn show() {
+ let internal_state = &*INTERNAL_STATE;
+ let mut internal_state = internal_state.lock();
+ internal_state.hide = false;
+
+ Self::maybe_start_draw_thread(&mut internal_state);
+ }
+
+ fn finish_entry(entry_id: u16) {
+ let internal_state = &*INTERNAL_STATE;
+ let mut internal_state = internal_state.lock();
+
+ if let Some(index) =
+ internal_state.entries.iter().position(|e| e.id == entry_id)
+ {
+ internal_state.entries.remove(index);
+
+ if internal_state.entries.is_empty() {
+ Self::clear_and_stop_draw_thread(&mut internal_state);
+ }
+ }
+ }
+
+ fn clear_and_stop_draw_thread(internal_state: &mut InternalState) {
+ if internal_state.has_draw_thread {
+ internal_state.static_text.eprint_clear();
+ // bump the drawer id to exit the draw thread
+ internal_state.drawer_id += 1;
+ internal_state.has_draw_thread = false;
+ }
+ }
+
+ fn maybe_start_draw_thread(internal_state: &mut InternalState) {
+ if internal_state.has_draw_thread || internal_state.hide {
+ return;
+ }
+
+ internal_state.drawer_id += 1;
+ internal_state.has_draw_thread = true;
+
+ let drawer_id = internal_state.drawer_id;
+ tokio::task::spawn_blocking(move || {
+ let mut previous_size = console_size().unwrap();
+ loop {
+ let mut delay_ms = 120;
+ {
+ // Get the entries to render.
+ let entries = {
+ let internal_state = &*INTERNAL_STATE;
+ let internal_state = internal_state.lock();
+ if internal_state.should_exit_draw_thread(drawer_id) {
+ break;
+ }
+ internal_state.entries.clone()
+ };
+
+ // Call into the renderers outside the lock to prevent a potential
+ // deadlock between our internal state lock and the renderers
+ // internal state lock.
+ //
+ // Example deadlock if this code didn't do this:
+ // 1. Other thread - Renderer - acquired internal lock to update state
+ // 2. This thread - Acquired internal state
+ // 3. Other thread - Renderer - drops DrawThreadGuard
+ // 4. This thread - Calls renderer.render within internal lock,
+ // which attempts to acquire the other thread's Render's internal
+ // lock causing a deadlock
+ let mut text = String::new();
+ let size = console_size().unwrap();
+ if size != previous_size {
+ // means the user is actively resizing the console...
+ // wait a little bit until they stop resizing
+ previous_size = size;
+ delay_ms = 200;
+ } else {
+ let mut should_new_line_next = false;
+ for entry in entries {
+ let new_text = entry.renderer.render(&size);
+ if should_new_line_next && !new_text.is_empty() {
+ text.push('\n');
+ }
+ should_new_line_next = !new_text.is_empty();
+ text.push_str(&new_text);
+ }
+ }
+
+ // now reacquire the lock, ensure we should still be drawing, then
+ // output the text
+ {
+ let internal_state = &*INTERNAL_STATE;
+ let mut internal_state = internal_state.lock();
+ if internal_state.should_exit_draw_thread(drawer_id) {
+ break;
+ }
+ internal_state.static_text.eprint_with_size(
+ &text,
+ console_static_text::ConsoleSize {
+ cols: Some(size.cols as u16),
+ rows: Some(size.rows as u16),
+ },
+ );
+ }
+ }
+
+ std::thread::sleep(Duration::from_millis(delay_ms));
+ }
+ });
+ }
+}
diff --git a/cli/util/mod.rs b/cli/util/mod.rs
index ab311ee86..a7a72f3b4 100644
--- a/cli/util/mod.rs
+++ b/cli/util/mod.rs
@@ -5,6 +5,7 @@ pub mod checksum;
pub mod console;
pub mod diff;
pub mod display;
+pub mod draw_thread;
pub mod file_watcher;
pub mod fs;
pub mod logger;
diff --git a/cli/util/progress_bar/draw_thread.rs b/cli/util/progress_bar/draw_thread.rs
deleted file mode 100644
index 89e8ab53f..000000000
--- a/cli/util/progress_bar/draw_thread.rs
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
-
-use console_static_text::ConsoleStaticText;
-use deno_core::parking_lot::Mutex;
-use std::sync::atomic::AtomicU64;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-use std::time::Duration;
-use std::time::SystemTime;
-
-use crate::util::console::console_size;
-
-use super::renderer::ProgressBarRenderer;
-use super::renderer::ProgressData;
-use super::renderer::ProgressDataDisplayEntry;
-
-#[derive(Clone, Debug)]
-pub struct ProgressBarEntry {
- id: usize,
- pub message: String,
- pos: Arc<AtomicU64>,
- total_size: Arc<AtomicU64>,
- draw_thread: DrawThread,
-}
-
-impl ProgressBarEntry {
- pub fn position(&self) -> u64 {
- self.pos.load(Ordering::Relaxed)
- }
-
- pub fn set_position(&self, new_pos: u64) {
- self.pos.store(new_pos, Ordering::Relaxed);
- }
-
- pub fn total_size(&self) -> u64 {
- self.total_size.load(Ordering::Relaxed)
- }
-
- pub fn set_total_size(&self, new_size: u64) {
- self.total_size.store(new_size, Ordering::Relaxed);
- }
-
- pub fn finish(&self) {
- self.draw_thread.finish_entry(self.id);
- }
-
- pub fn percent(&self) -> f64 {
- let pos = self.pos.load(Ordering::Relaxed) as f64;
- let total_size = self.total_size.load(Ordering::Relaxed) as f64;
- if total_size == 0f64 {
- 0f64
- } else {
- pos / total_size
- }
- }
-}
-
-#[derive(Debug)]
-struct InternalState {
- start_time: SystemTime,
- // this ensures only one draw thread is running
- drawer_id: usize,
- keep_alive_count: usize,
- has_draw_thread: bool,
- total_entries: usize,
- entries: Vec<ProgressBarEntry>,
- static_text: ConsoleStaticText,
- renderer: Box<dyn ProgressBarRenderer>,
-}
-
-#[derive(Clone, Debug)]
-pub struct DrawThread {
- state: Arc<Mutex<InternalState>>,
-}
-
-impl DrawThread {
- pub fn new(renderer: Box<dyn ProgressBarRenderer>) -> Self {
- Self {
- state: Arc::new(Mutex::new(InternalState {
- start_time: SystemTime::now(),
- drawer_id: 0,
- keep_alive_count: 0,
- has_draw_thread: false,
- total_entries: 0,
- entries: Vec::new(),
- static_text: ConsoleStaticText::new(|| {
- let size = console_size().unwrap();
- console_static_text::ConsoleSize {
- cols: Some(size.cols as u16),
- rows: Some(size.rows as u16),
- }
- }),
- renderer,
- })),
- }
- }
-
- pub fn add_entry(&self, message: String) -> ProgressBarEntry {
- let mut internal_state = self.state.lock();
- let id = internal_state.total_entries;
- let entry = ProgressBarEntry {
- id,
- draw_thread: self.clone(),
- message,
- pos: Default::default(),
- total_size: Default::default(),
- };
- internal_state.entries.push(entry.clone());
- internal_state.total_entries += 1;
- internal_state.keep_alive_count += 1;
-
- if !internal_state.has_draw_thread {
- self.start_draw_thread(&mut internal_state);
- }
-
- entry
- }
-
- fn finish_entry(&self, entry_id: usize) {
- let mut internal_state = self.state.lock();
-
- if let Ok(index) = internal_state
- .entries
- .binary_search_by(|e| e.id.cmp(&entry_id))
- {
- internal_state.entries.remove(index);
- self.decrement_keep_alive(&mut internal_state);
- }
- }
-
- pub fn increment_clear(&self) {
- let mut internal_state = self.state.lock();
- internal_state.keep_alive_count += 1;
- }
-
- pub fn decrement_clear(&self) {
- let mut internal_state = self.state.lock();
- self.decrement_keep_alive(&mut internal_state);
- }
-
- fn decrement_keep_alive(&self, internal_state: &mut InternalState) {
- internal_state.keep_alive_count -= 1;
-
- if internal_state.keep_alive_count == 0 {
- internal_state.static_text.eprint_clear();
- // bump the drawer id to exit the draw thread
- internal_state.drawer_id += 1;
- internal_state.has_draw_thread = false;
- }
- }
-
- fn start_draw_thread(&self, internal_state: &mut InternalState) {
- internal_state.drawer_id += 1;
- internal_state.start_time = SystemTime::now();
- internal_state.has_draw_thread = true;
- let drawer_id = internal_state.drawer_id;
- let internal_state = self.state.clone();
- tokio::task::spawn_blocking(move || {
- let mut previous_size = console_size().unwrap();
- loop {
- let mut delay_ms = 120;
- {
- let mut internal_state = internal_state.lock();
- // exit if not the current draw thread
- if internal_state.drawer_id != drawer_id {
- break;
- }
-
- let size = console_size().unwrap();
- if size != previous_size {
- // means the user is actively resizing the console...
- // wait a little bit until they stop resizing
- previous_size = size;
- delay_ms = 200;
- } else if !internal_state.entries.is_empty() {
- let preferred_entry = internal_state
- .entries
- .iter()
- .find(|e| e.percent() > 0f64)
- .or_else(|| internal_state.entries.iter().last())
- .unwrap();
- let text = internal_state.renderer.render(ProgressData {
- duration: internal_state.start_time.elapsed().unwrap(),
- terminal_width: size.cols,
- pending_entries: internal_state.entries.len(),
- total_entries: internal_state.total_entries,
- display_entry: ProgressDataDisplayEntry {
- message: preferred_entry.message.clone(),
- position: preferred_entry.position(),
- total_size: preferred_entry.total_size(),
- },
- percent_done: {
- let mut total_percent_sum = 0f64;
- for entry in &internal_state.entries {
- total_percent_sum += entry.percent();
- }
- total_percent_sum += (internal_state.total_entries
- - internal_state.entries.len())
- as f64;
- total_percent_sum / (internal_state.total_entries as f64)
- },
- });
-
- internal_state.static_text.eprint_with_size(
- &text,
- console_static_text::ConsoleSize {
- cols: Some(size.cols as u16),
- rows: Some(size.rows as u16),
- },
- );
- }
- }
-
- std::thread::sleep(Duration::from_millis(delay_ms));
- }
- });
- }
-}
diff --git a/cli/util/progress_bar/mod.rs b/cli/util/progress_bar/mod.rs
index 83292e2d1..8651e2d20 100644
--- a/cli/util/progress_bar/mod.rs
+++ b/cli/util/progress_bar/mod.rs
@@ -1,13 +1,23 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+use std::sync::atomic::AtomicU64;
+use std::sync::atomic::Ordering;
+use std::sync::Arc;
+use std::time::SystemTime;
+
+use deno_core::parking_lot::Mutex;
+use deno_runtime::ops::tty::ConsoleSize;
+
use crate::colors;
-use self::draw_thread::DrawThread;
-use self::draw_thread::ProgressBarEntry;
+use self::renderer::ProgressBarRenderer;
+use self::renderer::ProgressData;
+use self::renderer::ProgressDataDisplayEntry;
-use super::console::console_size;
+use super::draw_thread::DrawThread;
+use super::draw_thread::DrawThreadGuard;
+use super::draw_thread::DrawThreadRenderer;
-mod draw_thread;
mod renderer;
// Inspired by Indicatif, but this custom implementation allows
@@ -46,29 +56,196 @@ pub enum ProgressBarStyle {
}
#[derive(Clone, Debug)]
+struct ProgressBarEntry {
+ id: usize,
+ pub message: String,
+ pos: Arc<AtomicU64>,
+ total_size: Arc<AtomicU64>,
+ progress_bar: ProgressBarInner,
+}
+
+impl ProgressBarEntry {
+ pub fn position(&self) -> u64 {
+ self.pos.load(Ordering::Relaxed)
+ }
+
+ pub fn set_position(&self, new_pos: u64) {
+ self.pos.store(new_pos, Ordering::Relaxed);
+ }
+
+ pub fn total_size(&self) -> u64 {
+ self.total_size.load(Ordering::Relaxed)
+ }
+
+ pub fn set_total_size(&self, new_size: u64) {
+ self.total_size.store(new_size, Ordering::Relaxed);
+ }
+
+ pub fn finish(&self) {
+ self.progress_bar.finish_entry(self.id);
+ }
+
+ pub fn percent(&self) -> f64 {
+ let pos = self.pos.load(Ordering::Relaxed) as f64;
+ let total_size = self.total_size.load(Ordering::Relaxed) as f64;
+ if total_size == 0f64 {
+ 0f64
+ } else {
+ pos / total_size
+ }
+ }
+}
+
+#[derive(Debug)]
+struct InternalState {
+ /// If this guard exists, then it means the progress
+ /// bar is displaying in the draw thread.
+ draw_thread_guard: Option<DrawThreadGuard>,
+ start_time: SystemTime,
+ keep_alive_count: usize,
+ total_entries: usize,
+ entries: Vec<ProgressBarEntry>,
+}
+
+#[derive(Clone, Debug)]
+struct ProgressBarInner {
+ state: Arc<Mutex<InternalState>>,
+ renderer: Arc<dyn ProgressBarRenderer>,
+}
+
+impl ProgressBarInner {
+ fn new(renderer: Arc<dyn ProgressBarRenderer>) -> Self {
+ Self {
+ state: Arc::new(Mutex::new(InternalState {
+ draw_thread_guard: None,
+ start_time: SystemTime::now(),
+ keep_alive_count: 0,
+ total_entries: 0,
+ entries: Vec::new(),
+ })),
+ renderer,
+ }
+ }
+
+ pub fn add_entry(&self, message: String) -> ProgressBarEntry {
+ let mut internal_state = self.state.lock();
+ let id = internal_state.total_entries;
+ let entry = ProgressBarEntry {
+ id,
+ message,
+ pos: Default::default(),
+ total_size: Default::default(),
+ progress_bar: self.clone(),
+ };
+ internal_state.entries.push(entry.clone());
+ internal_state.total_entries += 1;
+ internal_state.keep_alive_count += 1;
+
+ self.maybe_start_draw_thread(&mut internal_state);
+
+ entry
+ }
+
+ fn finish_entry(&self, entry_id: usize) {
+ let mut internal_state = self.state.lock();
+
+ if let Ok(index) = internal_state
+ .entries
+ .binary_search_by(|e| e.id.cmp(&entry_id))
+ {
+ internal_state.entries.remove(index);
+ self.decrement_keep_alive(&mut internal_state);
+ }
+ }
+
+ pub fn increment_clear(&self) {
+ let mut internal_state = self.state.lock();
+ internal_state.keep_alive_count += 1;
+ }
+
+ pub fn decrement_clear(&self) {
+ let mut internal_state = self.state.lock();
+ self.decrement_keep_alive(&mut internal_state);
+ }
+
+ fn decrement_keep_alive(&self, state: &mut InternalState) {
+ state.keep_alive_count -= 1;
+
+ if state.keep_alive_count == 0 {
+ // drop the guard to remove this from the draw thread
+ state.draw_thread_guard.take();
+ }
+ }
+
+ fn maybe_start_draw_thread(&self, internal_state: &mut InternalState) {
+ if internal_state.draw_thread_guard.is_none()
+ && internal_state.keep_alive_count > 0
+ {
+ internal_state.start_time = SystemTime::now();
+ internal_state.draw_thread_guard =
+ Some(DrawThread::add_entry(0, Arc::new(self.clone())));
+ }
+ }
+}
+
+impl DrawThreadRenderer for ProgressBarInner {
+ fn render(&self, size: &ConsoleSize) -> String {
+ let data = {
+ let state = self.state.lock();
+ if state.entries.is_empty() {
+ return String::new();
+ }
+ let preferred_entry = state
+ .entries
+ .iter()
+ .find(|e| e.percent() > 0f64)
+ .or_else(|| state.entries.iter().last())
+ .unwrap();
+ ProgressData {
+ duration: state.start_time.elapsed().unwrap(),
+ terminal_width: size.cols,
+ pending_entries: state.entries.len(),
+ total_entries: state.total_entries,
+ display_entry: ProgressDataDisplayEntry {
+ message: preferred_entry.message.clone(),
+ position: preferred_entry.position(),
+ total_size: preferred_entry.total_size(),
+ },
+ percent_done: {
+ let mut total_percent_sum = 0f64;
+ for entry in &state.entries {
+ total_percent_sum += entry.percent();
+ }
+ total_percent_sum +=
+ (state.total_entries - state.entries.len()) as f64;
+ total_percent_sum / (state.total_entries as f64)
+ },
+ }
+ };
+ self.renderer.render(data)
+ }
+}
+
+#[derive(Clone, Debug)]
pub struct ProgressBar {
- draw_thread: Option<DrawThread>,
+ inner: Option<ProgressBarInner>,
}
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)
+ DrawThread::is_supported()
}
pub fn new(style: ProgressBarStyle) -> Self {
Self {
- draw_thread: match Self::are_supported() {
- true => Some(DrawThread::new(match style {
+ inner: match Self::are_supported() {
+ true => Some(ProgressBarInner::new(match style {
ProgressBarStyle::DownloadBars => {
- Box::new(renderer::BarProgressBarRenderer)
+ Arc::new(renderer::BarProgressBarRenderer)
}
ProgressBarStyle::TextOnly => {
- Box::new(renderer::TextOnlyProgressBarRenderer)
+ Arc::new(renderer::TextOnlyProgressBarRenderer)
}
})),
false => None,
@@ -77,9 +254,9 @@ impl ProgressBar {
}
pub fn update(&self, msg: &str) -> UpdateGuard {
- match &self.draw_thread {
- Some(draw_thread) => {
- let entry = draw_thread.add_entry(msg.to_string());
+ match &self.inner {
+ Some(inner) => {
+ let entry = inner.add_entry(msg.to_string());
UpdateGuard {
maybe_entry: Some(entry),
}
@@ -95,15 +272,15 @@ impl ProgressBar {
}
pub fn clear_guard(&self) -> ClearGuard {
- if let Some(draw_thread) = &self.draw_thread {
- draw_thread.increment_clear();
+ if let Some(inner) = &self.inner {
+ inner.increment_clear();
}
ClearGuard { pb: self.clone() }
}
fn decrement_clear(&self) {
- if let Some(draw_thread) = &self.draw_thread {
- draw_thread.decrement_clear();
+ if let Some(inner) = &self.inner {
+ inner.decrement_clear();
}
}
}
diff --git a/cli/util/progress_bar/renderer.rs b/cli/util/progress_bar/renderer.rs
index 75a4cafed..d8fa1769d 100644
--- a/cli/util/progress_bar/renderer.rs
+++ b/cli/util/progress_bar/renderer.rs
@@ -23,7 +23,7 @@ pub struct ProgressData {
pub duration: Duration,
}
-pub trait ProgressBarRenderer: Send + std::fmt::Debug {
+pub trait ProgressBarRenderer: Send + Sync + std::fmt::Debug {
fn render(&self, data: ProgressData) -> String;
}