A Rust library for building interactive prompts

Overview

Latest Version Build status Supported platforms License



inquire is a library for building interactive prompts on terminals.


Demo

Animated GIF making a demonstration of a questionnaire created with this library. You can replay this recording in your terminal with asciinema play command - asciinema play ./assets/expense_tracker.cast Source

Usage

Put this line in your Cargo.toml, under [dependencies].

inquire = "0.0.6"

Examples

Examples can be found in the examples directory. Run them to see basic behavior:

$ cargo run --example expense_tracker --features date

Features

  • Cross-platform, supporting UNIX and Windows terminals (thanks to crossterm).
  • Five (5) kinds of prompts and their own custom features (to see the full list of features check the full documentation below):
    • Text input, with auto-completion support.
    • Date picker, with support to limit allowed date ranges.
    • Selection inputs, with support for single and multiple selections, as well as custom filtering based on user input.
    • Confirm prompt, with support for custom parsing of input.
    • Password prompt, where user input is not echoed back to the terminal.
  • Standardized error handling (thanks to thiserror)
  • Support for customized help messages.
  • Support for default values.
  • Support for validation of user input.
  • Support for custom formatting of user input after it is submitted and echoed back to the terminal.
  • Fine-grained configuration, e.g. page size of option list, vim mode for navigation, etc.

Cross-cutting concerns

There are several features that are shared among different types of prompts. This section will give an overview on each of them.

Validation

Almost all prompts provide an API to set custom validators.

The validators provided to a given prompt are called whenever the user submits their input. These validators vary by prompt type, receiving different types of variables as arguments, such as &str, &[OptionAnswer], or NaiveDate, but their return type are always the same: Result<(), String>.

If the input provided by the user is invalid, your validator should return Ok(()).

If the input is not valid, your validator should return Err(String), where the content of Err is a string whose content will be displayed to the user as an error message. It is recommended that this value gives a helpful feedback to the user, e.g. "This field should contain at least 5 characters".

The validators are typed as a reference to dyn Fn. This allows both functions and closures to be used as validators, but it also means that the functions can not hold any mutable references.

Finally, inquire has a feature called builtin_validators that is included by default. When the feature is on, several built-in validators are exported at the root-level of the library in the form of macros, check their documentation to see more details.

The docs provide full-featured examples.

In the demo on the top of this README, you can see the behavior of an input not passing the requirements in the amount prompt, when the error message "Please type a valid number" is displayed. Full disclosure, this error message was displayed due to a parsing, not validation, error, but the user experience is the same for both cases.

Formatting

Formatting is the process of transforming the user input into a readable output displayed after the user submits their response. By default, this is in some cases just echoing back the input itself, such as in Text prompts. Other prompts have different formatting rules by default, for example DateSelect which formats the selected date into something like "August 5, 2021".

All prompts provide an API to set custom formatters. By setting a formatter, you can customize how the user's response is displayed to them. For example, you might want to format a selected date into a new format such as "05/08/2021".

Custom formatters receive the input as an argument, with varying types such as &str, chrono::NaiveDate, and return a String containing the output to be displayed to the user. Check the docs for specific examples.

In the demo on the top of this README, you can see this behavior in action with the amount (CustomType) prompt, where a custom formatter adds a '$' character preffix to the input.

Parsing

Parsing features are related to two prompts: Confirm and CustomType. They return to you a value (of types bool or any custom type you might want) parsed from the user's text input. In both cases, you can either use default parsers that are already built-in or provide custom ones adhering to the function signatures.

The default bool parser returns true if the input is either "y" or "yes", in a case-insensitive comparison. Similarly, the parser returns false if the input is either "n" or "no".

The default parser for CustomType prompts calls the parse::<T>() method on the input string. This means that if you want to create a CustomType with default settings, the wanted return type must implement the FromStr trait.

In the demo on the top of this README, you can see this behavior in action with the amount (CustomType) prompt.

Filtering

Filtering is applicable to two prompts: Select and MultiSelect. They provide the user the ability to filter the options based on their text input. This is specially useful when there are a lot of options for the user to choose from, allowing them to quickly find their expected options.

Filter functions receive three arguments: the current user input, the option string value and the option index. They must return a bool value indicating whether the option should be part of the results or not.

The default filter function does a naive case-insensitive comparison between the option string value and the current user input, returning true if the option string value contains the user input as a substring.

In the demo on the top of this README, you can see this behavior in action with the account (Select) and tags (MultiSelect) prompts.

Error handling

Error handling when using inquire is pretty simple. Instantiating prompt structs is not fallible by design, in order to avoid requiring chaining of map and and_then methods to subsequent configuration method calls such as with_help_message(). All fallible operations are exposable only when you call prompt() on the instantiated prompt struct.

prompt calls return a Result containing either your expected response value or an Err of type 'InquireError. An InquireError` has the following variants:

  • NotTTY: The input device is not a TTY, which means that enabling raw mode on the terminal in order to listen to input events is not possible. I currently do not know if it is possible to make the library work even if that's the case.
  • InvalidConfiguration(String): Some aspects of the prompt configuration were considered to be invalid, with more details given in the value string.
    • This error is only possible in Select, MultiSelect and DateSelect prompts, where specific settings might be incompatible. All other prompts always have valid configurations by design.
  • IO(io::Error): There was an error when performing IO operations. IO errors are not handled inside inquire to keep the library simple.
  • OperationCanceled: The user canceled the prompt before submitting a response. The user might cancel the operation by pressing Ctrl-C or ESC.

Prompts

Currently, there are 5 different prompt types supported.

Text

Text is the standard kind of prompt you would expect from a library like this one. It displays a message to the user, prompting them to type something back. The user's input is then stored in a String and returned to the prompt caller.

