Giter Club home page Giter Club logo

inquire's Introduction

Latest Version Docs Build status Unsafe forbidden Supported platforms License



inquire is a library for building interactive prompts on terminals.

It provides several different prompts in order to interactively ask the user for information via the CLI. With inquire, you can use:

  • Text to get text input from the user, with built-in autocompletion support;
  • Editor* to get longer text inputs by opening a text editor for the user;
  • DateSelect* to get a date input from the user, selected via an interactive calendar;
  • Select to ask the user to select one option from a given list;
  • MultiSelect to ask the user to select an arbitrary number of options from a given list;
  • Confirm for simple yes/no confirmation prompts;
  • CustomType for text prompts that you would like to parse to a custom type, such as numbers or UUIDs;
  • Password for secretive text prompts.

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

Features

  • Cross-platform, supporting UNIX and Windows terminals (thanks to crossterm);
  • Several kinds of prompts to suit your needs;
  • Standardized error handling (thanks to thiserror);
  • You can choose your terminal backend between crossterm (default), termion or console.
    • Perfect if you already use one library and do not want additional dependencies.
  • Support for fine-grained configuration for each prompt type, allowing you to customize:
    • Rendering configuration (aka color theme + other components);
    • Default values;
    • Placeholders;
    • Input validators and formatters;
    • Help messages;
    • Autocompletion for Text prompts;
    • Confirmation messages for Password prompts;
    • Custom list filters for Select and MultiSelect prompts;
    • Custom parsers for Confirm and CustomType prompts;
    • Custom extensions for files created by Editor prompts;
    • and many others!

Examples

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

cargo run --example expense_tracker --features date

Usage

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

inquire = "0.7.4"

* This prompt type is gated under a feature flag, e.g.:

inquire = { version = "0.7.4", features = ["date"] }

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.

Rendering configuration (aka color themes)

All prompts allow you to set a custom RenderConfig, a struct that contains lots of style customization options.

With RenderConfig, you can customize foreground color, background color and attributes (e.g. bold) of most components that are part of a prompt. Additionally, you can also customize the content of special tokens, such as prompt prefixes, highlighted-option prefixes, selected and unselected checkboxes, etc. If you do not want to re-set the render config object for each new prompt you create, you can call inquire::set_global_render_config to set a global RenderConfig object to be used as the default one for all future prompts.

This allows you to have greater control over the style of your application while continuing to have a clean API to create prompts as smoothly as possible.

In the render_config.rs example, you can take a look at the capabilities of this API. The example is exactly the same one as expense_tracker.rs, but with several style aspects customized. Take a look at their differences:

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

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, &[ListOption], or NaiveDate, but their return type are always the same: Result<Validation, CustomUserError>.

The Validation type is an enum that indicates whether the user input is valid, in which you should return Ok(Validation::Invalid), or invalid, where you should return Ok(Validation::Invalid(ErrorMessage)). The ErrorMessage type is another enum, containing the Default and Custom(String) variants, indicating the message to indicate the user that their input is invalid.

With an Invalid result, it is recommended that you set the ErrorMessage field to a custom message containing helpful feedback to the user, e.g. "This field should contain at least 5 characters".

The CustomUserError type is an alias to Box<dyn std::error::Error + Send + Sync + 'static>. Added to support validators with fallible operations, such as HTTP requests or database queries. If the validator returns Err(CustomUserError), the prompt will return Err(InquireError::Custom(CustomUserError)) as its result, containing the error you returned wrapped around the enums mentioned.

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 macros that is included by default. When the feature is on, several shorthand macros for the builtin validators are exported at the root-level of the library. Check their documentation to see more details, they provide full-featured examples.

In the demo 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.

If you'd like to see more examples, the date.rs and multiselect.rs files contain custom validators.

Terminal Back-end

Currently, there are like 3 major libraries to manipulate terminals: crossterm, console and termion.

Binary Rust applications that intend to manipulate terminals will probably pick any one of these 3 to power underlying abstractions. inquire chose to support crossterm by default in order to support many features on Windows out-of-the-box.

However, if your application already uses a dependency other than crossterm, such as console or termion, you can enable another terminal via feature flags. It is also important to disable inquire's default features as it comes with crossterm enabled by default. Such as this:

inquire = { version = "0.7.4", default-features = false, features = ["termion", "date"] }

or this:

