diff --git a/Cargo.toml b/Cargo.toml index 7c56868..f1adad3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,5 +9,6 @@ readme = "README.md" keywords = ["cli", "prompt", "console"] [dependencies] -console = "0.15" -termcolor = "1" +console = "0.15.8" +once_cell = "1.19.0" +termcolor = "1.4.1" diff --git a/README.md b/README.md index c190f9f..c4d9c56 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ let theme = Theme { Input::new("What's your e-mail?") .description("Please enter your e-mail address.") .placeholder("name@domain.com") - .theme(theme.clone()) + .theme(&theme) .run() .expect("error running input")?; ``` diff --git a/examples/themes.rs b/examples/themes.rs index 913a90d..1ab93a5 100644 --- a/examples/themes.rs +++ b/examples/themes.rs @@ -3,22 +3,19 @@ use std::env::args; use demand::{Confirm, DemandOption, Input, MultiSelect, Theme}; fn main() { - let mut theme = Theme::new(); - match args().nth(1) { - Some(arg) => match arg.as_str() { - "base16" => theme = Theme::base16(), - "charm" => theme = Theme::charm(), - "catppuccin" => theme = Theme::catppuccin(), - "dracula" => theme = Theme::dracula(), - _ => {} - }, - None => {} - } + let theme = match args().nth(1).unwrap_or_default().as_str() { + "base16" => Theme::base16(), + "charm" => Theme::charm(), + "catppuccin" => Theme::catppuccin(), + "dracula" => Theme::dracula(), + "" => Theme::new(), + theme => unimplemented!("theme {} not implemented", theme), + }; let i = Input::new("What's your e-mail?") .description("Please enter your e-mail address.") .placeholder("john.doe@acme.com") - .theme(theme.clone()); + .theme(&theme); i.run().expect("error running input"); let ms = MultiSelect::new("Interests") @@ -33,13 +30,13 @@ fn main() { .option(DemandOption::new("Technology")) .option(DemandOption::new("Travel")) .option(DemandOption::new("Sports")) - .theme(theme.clone()); + .theme(&theme); ms.run().expect("error running multi select"); let c = Confirm::new("Confirm privacy policy") .description("Do you accept the privacy policy?") .affirmative("Yes") .negative("No") - .theme(theme.clone()); + .theme(&theme); c.run().expect("error running confirm"); } diff --git a/src/confirm.rs b/src/confirm.rs index 29f1249..dcd03b3 100644 --- a/src/confirm.rs +++ b/src/confirm.rs @@ -1,11 +1,12 @@ -use crate::theme::Theme; - -use console::{Key, Term}; - use std::io; use std::io::Write; + +use console::{Key, Term}; use termcolor::{Buffer, WriteColor}; +use crate::theme; +use crate::theme::Theme; + /// Select multiple options from a list /// /// # Example @@ -18,11 +19,11 @@ use termcolor::{Buffer, WriteColor}; /// let yes = ms.run().expect("error running confirm"); /// println!("yes: {}", yes); /// ``` -pub struct Confirm { +pub struct Confirm<'a> { /// The title of the selector pub title: String, /// The colors/style of the selector - pub theme: Theme, + pub theme: &'a Theme, /// A description to display above the selector pub description: String, /// The text to display for the affirmative option @@ -35,13 +36,13 @@ pub struct Confirm { height: usize, } -impl Confirm { +impl<'a> Confirm<'a> { /// Create a new multi select with the given title pub fn new>(title: S) -> Self { Self { title: title.into(), description: String::new(), - theme: Theme::default(), + theme: &*theme::DEFAULT, term: Term::stderr(), affirmative: "Yes".to_string(), negative: "No".to_string(), @@ -75,7 +76,7 @@ impl Confirm { } /// Set the theme of the dialog - pub fn theme(mut self, theme: Theme) -> Self { + pub fn theme(mut self, theme: &'a Theme) -> Self { self.theme = theme; self } diff --git a/src/input.rs b/src/input.rs index b55f29d..f4d2b99 100644 --- a/src/input.rs +++ b/src/input.rs @@ -6,7 +6,7 @@ use std::{ use console::{Key, Term}; use termcolor::{Buffer, WriteColor}; -use crate::Theme; +use crate::{theme, Theme}; /// Single line text input /// @@ -18,7 +18,7 @@ use crate::Theme; /// .description("We'll use this to personalize your experience.") /// .placeholder("Enter your name"); /// let name = input.run().expect("error running input"); -pub struct Input { +pub struct Input<'a> { /// The title of the input pub title: String, /// A description to display after the title @@ -34,14 +34,14 @@ pub struct Input { /// Input entered by the user pub input: String, /// Colors/style of the input - pub theme: Theme, + pub theme: &'a Theme, cursor: usize, height: usize, term: Term, } -impl Input { +impl<'a> Input<'a> { /// Creates a new input with the given title. pub fn new>(title: S) -> Self { Self { @@ -52,7 +52,7 @@ impl Input { input: String::new(), inline: false, password: false, - theme: Theme::default(), + theme: &*theme::DEFAULT, cursor: 0, height: 0, term: Term::stderr(), @@ -95,7 +95,7 @@ impl Input { } /// Sets the theme of the input - pub fn theme(mut self, theme: Theme) -> Self { + pub fn theme(mut self, theme: &'a Theme) -> Self { self.theme = theme; self } diff --git a/src/multiselect.rs b/src/multiselect.rs index bc8ec8f..3650900 100644 --- a/src/multiselect.rs +++ b/src/multiselect.rs @@ -1,12 +1,14 @@ -use crate::theme::Theme; -use crate::DemandOption; -use console::{Key, Term}; use std::collections::HashSet; use std::fmt::Display; use std::io; use std::io::Write; + +use console::{Key, Term}; use termcolor::{Buffer, WriteColor}; +use crate::theme::Theme; +use crate::{theme, DemandOption}; + /// Select multiple options from a list /// /// # Example @@ -27,11 +29,11 @@ use termcolor::{Buffer, WriteColor}; /// .option(DemandOption::new("Nutella"));/// /// let toppings = ms.run().expect("error running multi select"); /// ``` -pub struct MultiSelect { +pub struct MultiSelect<'a, T: Display> { /// The title of the selector pub title: String, /// The colors/style of the selector - pub theme: Theme, + pub theme: &'a Theme, /// A description to display above the selector pub description: String, /// The options which can be selected @@ -53,7 +55,7 @@ pub struct MultiSelect { capacity: usize, } -impl MultiSelect { +impl<'a, T: Display> MultiSelect<'a, T> { /// Create a new multi select with the given title pub fn new>(title: S) -> Self { Self { @@ -63,7 +65,7 @@ impl MultiSelect { min: 0, max: usize::MAX, filterable: false, - theme: Theme::default(), + theme: &*theme::DEFAULT, err: None, cursor: 0, height: 0, @@ -107,7 +109,7 @@ impl MultiSelect { } /// Set the theme of the selector - pub fn theme(mut self, theme: Theme) -> Self { + pub fn theme(mut self, theme: &'a Theme) -> Self { self.theme = theme; self } diff --git a/src/option.rs b/src/option.rs index 426b507..09fb0d0 100644 --- a/src/option.rs +++ b/src/option.rs @@ -44,4 +44,5 @@ impl PartialEq for DemandOption { self.id == other.id } } + impl Eq for DemandOption {} diff --git a/src/select.rs b/src/select.rs index c22a505..7448805 100644 --- a/src/select.rs +++ b/src/select.rs @@ -1,12 +1,13 @@ -use crate::theme::Theme; -use crate::DemandOption; -use console::{Key, Term}; - use std::fmt::Display; use std::io; use std::io::Write; + +use console::{Key, Term}; use termcolor::{Buffer, WriteColor}; +use crate::theme::Theme; +use crate::{theme, DemandOption}; + /// Select multiple options from a list /// /// # Example @@ -25,11 +26,11 @@ use termcolor::{Buffer, WriteColor}; /// .option(DemandOption::new("Nutella")); /// let topping = ms.run().expect("error running multi select"); /// ``` -pub struct Select { +pub struct Select<'a, T: Display> { /// The title of the selector pub title: String, /// The colors/style of the selector - pub theme: Theme, + pub theme: &'a Theme, /// A description to display above the selector pub description: String, /// The options which can be selected @@ -46,7 +47,7 @@ pub struct Select { capacity: usize, } -impl Select { +impl<'a, T: Display> Select<'a, T> { /// Create a new select with the given title pub fn new>(title: S) -> Self { Self { @@ -54,7 +55,7 @@ impl Select { description: String::new(), options: vec![], filterable: false, - theme: Theme::default(), + theme: &*theme::DEFAULT, cursor: 0, height: 0, term: Term::stderr(), @@ -85,7 +86,7 @@ impl Select { } /// Set the theme of the selector - pub fn theme(mut self, theme: Theme) -> Self { + pub fn theme(mut self, theme: &'a Theme) -> Self { self.theme = theme; self } diff --git a/src/spinner.rs b/src/spinner.rs index 1deffa1..fae014c 100644 --- a/src/spinner.rs +++ b/src/spinner.rs @@ -7,7 +7,7 @@ use std::{ use console::Term; use termcolor::{Buffer, WriteColor}; -use crate::Theme; +use crate::{theme, Theme}; /// Show a spinner /// @@ -24,26 +24,26 @@ use crate::Theme; /// }) /// .expect("error running spinner"); /// ``` -pub struct Spinner { +pub struct Spinner<'a> { // The title of the spinner pub title: String, // The style of the spinner pub style: SpinnerStyle, /// The colors/style of the spinner - pub theme: Theme, + pub theme: &'a Theme, term: Term, frame: usize, height: usize, } -impl Spinner { +impl<'a> Spinner<'a> { /// Create a new spinner with the given title pub fn new>(title: S) -> Self { Self { title: title.into(), style: SpinnerStyle::line(), - theme: Theme::default(), + theme: &*theme::DEFAULT, term: Term::stderr(), frame: 0, height: 0, @@ -57,7 +57,7 @@ impl Spinner { } /// Set the theme of the dialog - pub fn theme(mut self, theme: Theme) -> Self { + pub fn theme(mut self, theme: &'a Theme) -> Self { self.theme = theme; self } diff --git a/src/theme.rs b/src/theme.rs index e74d872..42289d0 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -1,5 +1,8 @@ +use once_cell::sync::Lazy; use termcolor::{Color, ColorSpec}; +pub(crate) static DEFAULT: Lazy = Lazy::new(Theme::default); + /// Theme for styling the UI. /// /// # Example