Skip to content

Commit

Permalink
Print Cargo logs with SpinnerBar
Browse files Browse the repository at this point in the history
  • Loading branch information
maciektr committed Jun 6, 2024
1 parent 34c5945 commit 0d96c1b
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 5 deletions.
10 changes: 8 additions & 2 deletions utils/scarb-ui/src/components/spinner.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::time::Duration;

use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle, WeakProgressBar};

use crate::Widget;
use crate::{Widget, WidgetHandle};

/// Spinner widget informing about an ongoing process.
pub struct Spinner {
Expand Down Expand Up @@ -33,6 +33,12 @@ impl Drop for SpinnerHandle {
}
}

impl WidgetHandle for SpinnerHandle {
fn weak_progress_bar(&self) -> Option<WeakProgressBar> {
Some(self.pb.downgrade())
}
}

impl Widget for Spinner {
type Handle = SpinnerHandle;

Expand Down
44 changes: 42 additions & 2 deletions utils/scarb-ui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
#![warn(rust_2018_idioms)]

use clap::ValueEnum;
use indicatif::WeakProgressBar;
pub use indicatif::{
BinaryBytes, DecimalBytes, FormattedDuration, HumanBytes, HumanCount, HumanDuration,
HumanFloatCount,
};
use std::fmt::Debug;
use std::sync::{Arc, RwLock};

pub use message::*;
pub use verbosity::*;
Expand Down Expand Up @@ -53,10 +56,29 @@ pub enum OutputFormat {
/// colour, etc.
///
/// All human-oriented messaging (basically all writes to `stdout`) must go through this object.
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct Ui {
verbosity: Verbosity,
output_format: OutputFormat,
state: Arc<RwLock<State>>,
}

impl Debug for Ui {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Ui")
.field("verbosity", &self.verbosity)
.field("output_format", &self.output_format)
.finish()
}
}

/// An encapsulation of the UI state.
///
/// This can be used by `Ui` to store stateful information.
#[derive(Default)]
#[non_exhaustive]
struct State {
active_spinner: WeakProgressBar,
}

impl Ui {
Expand All @@ -65,6 +87,7 @@ impl Ui {
Self {
verbosity,
output_format,
state: Default::default(),
}
}

Expand Down Expand Up @@ -103,6 +126,12 @@ impl Ui {
pub fn widget<T: Widget>(&self, widget: T) -> Option<T::Handle> {
if self.output_format == OutputFormat::Text && self.verbosity >= Verbosity::Normal {
let handle = widget.text();
if let Some(handle) = handle.weak_progress_bar() {
self.state
.write()
.expect("cannot lock ui state for writing")
.active_spinner = handle;
}
Some(handle)
} else {
None
Expand Down Expand Up @@ -148,9 +177,20 @@ impl Ui {
}

fn do_print<T: Message>(&self, message: T) {
match self.output_format {
let print = || match self.output_format {
OutputFormat::Text => message.print_text(),
OutputFormat::Json => message.print_json(),
};
let handle = self
.state
.read()
.expect("cannot lock ui state for reading")
.active_spinner
.clone();
if let Some(pb) = handle.upgrade() {
pb.suspend(print);
} else {
print();
}
}

Expand Down
10 changes: 9 additions & 1 deletion utils/scarb-ui/src/widget.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
use indicatif::WeakProgressBar;

/// A persistent message that is only usable for humans, for example a spinner.
pub trait Widget {
/// Allows for live interaction with the widget, and its drop is called when the widget should
/// be cleared.
type Handle;
type Handle: WidgetHandle;

/// Display the widget on the standard output, and return a handle for further interaction.
fn text(self) -> Self::Handle;
}

/// A handle to a widget that allows for further interaction.
pub trait WidgetHandle {
#[doc(hidden)]
fn weak_progress_bar(&self) -> Option<WeakProgressBar>;
}

0 comments on commit 0d96c1b

Please sign in to comment.