inquire = { version = "0.7.4", default-features = false, features = ["console", "date"] }

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 you can see this behavior in action with the amount (CustomType) prompt, where a custom formatter adds a '$' character prefix 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 you can see this behavior in action with the amount (CustomType) prompt.

Scoring

Scoring is applicable to two prompts: Select and MultiSelect. They provide the user the ability to sort and filter the list of 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.

Scoring functions receive four arguments: the current user input, the option, the option string value and the option index. They must return a Option<i64> value indicating whether the option should be part of the results or not.

The default scoring function calculates a match value with the current user input and each option using SkimV2 from fuzzy_matcher, resulting in fuzzy searching and filtering, returning Some(<score>_i64) if SkimV2 detects a match.

In the demo 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.

Keybindings

To see all of the keybindings registered by prompts, check the KEY_BINDINGS.md file.

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.
  • Initial value: Initial value of the prompt's text input, in case you want to display the prompt with something already filled in.
  • Placeholder: Short hint that describes the expected value of the input.
  • 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.
  • Suggester: Custom function that returns a list of input suggestions based on the current text input. See more on "Autocomplete" below.

Autocomplete

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

You can call with_autocomplete() and provide a value that implements the Autocomplete trait. The Autocomplete trait has two provided methods: get_suggestions and get_completion.

  • get_suggestions is called whenever the user's text input is modified, e.g. a new letter is typed, returning a Vec<String>. The Vec<String> is the list of suggestions that the prompt displays to the user according to their text input. The user can then navigate through the list and if they submit while highlighting one of these suggestions, the suggestion is treated as the final answer.
  • get_completion is called whenever the user presses the autocompletion hotkey (tab by default), with the current text input and the text of the currently highlighted suggestion, if any, as parameters. This method should return whether any text replacement (an autocompletion) should be made. If the prompt receives a replacement to be made, it substitutes the current text input for the string received from the get_completion call.

For example, in the complex_autocompletion.rs example file, the FilePathCompleter scans the file system based on the current text input, storing a list of paths that match the current text input.

Every time get_suggestions is called, the method returns the list of paths that match the user input. When the user presses the autocompletion hotkey, the FilePathCompleter checks whether there is any path selected from the list, if there is, it decides to replace the current text input for it. The interesting piece of functionality is that if there isn't a path selected from the list, the FilePathCompleter calculates the longest common prefix amongst all scanned paths and updates the text input to an unambiguous new value. Similar to how terminals work when traversing paths.

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 autocompletion 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.

By default, the initial selected date is the current date. The user can navigate through the calendar by pressing the keyboard arrows. If the user also presses the control key along with the arrows, the user will be able to "fast-forward" to previous or next months or years.

More specifically:

  • Left arrow moves to the day previous to the one selected, and to the month previous to the one selected when pressed with ctrl.
  • Analogously, right arrow does the same, but moving to the next day or month.
  • Up arrow moves to the day above to the one selected, basically a week before the selected date. When pressed with ctrl, it moves to the previous year.
  • Analogously, the down arrow moves to a week later or a year later.

Finally, the user selects a date by pressing the space or enter keys.

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. If any boundary is set, the user will not be able to move past them, consequently not being able to select any dates out of the allowed range.

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<&str> = vec!["Banana", "Apple", "Strawberry", "Grapes", "Lemon", "Tangerine", "Watermelon", "Orange", "Pear", "Avocado", "Pineapple"];

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

match ans {
    Ok(choice) => println!("{}! That's mine too!", choice),
    Err(_) => println!("There was an error, please try again"),
}

Select prompts are suitable for when you need the user to select one option among many.

The user can select and submit the current highlighted option by pressing space or enter.

This prompt requires a prompt message and a non-empty Vec of options to be displayed to the user. The options can be of any type as long as they implement the Display trait. It is required that the Vec is moved to the prompt, as the prompt will return the selected option (Vec element) after the user submits.

  • If the list is empty, the prompt operation will fail with an InquireError::InvalidConfiguration error.

This prompt does not support custom validators because of its nature. 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).

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. Must be non-empty.
  • Starting cursor: Index of the cursor when the prompt is first rendered. Default is 0 (first option). If the index is out-of-range of the option list, the prompt will fail with an InquireError::InvalidConfiguration error.
  • 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.
  • Page size: Number of options displayed at once, 7 by default.
  • Display option indexes: On long lists, it might be helpful to display the indexes of the options to the user. Via the RenderConfig, you can set the display mode of the indexes as a prefix of an option. The default configuration is None, to not render any index when displaying the options.
  • Scoring function: Function that defines the order of options and if an option is displayed or not based on the current user 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.

