Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ include = ["CHANGELOG.md", "Cargo.toml", "LICENSE", "README.md", "src/**/*.rs"]

[features]
default = ["unicode-width", "ansi-parsing", "std"]
std = ["dep:libc", "alloc"]
std = ["dep:libc", "dep:anstyle-progress", "alloc"]
alloc = []
windows-console-colors = ["ansi-parsing"]
ansi-parsing = []

[dependencies]
anstyle-progress = { version = "0.1.3", optional = true }
libc = { version = "0.2.99", optional = true }
unicode-width = { version = "0.2", optional = true }

Expand Down
8 changes: 5 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,11 @@ pub use crate::term::{
#[cfg(feature = "std")]
pub use crate::utils::{
colors_enabled, colors_enabled_stderr, measure_text_width, pad_str, pad_str_with,
set_colors_enabled, set_colors_enabled_stderr, set_true_colors_enabled,
set_true_colors_enabled_stderr, style, true_colors_enabled, true_colors_enabled_stderr,
truncate_str, Alignment, Attribute, Color, Emoji, Style, StyledObject,
progress_integration, progress_integration_stderr, set_colors_enabled,
set_colors_enabled_stderr, set_progress_integration, set_progress_integration_stderr,
set_true_colors_enabled, set_true_colors_enabled_stderr, style, true_colors_enabled,
true_colors_enabled_stderr, truncate_str, Alignment, Attribute, Color, Emoji, Style,
StyledObject, TermProgress,
};

#[cfg(all(feature = "ansi-parsing", feature = "alloc"))]
Expand Down
5 changes: 5 additions & 0 deletions src/term.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ impl TermFeatures<'_> {
is_a_true_color_terminal(self.0)
}

/// The termninal supports integrated progress reporting.
pub fn progress_integration_supported(&self) -> bool {
anstyle_progress::supports_term_progress(self.is_attended())
}

/// Check if this terminal is an msys terminal.
///
/// This is sometimes useful to disable features that are known to not
Expand Down
134 changes: 134 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ fn stdout_true_colors() -> &'static AtomicBool {
static ENABLED: OnceLock<AtomicBool> = OnceLock::new();
ENABLED.get_or_init(|| AtomicBool::new(default_true_colors_enabled(&Term::stdout())))
}
fn stdout_progress_integration() -> &'static AtomicBool {
static ENABLED: OnceLock<AtomicBool> = OnceLock::new();
ENABLED
.get_or_init(|| AtomicBool::new(Term::stdout().features().progress_integration_supported()))
}
fn stderr_colors() -> &'static AtomicBool {
static ENABLED: OnceLock<AtomicBool> = OnceLock::new();
ENABLED.get_or_init(|| AtomicBool::new(default_colors_enabled(&Term::stderr())))
Expand All @@ -38,6 +43,11 @@ fn stderr_true_colors() -> &'static AtomicBool {
static ENABLED: OnceLock<AtomicBool> = OnceLock::new();
ENABLED.get_or_init(|| AtomicBool::new(default_true_colors_enabled(&Term::stderr())))
}
fn stderr_progress_integration() -> &'static AtomicBool {
static ENABLED: OnceLock<AtomicBool> = OnceLock::new();
ENABLED
.get_or_init(|| AtomicBool::new(Term::stderr().features().progress_integration_supported()))
}

/// Returns `true` if colors should be enabled for stdout.
///
Expand All @@ -57,6 +67,12 @@ pub fn true_colors_enabled() -> bool {
stdout_true_colors().load(Ordering::Relaxed)
}

/// Returns `true` if the terminal-integrated progress should be enabled for stdout.
#[inline]
pub fn progress_integration() -> bool {
stdout_progress_integration().load(Ordering::Relaxed)
}

/// Forces colorization on or off for stdout.
///
/// This overrides the default for the current process and changes the return value of the
Expand All @@ -75,6 +91,15 @@ pub fn set_true_colors_enabled(val: bool) {
stdout_true_colors().store(val, Ordering::Relaxed)
}