let name = Text::new("What is your name?").prompt();

match name {
    Ok(name) => println!("Hello {}", name),
    Err(_) => println!("An error happened when asking for your name, try again later."),
}

Animated GIF making a demonstration of a simple prompt with Text created with this library. You can replay this recording in your terminal with asciinema play command using the file ./assets/text_simple.cast

With Text, you can customize several aspects:

  • Prompt message: Main message when prompting the user for input, "What is your name?" in the example above.
  • Help message: Message displayed at the line below the prompt.
  • Default value: Default value returned when the user submits an empty response.
  • Validators: Custom validators to the user's input, displaying an error message if the input does not pass the requirements.
  • Formatter: Custom formatter in case you need to pre-process the user input before showing it as the final answer.

Autocomplete

With Text inputs, it is also possible to set-up an auto-completion system to provide a better UX when necessary.

You can set-up a custom Suggester function, which receives the current input as the only argument and should return a vector of strings, all of the suggested values.

The user is then able to select one of them by moving up and down the list, possibly further modifying a selected suggestion.

In the demo on the top of this README, you can see this behavior in action with the payee prompt.

Default behaviors

Default behaviors for each one of Text configuration options:

  • The input formatter just echoes back the given input.
  • No validators are called, accepting any sort of input including empty ones.
  • No default values or help messages.
  • No auto-completion features set-up.
  • Prompt messages are always required when instantiating via new().

DateSelect

Animated GIF making a demonstration of a DateSelect prompt created with this library. You can replay this recording in your terminal with asciinema play command using the file ./assets/date_complete.cast

let date = DateSelect::new("When do you want to travel?")
    .with_default(chrono::NaiveDate::from_ymd(2021, 8, 1))
    .with_min_date(chrono::NaiveDate::from_ymd(2021, 8, 1)) 
    .with_max_date(chrono::NaiveDate::from_ymd(2021, 12, 31))
    .with_week_start(chrono::Weekday::Mon)
    .with_help_message("Possible flights will be displayed according to the selected date")
    .prompt();

match date {
    Ok(_) => println!("No flights available for this date."),
    Err(_) => println!("There was an error in the system."),
}

DateSelect prompts allows user to select a date (time not supported) from an interactive calendar. This prompt is only available when including the date feature in the dependency, as it brings an additional module (chrono) in your dependency tree.

DateSelect prompts provide several options of configuration:

  • Prompt message: Required when creating the prompt.
  • Default value: Default value selected when the calendar is displayed and the one select if the user submits without any previous actions. Current date by default.
  • Help message: Message displayed at the line below the prompt.
  • Formatter: Custom formatter in case you need to pre-process the user input before showing it as the final answer.
    • Formats to "Month Day, Year" by default.
  • Validators: Custom validators to the user's selected date, displaying an error message if the date does not pass the requirements.
  • Week start: Which day of the week should be displayed in the first column of the calendar.
    • Sunday by default.
  • Min and max date: Inclusive boundaries of allowed dates in the interactive calendar.
    • None by default.
  • Vim mode: Allows the user to navigate using hjkl keys, off by default.

Select

Animated GIF making a demonstration of a simple Select prompt created with this library. You can replay this recording in your terminal with asciinema play command using the file ./assets/select.cast

let options = vec!["Banana", "Apple", "Strawberry", "Grapes",
    "Lemon", "Tangerine", "Watermelon", "Orange", "Pear", "Avocado", "Pineapple",
];

let ans = Select::new("What's your favorite fruit?", &options).prompt();

match ans {
    Ok(choice) => println!("I also love {}!", choice.value),
    Err(_) => println!("There was an error, please try again"),
}

The Select prompt is created with a prompt message and a non-empty list of options. It is suitable for when you need the user to select one option among many.

The Select prompt does not support custom validators because of the nature of the prompt. A submission always selects exactly one of the options. If this option was not supposed to be selected or is invalid in some way, it probably should not be included in the options list.

The options are paginated in order to provide a smooth experience to the user, with the default page size being 7. The user can move from the options and the pages will be updated accordingly, including moving from the last to the first options (or vice-versa).

The user can submit their choice by pressing either space or enter.

Like all others, this prompt also allows you to customize several aspects of it:

  • Prompt message: Required when creating the prompt.
  • Options list: Options displayed to the user.
  • Starting cursor: Index of the cursor when the prompt is first rendered. Default is 0 (first option).
  • Help message: Message displayed at the line below the prompt.
  • Formatter: Custom formatter in case you need to pre-process the user input before showing it as the final answer.
    • Prints the selected option string value by default.
  • Vim mode: Allows the user to navigate using hjkl keys, off by default.
  • Page size: Number of options displayed at once, 7 by default.
  • Filter function: Function that defines if an option is displayed or not based on the current filter input.

MultiSelect

Animated GIF making a demonstration of a simple MultiSelect prompt created with this library. You can replay this recording in your terminal with asciinema play command using the file ./assets/multiselect.cast

The source is too long, find it here.

The MultiSelect prompt is created with a prompt message and a non-empty list of options. It is suitable for when you need the user to select many options (including none if applicable) among a list of them.

The options are paginated in order to provide a smooth experience to the user, with the default page size being 7. The user can move from the options and the pages will be updated accordingly, including moving from the last to the first options (or vice-versa).

The user can pick the current selection by pressing space, cleaning all selections by pressing the left arrow and selecting all options by pressing the right arrow.