MultiSelect prompts are suitable for when you need the user to select many options (including none if applicable) among a list of them.

The user can select (or deselect) the current highlighted option by pressing space, clean all selections by pressing the left arrow and select all options by pressing the right arrow.

This prompt requires a prompt message and a non-empty Vec of options to be displayed to the user. The options can be of any type as long as they implement the Display trait. It is required that the Vec is moved to the prompt, as the prompt will return the ownership of the Vec after the user submits, with only the selected options inside it.

  • If the list is empty, the prompt operation will fail with an InquireError::InvalidConfiguration error.

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).

Customizable options:

  • Prompt message: Required when creating the prompt.
  • Options list: Options displayed to the user. Must be non-empty.
  • Default selections: Options that are selected by default when the prompt is first rendered. The user can unselect them. If any of the indices is out-of-range of the option list, the prompt will fail with an InquireError::InvalidConfiguration error.
  • Starting cursor: Index of the cursor when the prompt is first rendered. Default is 0 (first option). If the index is out-of-range of the option list, the prompt will fail with an InquireError::InvalidConfiguration error.
  • 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.
  • Page size: Number of options displayed at once, 7 by default.
  • Display option indexes: On long lists, it might be helpful to display the indexes of the options to the user. Via the RenderConfig, you can set the display mode of the indexes as a prefix of an option. The default configuration is None, to not render any index when displaying the options.
  • Scoring function: Function that defines the order of options and if an option is displayed or not based on the current user input.
  • Keep filter flag: Whether the current filter input should be cleared or not after a selection is made. Defaults to true.

Editor

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

The source is too long, find it here.

Editor prompts are meant for cases where you need the user to write some text that might not fit in a single line, such as long descriptions or commit messages.

This prompt is gated via the editor because it depends on the tempfile crate.

This prompt's behavior is to ask the user to either open the editor - by pressing the e key - or submit the current text - by pressing the enter key. The user can freely open and close the editor as they wish, until they either cancel or submit.

The editor opened is set by default to nano on Unix environments and notepad on Windows environments. Additionally, if there's an editor set in either the EDITOR or VISUAL environment variables, it is used instead.

If the user presses esc while the editor is not open, it will be interpreted as the user canceling (or skipping) the operation, in which case the prompt call will return Err(InquireError::OperationCanceled).

If the user presses enter without ever modyfing the temporary file, it will be treated as an empty submission. If this is unwanted behavior, you can control the user input by using validators.

Finally, this prompt allows a great range of customizable options as all others:

  • 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.
  • Editor command and its args: If you want to override the selected editor, you can pass over the command and additional args.
  • File extension: Custom extension for the temporary file, useful as a proxy for proper syntax highlighting for example.
  • Predefined text: Pre-defined text to be written to the temporary file before the user is allowed to edit it.
  • 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.
    • By default, a successfully submitted answer is displayed to the user simply as <received>.

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 meant for secretive text inputs.

By default, the password prompt behaves like a standard one you'd see in common CLI applications: the user has no UI indicators about the state of the current input. They do not know how many characters they typed, or which character they typed, with no option to display the current text input.

However, you can still customize these and other behaviors if you wish:

  • Standard display mode: Set the display mode of the text input among hidden, masked and full via the PasswordDisplayMode enum.
    • Hidden: default behavior, no UI indicators.
    • Masked: behaves like a normal text input, except that all characters of the input are masked to a special character, which is '*' by default but can be customized via RenderConfig.
    • Full: behaves like a normal text input, no modifications.
  • Toggle display mode: When enabling this feature by calling the with_display_toggle_enabled() method, you allow the user to toggle between the standard display mode set and the full display mode.
    • If you have set the standard display mode to hidden (which is also the default) or masked, the user can press Ctrl+R to change the display mode to Full, and Ctrl+R again to change it back to the standard one.
    • Obviously, if you have set the standard display mode to Full, pressing Ctrl+R won't cause any changes.
  • Confirmation: By default, the password will have a confirmation flow where the user will be asked for the input twice and the two responses will be compared. If they differ, an error message is shown and the user is prompted again.
    • By default, a "Confirmation:" message is shown for the confirmation prompts, but this can be modified by setting a custom confirmation message only shown the second time, using the with_custom_confirmation_message() method.
    • If confirmation is not desired, it can be turned off using the without_confirmation() method.
  • 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.
    • By default, it prints eight asterisk characters: ********.
  • Validators: Custom validators to make sure a given submitted input pass the specified requirements, e.g. not allowing empty inputs or requiring special characters.
    • No validators are on by default.