/// Forces terminal-integrated progress on or off for stdout.
///
/// This overrides the default for the current process and changes the return value of the
/// `progress_integration` function.
#[inline]
pub fn set_progress_integration(val: bool) {
stdout_progress_integration().store(val, Ordering::Relaxed)
}

/// Returns `true` if colors should be enabled for stderr.
///
/// This honors the [clicolors spec](http://bixense.com/clicolors/).
Expand All @@ -93,6 +118,12 @@ pub fn true_colors_enabled_stderr() -> bool {
stderr_true_colors().load(Ordering::Relaxed)
}

/// Returns `true` if the terminal-integrated progress should be enabled for stderr.
#[inline]
pub fn progress_integration_stderr() -> bool {
stderr_progress_integration().load(Ordering::Relaxed)
}

/// Forces colorization on or off for stderr.
///
/// This overrides the default for the current process and changes the return value of the
Expand All @@ -111,6 +142,15 @@ pub fn set_true_colors_enabled_stderr(val: bool) {
stderr_true_colors().store(val, Ordering::Relaxed)
}

/// Forces terminal-integrated progress on or off for stderr.
///
/// This overrides the default for the current process and changes the return value of the
/// `progress_integration_stderr` function.
#[inline]
pub fn set_progress_integration_stderr(val: bool) {
stderr_progress_integration().store(val, Ordering::Relaxed)
}

/// Measure the width of a string in terminal characters.
pub fn measure_text_width(s: &str) -> usize {
#[cfg(feature = "ansi-parsing")]
Expand Down Expand Up @@ -1036,6 +1076,100 @@ pub fn pad_str_with<'a>(
Cow::Owned(rv)
}

#[derive(Clone, Debug)]
pub struct TermProgress {
inner: anstyle_progress::TermProgress,
force: Option<bool>,
for_stderr: bool,
}

impl Default for TermProgress {
fn default() -> Self {
Self::new()
}
}

impl TermProgress {
pub const fn new() -> Self {
Self {
inner: anstyle_progress::TermProgress::none(),
force: None,
for_stderr: false,
}
}

/// Forces terminal-integrated progress on or off.
///
/// This overrides the automatic detection.
#[inline]
pub const fn force_styling(mut self, value: bool) -> Self {
self.force = Some(value);
self
}

/// Specifies that terminal-integrated progress is being written on stderr.
#[inline]
pub const fn for_stderr(mut self) -> Self {
self.for_stderr = true;
self
}

/// Specifies that terminal-integrated progress is being written on stdout.
///
/// This is the default behaviour.
#[inline]
pub const fn for_stdout(mut self) -> Self {
self.for_stderr = false;
self
}

/// Start a progress indicator
///
/// This starts in an indeterminate state
pub const fn start(mut self) -> Self {
self.inner = self
.inner
.status(anstyle_progress::TermProgressStatus::Normal);
self
}

/// Set progress percentage (between `0..=100`)
///
/// Without setting this, progress will be indeterminate
pub const fn percent(mut self, percent: u8) -> Self {
self.inner = self.inner.percent(percent);
self
}

/// Start an error indicator
pub const fn error(mut self) -> Self {
self.inner = self
.inner
.status(anstyle_progress::TermProgressStatus::Error);
self
}

/// Remove the indicator
pub const fn remove(mut self) -> Self {
self.inner = self
.inner
.status(anstyle_progress::TermProgressStatus::Removed);
self
}
}

impl fmt::Display for TermProgress {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.force.unwrap_or_else(|| match self.for_stderr {
true => progress_integration_stderr(),
false => progress_integration(),
}) {
fmt::Display::fmt(&self.inner, f)?;
}
Ok(())
}
}

#[test]
fn test_text_width() {
let s = style("foo")
Expand Down
Loading