Like all others, this prompt also allows you to customize several aspects of it:

  • Prompt message: Required when creating the prompt.
  • Options list: Options displayed to the user.
  • Default selections: Options that are selected by default when the prompt is first rendered. The user can unselect them.
  • Starting cursor: Index of the cursor when the prompt is first rendered. Default is 0 (first option).
  • Help message: Message displayed at the line below the prompt.
  • Formatter: Custom formatter in case you need to pre-process the user input before showing it as the final answer.
    • Prints the selected options string value, joined using a comma as the separator, by default.
  • Validator: Custom validator to make sure a given submitted input pass the specified requirements, e.g. not allowing 0 selected options or limiting the number of options that the user is allowed to select.
    • No validators are on by default.
  • Vim mode: Allows the user to navigate using hjkl keys, off by default.
  • Page size: Number of options displayed at once, 7 by default.
  • Filter function: Function that defines if an option is displayed or not based on the current filter input.
  • Keep filter flag: Whether the current filter input should be cleared or not after a selection is made. Defaults to true.

Password

Animated GIF making a demonstration of a simple Password prompt created with this library. You can replay this recording in your terminal with asciinema play command using the file ./assets/password_simple.cast

let name = Password::new("Encryption key:").prompt();

match name {
    Ok(_) => println!("This doesn't look like a key."),
    Err(_) => println!("An error happened when asking for your key, try again later."),
}

Password prompts are basically a less-featured version of Text prompts. Differences being:

  • User input is not echoed back to the terminal while typing.
  • User input is formatted to "********" (eight star characters) by default.
  • No support for default values.
  • No support for auto-completion, obviously.

However, it is still possible to customize error messages, formatters and validators.

CustomType

Animated GIF making a demonstration of a simple CustomType prompt created with this library. You can replay this recording in your terminal with asciinema play command using the file ./assets/custom_type.cast

let amount = CustomType::<f64>::new("How much do you want to donate?")
    .with_formatter(&|i| format!("${:.2}", i))
    .with_error_message("Please type a valid number")
    .with_help_message("Type the amount in US dollars using a decimal point as a separator")
    .prompt();

match amount {
    Ok(_) => println!("Thanks a lot for donating that much money!"),
    Err(_) => println!("We could not process your donation"),
}

CustomType prompts are generic prompts suitable for when you need to parse the user input into a specific type, for example an f64 or a rust_decimal, maybe even an uuid.

This prompt has all of the validation, parsing and error handling features built-in to reduce as much boilerplaste as possible from your prompts.

After the user submits, the prompt handler tries to parse the input into the expected type. If the operation succeeds, the value is returned to the prompt caller. If it fails, the message defined in error_message is displayed to the user.

When initializing this prompt via the new() method, some constraints on the return type T are added to make sure we can apply a default parser and formatter to the prompt.

The default parser calls the str.parse method, which means that T must implement the FromStr trait. When the parsing fails for any reason, a default error message "Invalid input" is displayed to the user.

The default formatter simply calls to_string() on the parsed value, which means that T must implement the ToString trait, which normally happens implicitly when you implement the Display trait.

If your type T does not satisfy these constraints, you can always manually instantiate the entire struct yourself like this:

let amount_prompt: CustomType<chrono::NaiveDate> = CustomType {
    message: "When will you travel?",
    formatter: &|val| val.format("%d/%m/%Y").to_string(),
    default: None,
    error_message: "Please type a valid date in the expected format.".into(),
    help_message: "The date should be in the dd/mm/yyyy format.".into(),
    parser: &|i| match chrono::NaiveDate::parse_from_str(i, "%d/%m/%Y") {
        Ok(val) => Ok(val),
        Err(_) => Err(()),
    },
};

Confirm

Animated GIF making a demonstration of a simple Confirm prompt created with this library. You can replay this recording in your terminal with asciinema play command using the file ./assets/confirm_simple.cast

let ans = Confirm::new("Do you live in Brazil?")
    .with_default(false)
    .with_help_message("This data is stored for good reasons")
    .prompt();

match ans {
    Ok(true) => println!("That's awesome!"),
    Ok(false) => println!("That's too bad, I've heard great things about it."),
    Err(_) => println!("Error with questionnaire, try again later"),
}

The Confirm is basically a wrapper around the behavior of CustomType prompts, providing a sensible set of defaults to ask for simple true/false questions, such as confirming an action.

The Confirm prompt does not support custom validators because of the nature of the prompt. The user input is always parsed to true or false. If one of the two alternatives is invalid, a Confirm prompt that only allows yes or no answers does not make a lot of sense to me, but if someone provides a clear use-case I will reconsider.

Confirm prompts provide several options of configuration:

  • Prompt message: Required when creating the prompt.
  • Default value: Default value returned when the user submits an empty response.
  • Help message: Message displayed at the line below the prompt.
  • Formatter: Custom formatter in case you need to pre-process the user input before showing it as the final answer.
    • Formats true to "Yes" and false to "No", by default.
    • Useful to set in case you might want to internationalize your prompts.
  • Parser: Custom parser for user inputs.
    • The default bool parser returns true if the input is either "y" or "yes", in a case-insensitive comparison. Similarly, the parser returns false if the input is either "n" or "no".
    • Useful to set in case you might want to internationalize your prompts, allowing different responses besides yes and no.
  • Default value formatter: Function that formats how the default value is displayed to the user.
    • By default, displays "y/n" with the default value capitalized, e.g. "y/N".
  • Error message: Error message to display when a value could not be parsed from the input.
    • Set to "Invalid answer, try typing 'y' for yes or 'n' for no" by default.