Remember that for CLI applications it is standard to not allow use any display modes other than Hidden and to not allow the user to see the text input in any way. Use the customization options at your discretion.

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. Its defaults are necessarily very simple in order to cover a large range of generic cases, for example a "Invalid input" error message.

You can customize as many aspects of this prompt as you like: prompt message, help message, default value, placeholder, value parser and value formatter.

Behavior

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.

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.

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"),
}

Confirm is a prompt to ask the user for simple yes/no questions, commonly known by asking the user displaying the (y/n) text.

This prompt 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.

Default values are formatted with the given value in uppercase, e.g. (Y/n) or (y/N). The bool parser accepts by default only the following inputs (case-insensitive): y, n, yes and no. If the user input does not match any of them, the following error message is displayed by default:

  • # Invalid answer, try typing 'y' for yes or 'n' for no.

Finally, once the answer is submitted, Confirm prompts display the bool value formatted as either "Yes", if a true value was parsed, or "No" otherwise.

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.
  • Placeholder: Short hint that describes the expected value of the input.
  • 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.
  • 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".
  • 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.

Stargazers over time

Stargazers over time

inquire's People

Contributors

afh avatar alexwlchan avatar b3nj5m1n avatar baarsgaard avatar bheylin avatar darkecho731 avatar dependabot[bot] avatar dnaka91 avatar enigmacurry avatar fribeau avatar frovolod avatar hampuslidin avatar irevoire avatar jasonish avatar josiptrbuscic avatar kianmeng avatar leoriether avatar luctius avatar mikaelmello avatar mikecvet avatar rchriste avatar swaroopmaddu avatar tpoliaw avatar wafflelapkin avatar woodruffw avatar ysndr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

inquire's Issues

Allow items for `Select` that do not necessary implement `Display` but with an appropiate formatter.

My use-case: I want to select over a tuple of values (String, CustomStruct). The formatted message should be tuple.0 + tuple.1.description. The whole struct doesn't implement Display, but the select dialog should use the struct's description field.

Currently that doesn't seem to be possible. Maybe lowering the bounds on T or making a change to Select would allow this? For example:

pub struct Select<'a, T, U: Display> {
    pub options: Vec<T>,
    pub item_formatter: &'a Fn(T) -> U,
}

Then the default item formatter could operate on T: Display and users could specify their own by setting the field?
This does require changing multiple parts of the code. I changed it to the idea above and had trouble fixing some compilation errors (probably due to limited knowledge about how the library works internally).

The problems that I find unergonomic is that:

  1. Creating the items using format!() returns a String after calling prompt(). It's hard to map that value back to the original selected item.
  2. Doing fuzzy search now also looks for partial matches inside the CustomStruct.description field. And I want to only have it look into the first tuple value tuple.0.

Automate terminal recordings for documentation

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

Generating each recording is a boring process with a lot of manual changes required. The recordings are even a bit outdated on functionality just because I didn't want to re-record everything which would require a lot of time.

Describe the solution you'd like

Have a set of recordings each containing the example to run and a series of keystrokes to perform.

Then automatically run these examples with the provided keystrokes, recording the terminal output and generating .cast and .gif outputs.

Describe alternatives you've considered

I thought of recording the keystrokes to give it a more natural feel but sometimes that's worse. For example when the recorder (I) take too long for the next action or type too fast worsening UX. Executing the keystrokes at a constant interval seems good enough.

Allow any kind of option types in Select/MultiSelect prompts

It would be great to be able to pass a slice of any type to these prompts and get the selected ones in return.

For example, you might want to pass a list of "Account"s and get a reference to the one selection back. If the Account struct implements the Display trait, we can easily print them.

In summary, the current approach requires the developer to do this:

let accounts: &[Account];
let options: &[str]; // mapped from accounts
let answer: OptionAnswer = Select::new("", options).prompt()?;
let selected_account: &Account = accounts[answer.index]; // get account back

// do something with the selected_account variable

We could use some more of this:

