Breaking change rework of `WithTitle` to allow for user-specified outputs.

Fortune for termprogress's current commit: Curse − 凶
master
Avril 9 months ago
parent 678483acc1
commit 1c7d85aee0
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -2,7 +2,7 @@
name = "termprogress" name = "termprogress"
description = "A terminal progress bar renderer with status and spinners" description = "A terminal progress bar renderer with status and spinners"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
version = "0.3.4" version = "1.0.0"
authors = ["Avril <flanchan@cumallover.me>"] authors = ["Avril <flanchan@cumallover.me>"]
edition = "2018" edition = "2018"

@ -46,7 +46,17 @@ pub trait Spinner: Display
/// A trait for creating a progress bar or spinner with a title. /// A trait for creating a progress bar or spinner with a title.
pub trait WithTitle: Sized + Display pub trait WithTitle: Sized + Display
{ {
fn with_title(len: usize, string: impl AsRef<str>) -> Self; /// Add a title to this indicator.
#[inline]
fn with_title(mut self, string: impl AsRef<str>) -> Self
{
self.add_title(string);
self
}
/// Add a title to this indicator.
fn add_title(&mut self, string: impl AsRef<str>);
fn update(&mut self); fn update(&mut self);
fn complete(self); fn complete(self);
} }
@ -54,9 +64,13 @@ pub trait WithTitle: Sized + Display
impl<T> WithTitle for Box<T> impl<T> WithTitle for Box<T>
where T: WithTitle + ?Sized where T: WithTitle + ?Sized
{ {
fn with_title(len: usize, string: impl AsRef<str>) -> Self /*fn with_title(len: usize, string: impl AsRef<str>) -> Self
{ {
Box::new(T::with_title(len, string)) Box::new(T::with_title(len, string))
}*/
fn add_title(&mut self, string: impl AsRef<str>) {
(*self).add_title(string.as_ref())
} }
fn update(&mut self) fn update(&mut self)
{ {
@ -180,9 +194,13 @@ where T: Spinner + ?Sized
impl WithTitle for ! impl WithTitle for !
{ {
#[inline] fn with_title(_: usize, _: impl AsRef<str>) -> Self #[inline] fn with_title(mut self, _: impl AsRef<str>) -> Self
{ {
unreachable!() unreachable!()
}
#[inline] fn add_title(&mut self, _: impl AsRef<str>)
{
} }
#[inline] fn update(&mut self) #[inline] fn update(&mut self)
{ {

@ -23,8 +23,9 @@ use std::{
/// # How it looks /// # How it looks
/// It renders in the terminal like: /// It renders in the terminal like:
/// `[========================= ]: 50% this is a title that may get cut if it reaches max le...` /// `[========================= ]: 50% this is a title that may get cut if it reaches max le...`
#[derive(Debug)] #[derive(Debug)]
pub struct Bar/*<T: ?Sized = io::Stdout> //TODO: Implement this after try_new(), WINCH, etc*/ pub struct Bar<T: ?Sized = io::Stdout> //TODO: Implement this after try_new(), WINCH, etc
{ {
width: usize, width: usize,
max_width: usize, max_width: usize,
@ -33,7 +34,7 @@ pub struct Bar/*<T: ?Sized = io::Stdout> //TODO: Implement this after try_new(),
title: String, title: String,
#[cfg(feature="size")] #[cfg(feature="size")]
fit_to_term: bool, fit_to_term: bool,
//output_to: T output: T
} }
/// The default size of the terminal bar when the programmer does not provide her own. /// The default size of the terminal bar when the programmer does not provide her own.
@ -44,35 +45,41 @@ pub const DEFAULT_SIZE: usize = 50;
/// Or if `size` is not used. /// Or if `size` is not used.
pub const DEFAULT_MAX_BORDER_SIZE: usize = 20; pub const DEFAULT_MAX_BORDER_SIZE: usize = 20;
impl/*<T: Default>*/ Default for Bar/*<T>*/ impl<T: Default> Default for Bar<T>
{ {
#[inline] #[inline]
fn default() -> Self fn default() -> Self
{ {
Self::new(DEFAULT_SIZE) Self::new(T::default(), DEFAULT_SIZE)
} }
} }
impl/*<T: io::Write>*/ Bar/*<T>*/ impl<T> Bar<T>
{ {
/// Create a new bar `width` long with a title. /// Create a new bar `width` long with a title.
pub fn with_title(width: usize, title: impl AsRef<str>) -> Self pub fn with_title(output: impl Into<T>, width: usize, title: impl AsRef<str>) -> Self
{ {
let mut this = Self::new(width); let mut this = Self::new(output, width);
this.set_title(title.as_ref()); this.set_title(title.as_ref());
this.update(); this.update();
this this
} }
#[inline] fn add_title(&mut self, title: &str)
{
self.set_title(title);
self.update()
}
/// Attempt to create a new bar with max display width of our terminal and a title. /// Attempt to create a new bar with max display width of our terminal and a title.
/// ///
/// If `stdout` is not a terminal, then `None` is returned. /// If `stdout` is not a terminal, then `None` is returned.
#[cfg(feature="size")] #[cfg(feature="size")]
pub fn try_new_with_title(width: usize, title: impl AsRef<str>) -> Option<Self> pub fn try_new_with_title(output: impl Into<T>, width: usize, title: impl AsRef<str>) -> Option<Self>
{ {
let (terminal_size::Width(tw), _) = terminal_size::terminal_size()?; let (terminal_size::Width(tw), _) = terminal_size::terminal_size()?;
let tw = usize::from(tw); let tw = usize::from(tw);
let mut o = Self::with_max(if width < tw {width} else {tw}, tw); let mut o = Self::with_max(output.into(), if width < tw {width} else {tw}, tw);
o.set_title(title.as_ref()); o.set_title(title.as_ref());
o.fit_to_term = true; o.fit_to_term = true;
o.update(); o.update();
@ -93,24 +100,24 @@ impl/*<T: io::Write>*/ Bar/*<T>*/
/// ///
/// To try to create one that always adheres to `size`, use the `try_new()` family of functions. /// To try to create one that always adheres to `size`, use the `try_new()` family of functions.
#[cfg_attr(not(feature="size"), inline)] #[cfg_attr(not(feature="size"), inline)]
pub fn new(width: usize) -> Self pub fn new(output: impl Into<T>, width: usize) -> Self
{ {
#[cfg(feature="size")] #[cfg(feature="size")]
return { return {
if let Some((terminal_size::Width(tw), _)) = terminal_size::terminal_size() { if let Some((terminal_size::Width(tw), _)) = terminal_size::terminal_size() {
let tw = usize::from(tw); let tw = usize::from(tw);
let mut o = Self::with_max(if width < tw {width} else {tw}, tw); let mut o = Self::with_max(output.into(), if width < tw {width} else {tw}, tw);
o.fit_to_term = true; o.fit_to_term = true;
o o
} else { } else {
let mut o = Self::with_max(width, width + DEFAULT_MAX_BORDER_SIZE); let mut o = Self::with_max(output.into(), width, width + DEFAULT_MAX_BORDER_SIZE);
o.fit_to_term = true; o.fit_to_term = true;
o o
} }
}; };
#[cfg(not(feature="size"))] #[cfg(not(feature="size"))]
return { return {
Self::with_max(width, width +DEFAULT_MAX_BORDER_SIZE) Self::with_max(output.into(), width, width +DEFAULT_MAX_BORDER_SIZE)
}; };
} }
@ -118,11 +125,11 @@ impl/*<T: io::Write>*/ Bar/*<T>*/
/// ///
/// If `stdout` is not a terminal, then `None` is returned. /// If `stdout` is not a terminal, then `None` is returned.
#[cfg(feature="size")] #[cfg(feature="size")]
pub fn try_new(width: usize) -> Option<Self> pub fn try_new(output: impl Into<T>, width: usize) -> Option<Self>
{ {
let (terminal_size::Width(tw), _) = terminal_size::terminal_size()?; let (terminal_size::Width(tw), _) = terminal_size::terminal_size()?;
let tw = usize::from(tw); let tw = usize::from(tw);
let mut o = Self::with_max(if width < tw {width} else {tw}, tw); let mut o = Self::with_max(output, if width < tw {width} else {tw}, tw);
o.fit_to_term = true; o.fit_to_term = true;
Some(o) Some(o)
} }
@ -132,16 +139,16 @@ impl/*<T: io::Write>*/ Bar/*<T>*/
/// If `stdout` is not a terminal, then `None` is returned. /// If `stdout` is not a terminal, then `None` is returned.
#[cfg(feature="size")] #[cfg(feature="size")]
#[inline] #[inline]
pub fn try_new_default_size() -> Option<Self> pub fn try_new_default_size(to: impl Into<T>) -> Option<Self>
{ {
Self::try_new(DEFAULT_SIZE) Self::try_new(to, DEFAULT_SIZE)
} }
/// Create a bar with a max display width /// Create a bar with a max display width
/// ///
/// # Panics /// # Panics
/// If `width` is larger than or equal to `max_width`. /// If `width` is larger than or equal to `max_width`.
pub fn with_max(width: usize, max_width: usize) -> Self pub fn with_max(output: T, width: usize, max_width: usize) -> Self
{ {
let mut this = Self { let mut this = Self {
width, width,
@ -151,12 +158,16 @@ impl/*<T: io::Write>*/ Bar/*<T>*/
title: String::with_capacity(max_width - width), title: String::with_capacity(max_width - width),
#[cfg(feature="size")] #[cfg(feature="size")]
fit_to_term: false, fit_to_term: false,
/*output_to: io::stdout(),*/ output
}; };
this.update(); this.update();
this this
} }
}
impl<T: ?Sized> Bar<T> {
/// Fit to terminal's width if possible. /// Fit to terminal's width if possible.
/// ///
/// # Notes /// # Notes
@ -254,7 +265,7 @@ fn ensure_lower(input: String, to: usize) -> String
} }
} }
impl Display for Bar impl<T: ?Sized + io::Write> Display for Bar<T>
{ {
fn refresh(&self) fn refresh(&self)
{ {
@ -293,7 +304,7 @@ impl Display for Bar
} }
} }
impl ProgressBar for Bar impl<T: ?Sized + io::Write> ProgressBar for Bar<T>
{ {
fn get_progress(&self) -> f64 fn get_progress(&self) -> f64
{ {
@ -309,11 +320,11 @@ impl ProgressBar for Bar
} }
} }
impl WithTitle for Bar impl<T: io::Write> WithTitle for Bar<T>
{ {
fn with_title(len: usize, string: impl AsRef<str>) -> Self fn add_title(&mut self, string: impl AsRef<str>)
{ {
Self::with_title(len, string) (*self).add_title(string.as_ref())
} }
fn update(&mut self) fn update(&mut self)
{ {
@ -324,3 +335,25 @@ impl WithTitle for Bar
self.complete(); self.complete();
} }
} }
const _:() = {
const fn declval<T>() -> Bar<T> {
unreachable!()
}
fn take_title(_: &(impl WithTitle + ?Sized)) {}
fn take_progress(_: &(impl ProgressBar + ?Sized)) {}
fn take_display(_: &(impl Display + ?Sized)) {}
fn test()
{
#[macro_export] macro_rules! assert_is_bar {
($ty:path) => {
take_title(&declval::<$ty>());
take_progress(&declval::<$ty>());
take_display(&declval::<$ty>());
}
}
assert_is_bar!(io::Stdout);
assert_is_bar!(std::fs::File);
}
};

@ -35,7 +35,8 @@ impl Spinner for Silent
impl WithTitle for Silent impl WithTitle for Silent
{ {
#[inline] fn with_title(_: usize, _: impl AsRef<str>) -> Self{Self} #[inline] fn with_title(self, _: impl AsRef<str>) -> Self{self}
#[inline] fn add_title(&mut self, _: impl AsRef<str>) {}
#[inline] fn update(&mut self) {} #[inline] fn update(&mut self) {}
#[inline] fn complete(self) {} #[inline] fn complete(self) {}
} }
@ -138,16 +139,28 @@ impl<T> Spinner for MaybeSilent<T>
impl<T> WithTitle for MaybeSilent<T> impl<T> WithTitle for MaybeSilent<T>
where T: WithTitle where T: WithTitle
{ {
fn with_title(len: usize, string: impl AsRef<str>) -> Self #[inline]
fn add_title(&mut self, string: impl AsRef<str>) {
if let Self::Loud(this) = self {
this.add_title(string);
}
}
#[inline]
fn with_title(self, string: impl AsRef<str>) -> Self
{ {
Self::Loud(T::with_title(len, string)) match self {
Self::Loud(l) => Self::Loud(T::with_title(l, string)),
n => n,
}
} }
#[inline]
fn update(&mut self) fn update(&mut self)
{ {
if let Self::Loud(this) = self { if let Self::Loud(this) = self {
this.update() this.update()
} }
} }
#[inline]
fn complete(self) fn complete(self)
{ {
if let Self::Loud(this) = self { if let Self::Loud(this) = self {

@ -125,9 +125,19 @@ impl Spinner for Spin
impl WithTitle for Spin impl WithTitle for Spin
{ {
fn with_title(_: usize, t: impl AsRef<str>) -> Self #[inline]
fn with_title(self, t: impl AsRef<str>) -> Self
{ {
Self::with_title(t.as_ref(), Default::default()) Self {
title: t.as_ref().to_owned(),
..self
}
}
#[inline]
fn add_title(&mut self, t: impl AsRef<str>)
{
self.title = t.as_ref().to_owned();
// Self::with_title(t.as_ref(), Default::default())
} }
#[inline] fn update(&mut self){} #[inline] fn update(&mut self){}
#[inline] fn complete(self) #[inline] fn complete(self)

Loading…
Cancel
Save