Comments
  • Tab autocompletion doesn't seem to be working in iTerm 2/Terminal

    Tab autocompletion doesn't seem to be working in iTerm 2/Terminal

    Describe the bug

    I'm trying the text suggestions in 0.3.0-alpha.2 in a terminal on macOS; it tells me I can use "tab to auto-complete", but it doesn't seem to work.

    Reproduction project

    This is my Cargo.toml:

    [package]
    name = "example"
    version = "0.1.0"
    edition = "2021"
    
    [dependencies]
    inquire = "0.3.0-alpha.2"
    

    and this is my main.rs, which is a simplified version of examples/text_options.rs:

    use inquire::{error::CustomUserError, Text};
    
    fn suggester(val: &str) -> Result<Vec<String>, CustomUserError> {
        let suggestions = ["andrew", "charles", "christopher"];
    
        Ok(suggestions
            .iter()
            .filter(|s| s.contains(&val))
            .map(|s| String::from(*s))
            .collect())
    }
    
    fn main() {
        let answer = Text::new("What's your name?")
            .with_suggester(&suggester)
            .prompt()
            .unwrap();
    
        println!("Hello {}", answer);
    }
    

    Expected/actual behaviour

    If I run the code, I get a prompt with three suggestions:

    Screenshot 2022-08-16 at 20 43 45

    If I then type cha for charles, my selection reduces to a single item:

    Screenshot 2022-08-16 at 20 45 33

    At this point, I expect that pressing tab will complete to charles, but as far as I can tell nothing happens.

    Desktop

    • OS: macOS Catalina 10.15.7
    • Terminal: iTerm 2 3.4.16 and Terminal 2.10; I get the same behaviour in both
    • Version: 0.3.0-alpha.2

    Additional context

    I can reproduce this error if I swap out the back-ends, in particular either of the following lines in my Cargo.toml have the same behaviour:

    inquire = { version = "0.3.0-alpha.2", features = ["console"] }
    
    inquire = { version = "0.3.0-alpha.2", features = ["termion"] }
    
    bug 
    opened by alexwlchan 10
  • Allow user to manually input a date

    Allow user to manually input a date

    Is your feature request related to a problem? Please describe.

    The user might not want to manually navigate through several days/months/years when trying to input a date. Imagine a birthday for example.

    We have shortcuts in place for this, in which ctrl+arrows quickly move by months or years, but it could be better

    Describe the solution you'd like

    Not sure yet...

    Option 0

    A new prompt type where instead of a calendar, we display the three date parts (month, date, year) in a customizable order with customizable separators.

    The end user can then move around each one of them pressing left or right arrows, and then press up or down to update the values.

    Option 1

    The user can type a full date in a predefined format, e.g. dd/mm/yyyy and submit. The prompt handler should then try to parse this input and if successful, return the parsed value.

    The submit button could be a new shortcut, e.g. Ctrl+Enter, or the same Enter.

    Maybe we could do the following:

    • Space for selecting on interactive calendar
    • Enter to submit current input, or current calendar selection if input is empty.

    It would be nice if the expected input format was written in grey where the input would be, something like:

    ? Travel date: 12/0m/yyyy

    Option 2

    I tried to think of a "filter" approach, like typing a month or year and then the calendar would jump right on that, but didn't get to a reasonable solution.

    enhancement dateselect-prompt 
    opened by mikaelmello 10
  • Add an indication that a list has extra options below (or above)

    Add an indication that a list has extra options below (or above)

    Is your feature request related to a problem? Please describe.

    Does a long list have indication that only its part is displayed? As I see from the demo, a list can be scrolled but I do not notice any clue that there are extra items above or below.

    Source

    Describe the solution you'd like

    Some sort of visual indication that the list has more options not displayed at the moment, still not sure of how that would look like.

    This issue affects the three prompts containing lists: select, multiselect and text (with auto-complete suggestions).

    enhancement multiselect-prompt select-prompt text-prompt 
    opened by mikaelmello 8
  • Successful prompt indicator

    Successful prompt indicator

    Is your feature request related to a problem? Please describe. When the user inputs data, the default prompt shown begins with a light-green question mark. When the input completes, that question mark remains.

    Describe the solution you'd like I would love for the question mark to become a check mark or so.

    Additional context Thank you for this library. I really like the prompts I’m able to create with it!

    Example (using Dialoguer)

    enhancement all-prompts 
    opened by href 7
  • Use terminal cursor in text prompts

    Use terminal cursor in text prompts

    Is your feature request related to a problem? Please describe.

    The cursor in text prompts is entirely artificial, we explicitly add a background and foreground colors on where the cursor should be. Meanwhile, the actual cursor is hidden at the end of the prompt.

    Ideally, we should position the cursor where it should actually reside. I'm not sure if this helps with accessibility, it would be even more worth it if it does.

    Describe the solution you'd like

    The backend should mark where the cursor should be and move it to the correct place after rendering the entire prompt.

    enhancement user-text-input 
    opened by mikaelmello 7
  • await repetition

    await repetition

    question:call function await on match, prompt repeats. image

    code:

        const PEER: &str = "peer";
        const PEER_SERVER: &str = "peer-server";
        let node_type_option = vec![PEER, PEER_SERVER];
        let node_type_select = inquire::Select::new("Select the peer node type that needs to be revoked.", node_type_option).prompt();
        match node_type_select {
            Ok(node_type) => {
                match node_type {
                    PEER => {
                        let mut configuration = Configuration::new(config).await?;
                        let node_list = configuration.list().await?;
                        let node_option = node_list.iter()
                            .map(|v| v.name())
                            .collect::<Vec<&str>>();
                        let node_select = inquire::Select::new("Select node", node_option).prompt();
                        match node_select {
                            Ok(choice) => {
                                println!("{}", choice);
                            }
                            Err(_) => {}
                        }
                    }
                    PEER_SERVER => {
                        println!("{}", PEER_SERVER);
                    }
                    _ => {}
                }
            },
    
            Err(_) => {
                println!("There was an error, please try again")
            }
        }
        Ok(())
    
    enhancement 
    opened by gngpp 6
  • Implement validators as traits

    Implement validators as traits

    This is the re-implementation of validators as traits, rather than a plain closure trait object, as discussed in #54.

    There were a few unexpected hurdles during implementation:

    • Boxed trait objects are not cloneable easily. Therefore, using dyn-clone as helper to make the clone-able. Otherwise, all prompts would lose the ability to be cloned.
    • Some prompts have both with_validator and with_validators functions. The first one could be made generic, calling Box::new internally, whereas the second one directly takes a slice of Box as a parameter (due to how generics work).
    • Closures now seem to always require the parameter type to be defined. This is likely to how the generics are being resolved.

    Todo

    Still have to update several docs, just wanted to get some input about this implementation (and its effects on the API) first.

    Future work

    I think if this one looks good, we could continue doing the same change for formatters and parsers. What do you think?

    opened by dnaka91 6
  • How to write unit tests around Prompts

    How to write unit tests around Prompts

    Is your feature request related to a problem? Please describe. I just started to play around with this as part of a CLI i'm building and was curious what suggestions you had for being able to unit test logic that contained inquire prompts? I see that internally you use prompt_with_backend

    Describe the solution you'd like I would like to be able to add unit tests around code that uses inquire prompts. One possible solution would be to expose prompt_with_backend

    Describe alternatives you've considered Not sure about alternatives but would love to hear your suggestions

    Additional context

    enhancement 
    opened by seancarroll 6
  • Implement

    Implement "multiline" prompt

    Motivation looks similar to #1, the idea here is to allow the user to input a multi-line text without having to open a text editor.

    Not sure how useful this would be, as I consider #1 more important.

    Edit: this is now activelly not planned to be implemented by the maintainer (me...). I'll be leaving this open in case anyone is interested in implementing it.

    enhancement new-prompt-type 
    opened by mikaelmello 6
  • Add prompts for common type?

    Add prompts for common type?

    Is your feature request related to a problem? Please describe. Right now, creating prompt for common types like i64 is very verbose, especially when default values are involved, which somehow needs a formatting function provided with the value.

    Describe the solution you'd like Include prompts for common values, preferably for all types implementing TryFrom<&str> or equivalent.

    Describe alternatives you've considered Give some additional methods in Text so that it can parse values/validate/etc.

    Additional context

    enhancement 
    opened by rongcuid 5
  • press

    press "?" to display help message

    Is your feature request related to a problem? Please describe. I'd want my user to be able to read in more detail about the data he is prompted to input.

    Describe the solution you'd like The prompt would display: What's your age? (press "?" for help). Once ? is pressed, the message will be displayed (somewhere) about the formula to calculate the age. This would be more tricky to do inside the Text field type, since "?" is a valid character to put into that field type, therefore, I guess, the best way for this feature to exist, would be when the key sequence to press to get help was configurable by the developer (but I also think it depends on the context, e.g. when prompting What's the name of the project?, usually, a question mark is not a valid character to be used as a project name)

    enhancement 
    opened by smallstepman 5
  • Extract password input clearing logic to a common method

    Extract password input clearing logic to a common method

                    if self.display_mode == PasswordDisplayMode::Hidden {
                        self.input.clear();
                    }
    

    This logic is repeated across the password prompt at least 3 times, we should possibly refactor this to be more reusable and work consistently across even future refactors.

    I'm thinking a design where clearing the input is part of the normal loop of the prompt and so we don't have to take care of this edge-case everywhere.

    Not critical, but I created the issue to track it and if anyone is up to it I'll gladly review the PR

    enhancement 
    opened by mikaelmello 0
  • Support global prefix + global indentation

    Support global prefix + global indentation

    This PR implements a new field in the render config called a "global prefix", which will be interpreted by the prompt backend as a prefix that is rendered before each line written out to the terminal.

    This will be a breaking change, since the RenderConfig type was altered to allow the user to infer a lifetime other than the 'static lifetime. A non-static lifetime was only added for the global prefix field, but for consistencies sake, the PR can be updated to support the other fields just as easy if needed. Alternatively, the non-static RenderConfig can also be broken out into a separate PR, if it is desired to be handled separately.

    Additionally, a bug fix for hidden password prompts is also included in the PR (see commit history). Again, this can be handled in a separate PR if desired.

    Feel free to come back with suggestions if the feature and/or implementation is appropriate!

    Closes #81

    opened by hampuslidin 2
  • Allow prompts to be rendered at a custom column offset

    Allow prompts to be rendered at a custom column offset

    Is your feature request related to a problem? Please describe. I don't know if this is out of scope for this project, but here it goes.

    I am building an application with nested log output, and sometimes I want to stop and query the user for input. The current way of doing it is to show the prompt at the bottom of the screen, but it would be really awesome if it could be rendered inline in the nested log output.

    The problem is there is no way of rendering the inquire prompts at a non-zero column position offset, neither is it possible to add prefixes to all the prompt lines in the current API. The prompt will always justify to the leftmost column of the screen at each render pass.

    Describe the solution you'd like A "simple" solution would be to honor the current cursor position and always make sure to render the start of each line at that starting column when initiating the prompt. The line clearing would need to be done from that column as well, to prevent previous output from being overwritten.

    Describe alternatives you've considered There are really no other alternatives other than reimplementing inquire into my own project, or using another library which can render at an arbitrary position of the screen.

    Additional context Example to my current state of application output:

    * Downloading file
    ┃ ~ URL: example.org/file
    ┃ * Verifying file content
    ┃ ┃ ! Unsupported file type
    ┃ ┗╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶
    ┗╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶
    
    ? Do you want to inspect the file?
    > Yes
      No
    

    Example of how I want it to look:

    * Downloading file
    ┃ ~ URL: example.org/file
    ┃ * Verifying file content
    ┃ ┃ ! Unsupported file type
    ┃ ┃ ? Do you want to inspect the file?
    ┃ ┃ > Yes
    ┃ ┃   No
    ┃ ┗╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶
    ┗╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶╶
    
    enhancement 
    opened by hampuslidin 5
  • Update termion requirement from 1.5 to 2.0

    Update termion requirement from 1.5 to 2.0

    Updates the requirements on termion to permit the latest version.

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Expose API to customize keybindings and their actions

    Expose API to customize keybindings and their actions

    It isn't a huge jump from where we currently are.

    It is also very important if we want inquire to be extendable and allow stuff like widgets, and ultimately give more freedom to the users when building their applications, while we keep sane and opinionated defaults.

    enhancement 
    opened by mikaelmello 0
Releases(v0.5.2)
  • v0.5.2(Nov 1, 2022)

    • Fixed typo in the default error message when a password confirmation does not match. Thanks to @woodruffw for the PR! #79
      • Releases containing the typo: v0.5.0 and v0.5.1.

    0.5.1

    • Removed use of bool::then_some feature to keep minimum supported Rust version on 1.56.0.

    0.5.0 - 2022-10-31

    Breaking Changes

    Password prompts now enable a secondary confirmation prompt by default:

    • Added support for password confirmation, which can be oupted-out of by adding the without_confirmation() method into the Password builder chain. Thanks to @hampuslidin for the PR! #73
    Source code(tar.gz)
    Source code(zip)
  • v0.5.1(Oct 31, 2022)

    • Removed use of bool::then_some feature to keep minimum supported Rust version on 1.56.0.

    v0.5.0

    Breaking Changes

    Password prompts now enable a secondary confirmation prompt by default:

    • Added support for password confirmation, which can be oupted-out of by adding the without_confirmation() method into the Password builder chain. Thanks @hampuslidin
    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(Oct 31, 2022)

    Breaking Changes

    Password prompts now enable a secondary confirmation prompt by default:

    • Added support for password confirmation, which can be oupted-out of by adding the without_confirmation() method into the Password builder chain. Thanks @hampuslidin
    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Sep 27, 2022)

    Breaking Changes

    Multiple changes to the CustomType prompt:

    • Added support for validators, separating concerns between parsing and validating parsed values.
    • Decoupled default value formatting from the default value property. Now you can set default values without a specific formatter to accompany them.
    • Input is not cleared anymore when the parsing or validation fails.

    New autocompletion mechanism for Text prompts

    • Existing methods still work, you just have to update with_suggester calls to with_autocomplete.
    • To know more about the new possibilities, check the updated documentation on the repository's README.

    Other changes

    • Added shorthand method rgb(r: u8, g: u8, b: u8) to create a Color struct from RGB components. Thanks to @tpoliaw for the PR! #73
    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Aug 20, 2022)

    Breaking Changes

    Features #1 to #4 are all breaking changes and could break the compilation of your program.

    Fix #2 representes a change in usability and might be an unexpected behavior.

    Features

    1. Completer

    Completer for Text prompts, allowing users to auto-update their text input by pressing tab and not having to navigate through a suggestion list.

    It takes the current input and return an optional suggestion. If any, the prompter will replace the current input with the received suggestion. Completer is an alias for &'a dyn Fn(&str) -> Result<Option<String>, CustomUserError>.

    The auto-completion API will be revamped for v0.4.0, watch #69.


    2. Support for custom prompt prefix in finished prompts.

    Added answered_prompt_prefix configuration on RenderConfig, allowing users to set custom prefixes (e.g. a check mark) to prompts that have already been answered.

    Additionally, prompts that have been answered are now differed by a > prefix instead of the usual ?.

    Cheers to @href for the suggestion! #44


    3. User-provided operations can be fallible.

    Input validation, suggestions and completions are now fallible operations.

    The return type of validators has been changed to Result<Validation, CustomUserError>. This means that validating the input can now be a fallible operation. The docs contain more thorough explanations and full-featured examples.

    • Successful executions of the validator should return a variant of the Validation enum, which can be either Valid or Invalid(ErrorMessage).
    • Unsuccessful executions return a CustomUserError type, which is an alias for Box<dyn std::error::Error + Send + Sync + 'static>.

    The return type of suggesters has also been changed to allow fallible executions. The return type in successful executions continues to be Vec<String>, while CustomUserError is used with errors.


    4. Validators are traits instead of closures.

    All builtin validators have been turned into traits, with structs instead of macros as implementations.

    This change makes it easier to share the validators throughout the code, especially if these carry their own owned data. For example, consider a validator that uses a compiled regular expression to verify the input. That validator can now be built as a new-type struct that encapsulates the regex.

    Closures can still be used as before, but may not require to pass the argument type explicitly. The previous macros are now simply shorthands for the constructors of builtin validators.

    Fixes

    • Fix a broken link in the struct.Text documentation.
    • Suggestions are now always loaded at the start of a Text prompt.
      • Previously, suggestions were only loaded and displayed if the Text prompt was created with a pre-existing input value or after the user entered any input.
      • Now, even if the prompt is started without any input and the user hasn't done anything, suggestions are displayed.

    Changes

    • Update crossterm and console to their latest versions.
    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Oct 2, 2021)

    Features

    • Add initial_value property to Text prompts, which sets an initial value for the prompt's text input. Huge thanks to @irevoire for the suggestion and implementation. #34.

    Internals

    • Multiple changes to fix general warnings appearing throughout the code.
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Sep 14, 2021)

    Features

    • Add inquire::set_global_render_config method to set a global RenderConfig object to be used as the default one for all prompts created after the call.
    • Add KEY_BINDINGS.md to register all key bindings registered by inquire prompts.

    Breaking changes

    • RenderConfig was made Copy-able and prompts now contain a RenderConfig field where it previously held a &'a RenderConfig. Consequently, with_render_config() methods now accept a RenderConfig argument instead of &'a RenderConfig.
    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Sep 14, 2021)

    No changes in this version.

    This is a bump to v0.1.0 as per @jam1garner's advice on the Virtual RustConf Discord server.

    The library is already featureful enough to warrant a higher version number, bumping us to a minor release while we are still on our path to stabilization.

    Source code(tar.gz)
    Source code(zip)
  • v0.0.11(Sep 6, 2021)

    Features

    • Add Editor prompt.
    • Add support to use console or termion as the library to handle terminals while keeping crossterm as the default choice.
    • Canceling the prompt by pressing ESC is now a different behavior than interrupting the prompt by pressing Ctrl+C.
      • If the prompt is canceled, the final prompt render indicates to the user that it was canceled via a <canceled> text, which is customizable via RenderConfig, and the prompt method returns Err(InquireError::OperationCanceled).
      • If the prompt is interrupted, the only clean-up action done is restoring the cursor position, and the prompt method returns Err(InquireError::OperationInterrupted).
    • Add a prompt_skippable method for all prompts.
      • This method is intended for flows where the user skipping/cancelling the prompt - by pressing ESC - is considered normal behavior. In this case, it does not return Err(InquireError::OperationCanceled), but Ok(None). Meanwhile, if the user does submit an answer, the method wraps the return type with Some.

    Improvements

    • Removed need to add use inquire::validator::InquireLength when using one of the length-related built-in validators.
    • Cursor should not ficker anymore in wrong positions on ~~Windows~~ slower terminals.
    • Documentation on the Color enum used for render configuration has been improved.

    Fixes

    • Fix dependencies the crate had on macros provided by the builtin_validators feature, making it now compile when the feature is not turned on.
    Source code(tar.gz)
    Source code(zip)
  • v0.0.10(Aug 29, 2021)

    Features

    • Use native terminal cursors in text inputs by default.
    • Use native terminal cursor on date prompts when an optional style sheet for the selected cursor token was defined as None. The default behavior is still a custom style sheet which highlights the two columns pertaining to a date, instead of using a native cursor which can only highlight one column.
    • Respect NO_COLOR environment variable when prompt uses the default render configuration.

    Fixes

    • By using a new method to identify the length of the rendered prompt, we avoid possible rendering errors (edge cases) when a string can not render into a single line in the terminal due to a smaller width. Inner calculations could previously predict that the rendered string would fit, by considering that 1 grapheme = 1 column width, but this is not true for e.g. emojis. Now we use unicode_width to fix this behavior.
    • Fixed case where Select/MultiSelect prompts were panicking when a user pressed the down arrow on an empty list, which happens when a filter input does not match any options. #30
    • Fixed incorrect indexes on the output of MultiSelect prompts, where the indexes inside a ListOption struct were relative to the output instead of the original input vector. #31
    • Fixed case where IO errors due to not finding a tty devices were not being catched and transformed to InquireError::NotTTY. #28
    Source code(tar.gz)
    Source code(zip)
  • v0.0.9(Aug 29, 2021)

    General

    • Improve docs on the differences between raw_prompt and prompt on Select and MultiSelect prompts.
    • Bump version of crossterm dependency

    Fixes

    • Regression introduced on v0.0.8 where select prompts were panicking when user pressed enter while no options were displayed (due to filter input). Tracked by #29 and tests were added for this to not happen again.
    Source code(tar.gz)
    Source code(zip)
  • v0.0.8(Aug 25, 2021)

    Features

    • Password display toggle: By enabling this option in Password prompts via with_display_toggle_enabled(), the application user can choose to display the current text input for the password by pressing Ctrl+R, and hide it back by pressing the hotkey again. #18
    • Render mask of password input: Password prompts now support another render mode of the text input. Before, the only behavior was to not render anything about the current password input. Now, if the developer so chooses, they can activate the Masked mode where the current text input will be masked with special characters such as '*'. #19
    • PageUp, PageDown, Home and End hotkeys: PageUp and PageDown are now supported in Select, MultiSelect and Text (suggestions list) prompts, where they go a page up or down in the current list. Also, for Select and MultiSelect prompts, the Home and End keys were mapped to go to the start or end of the list, respectively. #17
    • Indication that list is scrollable: Now option lists, present in Select, MultiSelect and Text prompts, indicate whether there are more options other than the ones currently displayed. Little arrows are displayed at the top or bottom of the list indicating to which positions the user can scroll. #8
    • Generic option types for Select and MultiSelect prompts: Now, Select and MultiSelect prompts accept any type of options as input, allowing developers to pass a vector of owned objects and get back the full object picked by the user. #9

    Fixes

    • Handling of new-line characters in user-provided strings: When putting \n on strings such as prompt messages, the library previously did not render it very well and did not account for it when cleaning the current prompt. This is fixed and you are free to create multi-line prompts! #15
    • Lines larger than terminal width broke rendering: When lines that were larger than the terminal width were rendered, it caused the internal line counter (used to clean the prompt) to be off, leading to buggy behavior. This was fixed by retrieving the terminal size at the start of the prompt. #21
    Source code(tar.gz)
    Source code(zip)
  • v0.0.7(Aug 20, 2021)

    Features

    • Add possibility to set custom rendering config, allowing users to set:
      • Custom colors
      • Custom prefixes for several prompts
      • Custom checkboxes
    • Add "placeholder" feature for prompts with text input
    Source code(tar.gz)
    Source code(zip)
  • v0.0.6(Jul 26, 2021)

  • v0.0.5(Jul 20, 2021)

    • All function arguments now accept closures by having their type changed to &dyn Fn.
    • Improved input UX
      • Cursor added for better editing experience
      • Features/shortcuts added: Ctrl+Left, Ctrl+Right, Home, End, Delete, Ctrl+Delete
    Source code(tar.gz)
    Source code(zip)
  • v0.0.4(Jul 14, 2021)

    • Add a custom error enum InquireError, improving error handling for library users.
    • Improve support for validator functions, allowing the use of closures.
    • Change the terminal back-end from termion to crossterm, adding Windows support for this library.
    Source code(tar.gz)
    Source code(zip)
  • v0.0.3(Jul 7, 2021)