let accounts: &[Account];
let answer: &Account = Selec::new("", accounts).prompt()?;

// do something with the answer variable

not sure if the types defined above would actually work with the borrow-checker

Support Page Up and Page Down keys in selection prompts

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

Faster navigation might be very helpful to some users, specially in long lists.

Unfortunately, other hotkeys such as arrows are already taken by input parameters.

Describe the solution you'd like

When the user presses Page Down or Page Up, navigation will jump to the next page, with no options in common with the current page.

Exception: page up and page down should never wrap around the list, stopping at the first or last items, respectively.

Question: should we also disable page wrapping on arrow up and arrow down keys? As we would have fast ways (the page keys) to go to the end of the list.

Autocomplete for Text prompter doesn't seems to be working

Describe the bug
I can't manage to make autocomplete work with a Text prompter. Thinking it was my code, I cloned the repo and ran the expense_tracker example, but the autocomplete didn't work either.

Unlike in the demo, I didn't get any autocomplete when hitting the tab key with the payee field. Has it been broken or am I not using it correctly?

Thanks

To Reproduce
Steps to reproduce the behavior:

  1. git clone https://github.com/mikaelmello/inquire
  2. cd inquire && cargo run --example expense_tracker --features="builtin_validators date"
  3. Try to complete the payee field (third field) with the tab key as shown in the demo
  4. Autocomplete doesn't work

Expected behavior
Complete the input.

Desktop (please complete the following information):

$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="20.04.3 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.3 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

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.

Allow users to disable colorful output

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

We should allow library users to disable colors in the output, keeping it simple.

Describe the solution you'd like

We should allow colors to be disabled on a prompt-by-prompt basis, that's for sure. But it would also be great to expose an API to change some sort of global settings in the library, which would also be really useful for #6.

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.

Improve pre-built validators to properly handle string lengths

Currently, the pre-built validators via macros do not have any type annotations so they can be used freely whether the validators come from str arguments or Vec.

The length validators use the simple len() method to get the length of the answer. On strings, this can fail with unicode characters, as the len method returns the number of bytes IIRC and we should count the graphemes, with something like that: ans[..].graphemes(true).count()

Figure out a way to fix this while maintaining the following API:

  • The user should be able to call a macro or simple method or create a simple object: length!() ; length() ; Length::new().
  • This single API should automagically handle all the different validators that are applicable.

Allow toggling between displaying or not the password

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

Password prompt may need some kind of input indicator. Without disclosing the length of the password, just a keystroke indication. Some keyboards, especially wireless and membrane keyboards, sometimes miss a key press. In the case of creating a password, this can be a big problem, finding out the missing character will take time, if, of course, the user guesses what happened. For this reason, sometimes users want to validate the entered password before completing input.

Describe the solution you'd like

The library user should be able to enable this configuration via a flag, when building the Password prompt.

The application user, when this configuration is enabled, should be able to press a hotkey and have the current password displayed for me.

Describe alternatives you've considered

Displaying the password only while holding down a hotkey. This is not trivial (if possible) because we're in a terminal, only toggling on a press is much simpler.

Additional Context

Which hotkey would be best?

Turn validators into a trait

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

I'm trying to create a validator that uses user provided Regex patterns against the input. These patterns come from a settings file, and I'd like to be able to pass the validator around. With the current API of StringValidator, it is possible but very hacky and verbose as it must be turned into a lambda to work.

It would be great to instead be able to use structs that implement a trait. These could then be easier passed around.

Describe the solution you'd like

The validators being a trait like the following for the StringValidator:

trait StringValidator {
    fn validate(&self, value: &str) -> Result<(), String>
}

Then it can be implemented for all lambdas, to preserve the previous API:

impl<F> StringValidator for F
where
    F: Fn(&str) -> Result<(), String>,
{
    fn validate(&self, value: &str) -> Result<(), String> {
        (self)(value)
    }
}

But in addition, we can have structs with addition state, as well:

struct RegexValidator(Regex);

impl StringValidator for RegexValidator {
    fn validate(&self, value: &str) -> Result<(), String> {
        match self.0.is_match(value) {
            true => Ok(()),
            false => Err(format!("value must match pattern `{}`", self.0)),
        }
    }
}

This is currently still possible with lambdas, but especially when using shared values, it is very difficult to implement. Often forced to put this the same function where it is called.

oops

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Add API to set global configurations

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

