19 releases (stable)

new 1.4.1 Dec 11, 2024
1.2.4 Jun 2, 2024
1.1.0 Feb 22, 2024
0.4.0 Jan 18, 2024
0.3.0 Dec 21, 2023

#241 in Data structures

Download history 409/week @ 2024-08-22 368/week @ 2024-08-29 480/week @ 2024-09-05 590/week @ 2024-09-12 570/week @ 2024-09-19 587/week @ 2024-09-26 467/week @ 2024-10-03 607/week @ 2024-10-10 561/week @ 2024-10-17 755/week @ 2024-10-24 890/week @ 2024-10-31 889/week @ 2024-11-07 1726/week @ 2024-11-14 1935/week @ 2024-11-21 957/week @ 2024-11-28 1420/week @ 2024-12-05

6,148 downloads per month
Used in 5 crates

MIT license

1MB
2.5K SLoC

demand

Crates.io docs.rs GitHub License GitHub Workflow Status GitHub issues

A prompt library for Rust. Based on huh? for Go. Maintained by @jdx and @roele.

Input

  • Single-line text input with variable prompt and placeholder
  • Auto-complete suggestions with TAB
  • Validate input with a custom closure

Run example with cargo run --example input.

Input

use demand::Input;

fn main() {
    let notempty_minlen = |s: &str| {
        if s.is_empty() {
            return Err("Name cannot be empty");
        }
        if s.len() < 8 {
            return Err("Name must be at least 8 characters");
        }
        Ok(())
    };

    let t = Input::new("What's your name?")
        .description("We'll use this to personalize your experience.")
        .placeholder("Enter your name")
        .prompt("Name: ")
        .suggestions(vec![
            "Adam Grant",
            "Danielle Steel",
            "Eveline Widmer-Schlumpf",
            "Robert De Niro",
            "Ronaldo Rodrigues de Jesus",
            "Sarah Michelle Gellar",
            "Yael Naim",
            "Zack Snyder",
        ])
        .validation(notempty_minlen);
    let i = t.run().expect("error running input");
}

Password

Run example with cargo run --example input-password.

Input

use demand::Input;

fn main() {
    let t = Input::new("Set a password")
        .placeholder("Enter password")
        .prompt("Password: ")
        .password(true);
    let i = t.run().expect("error running input");
}

List

Shows a list of options. Run example with cargo run --example list.

List

use demand::List;

fn main() {
    let list = List::new("Toppings")
        .description("List of available toppings")
        .item("Lettuce")
        .item("Tomatoes")
        .item("Charm Sauce")
        .item("Jalapenos")
        .item("Cheese")
        .item("Vegan Cheese")
        .item("Nutella")
        .item("Peanut Butter")
        .item("Banana")
        .filterable(true);
    list.run().expect("error running list")
}

Select

Select from a list of options.

Run example with cargo run --example select.

Select

use demand::{DemandOption, Select};

fn main() {
    let ms = Select::new("Toppings")
        .description("Select your topping")
        .filterable(true)
        .option(DemandOption::new("Lettuce").description("Fresh and crispy"))
        .option(DemandOption::new("Tomatoes").description("Juicy and red"))
        .option(DemandOption::new("Charm Sauce").description("Our secret recipe"))
        .option(DemandOption::new("Jalapenos").label("Jalapeños").description("Spicy and hot"))
        .option(DemandOption::new("Cheese").description("Melted and gooey"))
        .option(DemandOption::new("Vegan Cheese").description("Melted and gooey"))
        .option(DemandOption::new("Nutella").description("Sweet and creamy"));
    ms.run().expect("error running select");
}

Multiselect

Select multiple options from a list. Run example with cargo run --example multiselect.

Multiselect

use demand::{DemandOption, MultiSelect};

fn main() {
    let ms = MultiSelect::new("Toppings")
        .description("Select your toppings")
        .min(1)
        .max(4)
        .filterable(true)
        .option(DemandOption::new("Lettuce").selected(true))
        .option(DemandOption::new("Tomatoes").selected(true))
        .option(DemandOption::new("Charm Sauce"))
        .option(DemandOption::new("Jalapenos").label("Jalapeños"))
        .option(DemandOption::new("Cheese"))
        .option(DemandOption::new("Vegan Cheese"))
        .option(DemandOption::new("Nutella"));
    ms.run().expect("error running multi select");
}

Confirm

Confirm a question with a yes or no. Run example with cargo run --example confirm.

Confirm

use demand::Confirm;

fn main() {
    let ms = Confirm::new("Are you sure?")
        .affirmative("Yes!")
        .negative("No.");
    let yes = ms.run().expect("error running confirm");
}

Dialog

Show a dialog with multiple buttons. Run example with cargo run --example dialog.

Dialog

use demand::{Dialog, DialogButton};

fn main() {
    let ms = Dialog::new("Are you sure?")
        .description("This will do a thing.")
        .buttons(vec![
            DialogButton::new("Ok"),
            DialogButton::new("Not sure"),
            DialogButton::new("Cancel"),
        ])
        .selected_button(1);
    ms.run().expect("error running confirm");
}

Spinner

Spinners are used to indicate that a process is running. Run example with cargo run --example spinner.

Spinner

use std::{thread::sleep, time::Duration};

use demand::{Spinner, SpinnerStyle};

fn main() {
    Spinner::new("Loading Data...")
        .style(SpinnerStyle::line())
        .run(|| {
            sleep(Duration::from_secs(2));
        })
        .expect("error running spinner");
}

Themes

Supply your own custom theme or choose from one of the predefined themes:

Derive a custom theme from the default theme.

let theme = Theme {
    selected_prefix: String::from(""),
    selected_prefix_fg: Theme::color_rgb(2, 191, 135),
    unselected_prefix: String::from("  "),
    ..Theme::default()
};

Input::new("What's your e-mail?")
        .description("Please enter your e-mail address.")
        .placeholder("name@domain.com")
        .theme(&theme)
        .run()
        .expect("error running input")?;

Base 16

base16

Charm

Default if colors are enabled in the console.

charm

Catppuccin

catppuccin

Dracula

dracula

New

Default if colors are NOT enabled in the console.

new

"demand"

The name of this library is inspired by a great mistranslation that soured US-French relations in 1830. In French, the verb "demander" means "to ask".

Dependencies

~1.8–8.5MB
~69K SLoC