Owner
Mikael Mello
what if I started a blog
Mikael Mello
Requestty - An easy-to-use collection of interactive cli prompts inspired by Inquirer.js.

Requestty requestty (request-tty) is an easy-to-use collection of interactive cli prompts inspired by Inquirer.js. Easy-to-use - The builder API and m

null 160 Dec 28, 2022
Simple OpenAI CLI wrapper written in Rust, feat. configurable prompts and models

Quick Start git clone https://github.com/ryantinder/ask-rs cd ask cargo install --path . Example ask tell me about the Lockheed Martin SR71 >> The Loc

Ryan Tinder 3 Aug 9, 2023
Beautiful, minimal, opinionated CLI prompts inspired by the Clack NPM package

Effortlessly build beautiful command-line apps with Rust ?? ✨ Beautiful, minimal, opinionated CLI prompts inspired by the @clack/prompts npm package.

Alexander Fadeev 7 Jul 23, 2023
A toolkit for building your own interactive command-line tools in Rust

promkit A toolkit for building your own interactive command-line tools in Rust, utilizing crossterm. Getting Started Put the package in your Cargo.tom

null 70 Dec 18, 2022
Ember is a minimalistic Rust library for creating 2D graphics, games, and interactive visualizations with ease and simplicity.

Ember Ember is a simple and fun 2D rendering library for Rust, allowing you to quickly create graphics and interactive applications with ease. It uses