In order to improve the developer's experience and reduce the need for repetitive code, it would be great to have an API to set global configuration parameters applied to all prompts created from that moment in time.

Describe the solution you'd like

See Additional context

Additionally, extend this from just render configs, storing defaults for things such as page size, vim mode, help messages, terminal impl (although this one is not publicly settable), etc.

Finally, consider whether to allow or not multiple updates in global configs.

Additional context

Before

    let render_config = get_render_config();

    let _date = DateSelect::new("Date:")
        .with_render_config(&render_config)
        .prompt()?;

    let _category = Select::new("Category:", get_categories())
        .with_render_config(&render_config)
        .prompt()?;

After

    let render_config = get_render_config();
    inquire::set_default_render_config(render_config);

    let _date = DateSelect::new("Date:").prompt()?;

    let _category = Select::new("Category:", get_categories()).prompt()?;

Document the release process

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

This is important for me when I stay away the project for a little while (like last month) and have to remember all of the steps, even though there aren't that many.

Describe the solution you'd like

An update CONTRIBUTING.md (or another file) that describes the release process in detail.

Remove assets from package uploaded to crates.io

Currently (v0.0.6) the package is amounting to 873 kB, which seems absurd. I haven't checked but I'm pretty sure it is because of all of the '.castand.giffiles under/assets`.

We should probably use a special README file for the crates.io package, without all the gifs.

Add option to display position indicator in items of selection prompts

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

For a long select and multiselect. It may be helpful to indicate the position of an item in the list (for example, 6 out of 123).

Describe the solution you'd like

This should not be enabled by default, the user should have to explicitly set it, like this:

let option = Select::new("Prompt", &options)
    .with_indicators(true)
    .prompt()?;

Additional context

Should original indexes be kept on a filtered list, or should indexes relative to the filtered list be displayed?

Add suport for "console" backend

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

Users might already be using a terminal library for other tasks, one that is not crossterm, so ideally we should be able to use that too instead of forcing the user to have multiple dependencies for the same thing.

Describe the solution you'd like

Add a new implementation for the Terminal trait, and select different types that implement it based on feature flags.

This issue is meant to track the support for the console backend

Additional context

Following requestty's footsteps :D

Implement Text Editor prompts

The behavior I'm looking for is similar to Github's CLI.

Basically something like this:

? Description: [(e) to launch nano, enter to skip]

after the user inputs: it calls the formatter, having this by default:

? Description: <received>

or, if skipped:

? Description: <skipped>

Project Status - Alive and Maintained

New version of the text, for previous ones just check the edit history

Hi everyone!

The development of this project has become a bit slower-paced for a few months now. The reason for this is that it has reached a stage where I, personally, am satisfied with the current set of features, covering the scope I envisioned for this project.

Of course, this isn't to say that the project is done or there aren't improvements to be made, but that anything new is likely coming from your needs and wants.

So, this text is just me confirming that this project still has my full attention.

If you have any issues when using it, or features you need, let us know and we can work together to find a solution :)

Breaking Change: Change `prompt` function error return type

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

I'm testing out inquire in a cli app of mine and at least initially I want to just propagate errors back to main and print them with eyre::Report but the current choice of error return type (Box<dyn Error>) is making this impossible. The issue is two fold. The main issue being that Box<dyn Error> doesn't implement the Error trait so it can't be converted into an eyre::Report through From. I could work around this normally by using the eyre! macro to manually convert the boxed error into a report but this doesn't work because Box<dyn Error> also doesn't implement Send or Sync, which is required to be stored in an eyre::Report at all. This second problem could be fixed by just changing the signature to Box<dyn Error + Send + Sync + 'static> but that still wouldn't solve the From incompatibility, which is intrinsic to Box itself.

Describe the solution you'd like

Ideally I'd recommend introducing your own Error type and implement the Error trait for it. It's too early for me to say yet how it should be structured or what interface it should present, other than an opaque error type that implements Send, Sync, and Error. Ideally I'd start there, even if the Error type internally just stores a Box<dyn Error + Send + Sync + 'static> and is used the same way the current error type is.

Stack of errors for long error messages

Describe the bug
If the error message is longer than the available terminal width, the error messages start to appear one below the other when any key is pressed.

To Reproduce
Steps to reproduce the behavior:

  1. Add long message to validator
  2. Set terminal window less then validation message length
  3. Get validation error
  4. Press left arrow key or backspace or continue typing