null 8 May 4, 2023
Simple Interactive Terminal Todo App in Rust

todo-rs Simple Interactive Terminal Todo App in Rust Quick Start $ cargo run TODO Controls Keys Description k, j Move cursor up and down Shift+K, Shif

Tsoding 56 Dec 8, 2022
Rust adaptation of sindresorhus/is-interactive from NodeJS

is-interactive Rust adaptation of sindresorhus/is-interactive from NodeJS Check if stdout or stderr is interactive It checks that stedout or stderr is

Sean Larkin 4 Jan 21, 2023
Configurable, extensible, interactive line reader

linefeed linefeed is a configurable, concurrent, extensible, interactive input reader for Unix terminals and Windows console. API Documentation linefe

Murarth 176 Jan 3, 2023
An interactive cheatsheet tool for the command-line

navi An interactive cheatsheet tool for the command-line. navi allows you to browse through cheatsheets (that you may write yourself or download from

Denis Isidoro 12.2k Dec 30, 2022
Coinlive is an interactive command line tool that displays live cryptocurrency prices.

Coinlive is an interactive command line tool that displays live cryptocurrency prices. It can also display simple historical price charts.

Mayer Analytics 9 Dec 7, 2022
ruborute is an interactive command-line tool to get asphyxia@sdvx gaming data.

ruborute Are you 暴龍天 ?. The ruborute is an interactive command-line tool to get asphyxia@sdvx gaming data. asphyxia-core/plugins: https://github.com/a

RinChanNOW! 9 Sep 28, 2022
An interactive shell environment for exploring the p2panda protocol

An interactive shell environment for exploring the p2panda protocol. Uses a mock node and clients to simulate network logic.

null 4 Dec 12, 2021
Native cross-platform full feature terminal-based sequence editor for git interactive rebase.

Native cross-platform full feature terminal-based sequence editor for git interactive rebase.

Tim Oram 1.2k Jan 2, 2023
Terminal based, feature rich, interactive SQL tool

datafusion-tui (dft) DataFusion-tui provides a feature rich terminal application, built with tui-rs, for using DataFusion (and eventually Ballista). I

null 49 Dec 24, 2022
Non-interactive nREPL client for shell scripts and command-line

nreplops-tool (nr) nreplops-tool (nr) is a non-interactive nREPL client designed to be used in shell scripts and on the command-line. Early α warning:

Matti Hänninen 3 Jul 1, 2022
Tricking shells into interactive mode when local PTY's are not available

Remote Pseudoterminals Remote Pseudoterminals or "RPTY" is a Rust library which intercepts calls to the Linux kernel's TTY/PTY-related libc functions

null 135 Dec 4, 2022
A simple interactive OSC (Open Sound Control) debugger for terminal

oscd, a simple interactive OSC debugger for the terminal by using nom as a lexer/parser, oscd offers auto type casting and support sending multiple osc arguments.

Karnpapon Boonput 5 Oct 19, 2022
YARI - An interactive debugger for YARA Language

Interactive debugger for the YARA language written in Rust. Debugger directly calls libyara avoiding emulation to get the most accurate results.

Avast 74 Dec 7, 2022
An interactive Bayesian Probability Calculator CLI that guides users through updating beliefs based on new evidence.

Bayesian Probability Calculator CLI Welcome to the Bayesian Probability Calculator CLI! This command-line tool is designed to help you update your bel

Ben Greenberg 4 Apr 25, 2023