Expected behavior
The error message keeps its position on the screen.

Screenshots
image

Desktop

  • OS: ArchLinux
  • Version: Latest

Additional context
Can be related to #15

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)

Interactive cursor gets weird on special inputs.

great 🌍, 🍞, πŸš—, 1231321πŸ“ž, πŸŽ‰, β™₯️, πŸ†xsa232 s2da ake iak eaik

When pasting this input on any prompt that uses the Input struct for interactive cursors, moving around the string gets all weird because of the one heart character.

Understand why this is happening and how to fix it.

Use terminal cursor in date prompts

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

The selected date cursor in date 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.

We probably will continue to hide the cursor, as we can't highlight an entire 2-digit date with a cursor of width 1. But just having the cursor there is important.

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.

Allow password prompts to render a mask of the current input

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

The current behavior is to not render anything at all in when inputting in a password prompt. This is the standard for CLI applications.

In web, the standard is to render those little dots, or asterisks. With that approach, the user has full control and visibility of the cursor and the current input length. This is not the standard approach for CLIs, but we can support this feature for those who want/need it.

Describe the solution you'd like

The library user should be able to configure the render mode for password inputs between something like None and Masked, with None as the default.

Add documentation of Text::initial_value in missing places

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

The initial_value property is properly documented in doc comments, but when reviewing the PR I forgot about the README (Text section) and the actual documentation of the Text struct, which contains an overview of the prompt API.

This is important to allow future users to easily discover this feature, in case it is useful for them.

Describe the solution you'd like

Simple lines describing the purpose of initial_value.


@irevoire pinging you in case you might be interested, but I know this is the boring part of contributing, so don't worry, I'll get to it before I release.

Allow customization of colors in prompts.

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

Your color palette is awful but I still need your crate, how can I make the question marks red?

Describe the solution you'd like

Allow lib users to customize the colors used in the prompts, something other than green for [anything, because I basically used green for all of the colorful stuff].

Could this be like a custom setting that you set once and all prompts use this config?

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.

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)

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

Add API to add callbacks to customize style of a date

Is your feature request related to a problem? Please describe.
A bit crazy idea but it may result in something useful in another way. A calendar is a convenient and easy to use widget. But sometimes it is good to see extra information. E.g, if I choose a day for a new appointment, I'd like to know what days are already booked. A good example is Google Calendar that highlights today and all dates which I have already filled with another appointment. Yes, terminal has fewer ways to mark a date, but we can use colors/background colors/boldness/underline/italic.

Describe the solution you'd like
I see two ways to do it:

  • Allow a user to pass a list of dates to highlight. A sufficient solution when one type of highlight is enough. But the solutions turns bad when a user has a long list of dates (think of passing all the dates for at least the current year).
  • Add a callback to calendar display function. The callback argument is a date(maybe more but the date is required). It returns(as Option: None means display with default colors) foreground, background colors, and maybe style(bold/underline/etc). A flexible way but requires more work from a user.

Describe alternatives you've considered
I did not consider no alternatives.

Additional context
It is an example of GUI calendar (grey = today, red = have something).
image

Add support for termion backend

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

Users might already be using a terminal library for other tasks, one that is not crossterm, so ideally we should be able to use that too instead of forcing the user to have multiple dependencies for the same thing.

Describe the solution you'd like

Add a new implementation for the Terminal trait, and select different types that implement it based on feature flags.

This issue is meant to track the support for the termion backend

Additional context

Following requestty's footsteps :D

Thanks

I'm not yet using the crate, but what I see in the repo looks just great<3

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).

Respect NO_COLOR environment variable

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

From no-color.org:

An increasing number of command-line software programs output text with ANSI color escape codes by default. While some developers and users obviously prefer seeing these colors, many users don’t. Unfortunately, every new piece of software seems to have a different way of disabling colored text output and some software has no way at all.

Accepting the futility of trying to reverse this trend, an informal standard is hereby proposed:

All command-line software which outputs text with ANSI color added should check for the presence of a NO_COLOR environment variable that, when present (regardless of its value), prevents the addition of ANSI color.

By adopting this standard, users that prefer to have plain, non-colored text output can set one environment variable in their shell to have it automatically affect all supported software.

Describe the solution you'd like

Detect NO_COLOR env vars on the render_config instantiation.

The lib user should be able to override this, opting to print colors anyway.

It is also important to not lose any UX because of that. All prompts should be fine, except:

  • Prompts with text input: #23 should be done to allow the user to know where the cursor is.
  • Date prompts: a date prompt with no ansi attributes has an awful UX. Because of that #24 should be done before this task. Then we can use the built-in cursor instead of adding a background to the date.

Additional context

We should think more about the relationship between colors and behavior:

  • Should a non-colored render config trigger a cursor_show with date prompts?
  • Should we omit colors when the prompt is called with a custom render config but NO_COLOR is set?
  • etc.

We must think better about the API

Create API to quickly create prompts to select from enum variants

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

When checking out some projects that use inquire, I noticed that two of them are using Select/MultiSelect prompts to allow the user to select enum variants, such as an enum for currency or maybe settings.

Each one had their own way to make it work and I thought it would be a great idea to incorporate this into the lib.

Describe the solution you'd like

I'd like something clean and concise, like Select<Enum>::new("prompt message"), but I'm not sure how feasible this is with the current architecture. I'm still gonna come up with a few approache.

Describe alternatives you've considered

I've considered making wrappers around Select/MultiSelect, that would convert the enums to strings and then instantiate a Select/Multi behind the scenes. However, I'd like something better integrated. If the plan A turns out to not be possible, I'd go back to consider this.

Select is panicking when enter is pressed on an empty list

Not sure how I missed this one. Release going out as soon as it is fixed

If the user types something and the filter does not match anything, no options are displayed to the user.

If the user then presses enter, we will try to retrieve the index of the option currently highlighted, calling unwrap on it. Since no current option is highlighted because the vec is empty, we panic.

Prompts with multi-line string values break formatting

Describe the bug

Strings rendered by the backend that contain new-line characters (\n) are not properly handled. Creating two problems:

  1. In raw_mode, new line characters just move the cursor down one row. We need to manually inject \r to these strings.
  2. The prompt-cleaning algorithm, the one that resets all rows currently written, does not account for the additional number of lines created by these strings. We need to check them too.

To Reproduce

    let ans = Confirm::new("Do you live in\nBrazil?")
        .with_default(false)
        .with_help_message("Don't worry!\nBe happy!")
        .prompt()
        .unwrap();

    println!("Your answer: {}", ans);

    let ans = Confirm::new("Do you live in\nBrazil?")
        .with_default(false)
        .with_help_message("Don't worry!\nBe happy!")
        .prompt()
        .unwrap();

    println!("Your answer: {}", ans);

Expected behavior

[mikael@mello inquire]$ cargo run --example multi_line_help_message 
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/examples/multi_line_help_message`
? Do you live in
Brazil? No
Your answer: false
? Do you live in
Brazil? Yes
Your answer: true

Screenshots
image

image

Add a Matrix Space for `inquire`

Is your feature request related to a problem? Please describe.
Just a better place for chats, and simple questions that don't require separate issues.

Describe the solution you'd like
How about having a Matrix space. (I use Element)

Add styling to selection options

Is your feature request related to a problem? Please describe.
I have a list of options where some are different types and it would be good to make them visually distinctive in the prompt.

For my case, I'd like to be able to highlight the option that is currently in use so that users can see they're not going to change anything.

Describe the solution you'd like
A new field+method on the Select prompt to add an option_formatter of type (something like) &'a dyn Fn(ListOption<&T>) -> Styled that would let the appearance of options be determined at run time.

Describe alternatives you've considered
I initially thought this is what the existing formatter field was used for but that seems to only be used to render the selected option.
I also tried wrapping my T in a new type and adding ansi formatting in its Display impl. This seemed to be cleared somewhere in the rendering.

Additional context
I'm not sure how this would interact with the RenderConfig and keeping the presentation consistent across multiple prompts.

It could also be interesting to have access to the selected/highlighted state of the option so that options can be presented differently when they're highlighted (eg to display additional help). Something like

> one (more info on one)                           one
  two                      >>>scroll down>>>     > two (more info on two)
  three                                            three

Select/MultiSelect is panicking when down arrow is pressed on an empty list

Not sure how I missed this one. Release going out as soon as it is fixed

If the user types something and the filter does not match anything, no options are displayed to the user.

If the user then presses down arrow, we check if we need to wrap around the list in case the new index is larger than the list len. We do this by executing a mod operation, which panics when the divisor is 0 (list length)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.