diff --git a/Cargo.toml b/Cargo.toml index 01dec70..8ad3317 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,17 @@ [package] name = "requestty" -version = "0.0.1" +version = "0.1.0" authors = ["Lutetium Vanadium"] edition = "2018" +description = "An easy-to-use collection of interactive cli prompts" +homepage="https://github.com/Lutetium-Vanadium/requestty#readme" +repository = "https://github.com/Lutetium-Vanadium/requestty" +documentation="https://docs.rs/requestty" +readme = "README.md" +license = "MIT" +keywords = ["interactive", "prompt", "cli", "inquirer", "enquirer"] +categories = ["command-line-interface", "command-line-utilities"] +exclude = ["/.github/*", "/assets", "/requestty-ui", "/requestty-macro", "*-snapshots"] [workspace] members = [ @@ -13,8 +22,8 @@ members = [ [dependencies] tempfile = "3" -ui = { package = "requestty-ui", path = "./requestty-ui" } -macro = { package = "requestty-macro", path = "./requestty-macro", optional = true } +ui = { package = "requestty-ui", path = "./requestty-ui", version = "=0.1.0" } +macro = { package = "requestty-macro", path = "./requestty-macro", optional = true, version = "=0.1.0" } smallvec = { version = "1.6", optional = true } diff --git a/README.md b/README.md index d782122..add6db1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,150 @@ # Requestty -WIP rust clone of [Inquirer.js](https://github.com/SBoudrias/Inquirer.js) +![RustCI](https://github.com/Lutetium-Vanadium/requestty/workflows/Default/badge.svg) +![RustCI](https://github.com/Lutetium-Vanadium/requestty/workflows/Crossterm/badge.svg) +![RustCI](https://github.com/Lutetium-Vanadium/requestty/workflows/Termion/badge.svg) +[![Crates.io](https://img.shields.io/crates/v/requestty.svg)](https://crates.io/crates/requestty) +[![License](https://img.shields.io/crates/l/requestty.svg)](./LICENSE) +[![Documentation](https://docs.rs/requestty.svg)](https://docs.rs/requestty) -Minimum supported rust version (as per [cargo-msrv](https://crates.io/crates/cargo-msrv)) -is `1.47` +`requestty` (request-tty) is an easy-to-use collection of interactive +cli prompts inspired by [Inquirer.js](https://github.com/SBoudrias/Inquirer.js). + +- Easy-to-use - The builder API and macros allow you to easily configure + and use the in-built prompts. + +- Extensible - Easily create and use custom prompts with a companion + ui rendering library. + +- Flexible - All prompts can be used standalone or chained together. + +- Dynamic - You can dynamically decide what questions should be asked + based on previous questions. + +- Validation - You can validate user input with any prompt. + +- Examples - Every prompt is accompanied with an example as well as other + [examples](./examples) for more complex workflows + +## Usage + +Add this to your `Cargo.toml` + +```toml +[dependencies] +requestty = "0.1.0" +``` + +```rust +let question = requestty::Question::expand("overwrite") + .message("Conflict on `file.rs`") + .choices(vec![ + ('y', "Overwrite"), + ('a', "Overwrite this one and all next"), + ('d', "Show diff"), + ]) + .default_separator() + .choice('x', "Abort") + .build(); + +println!("{:#?}", requestty::prompt_one(question)); +``` + +## In-built prompts + +There are 10 in-built prompts: + +- ### Input + + Prompt that takes user input and returns a `String`. + + + +- ### Password + + Prompt that takes user input and hides it. + +
+ + +
+ +- ### Editor + + Prompt that takes launches the users preferred editor on a temporary + file + + + +- ### Confirm + + Prompt that returns `true` or `false`. + + + +- ### Int + + Prompt that takes a `i64` as input. + + + +- ### Float + + Prompt that takes a `f64` as input. + + + +- ### Expand + + Prompt that allows the user to select from a list of options by key + + + +- ### Select + + Prompt that allows the user to select from a list of options + + + +- ### RawSelect + + Prompt that allows the user to select from a list of options with + indices + + + +- ### MultiSelect + + Prompt that allows the user to select multiple items from a list of + options + + + +## Optional features + +- `macros`: Enabling this feature will allow you to use the `questions` + and `prompt_module` macros. + +- `smallvec` (default): Enabling this feature will use + [`SmallVec`](https://docs.rs/smallvec/1.6.1/smallvec/struct.SmallVec.html) + instead of `Vec` for auto completions. This allows inlining single + completions. + +- `crossterm` (default): Enabling this feature will use the + [`crossterm`](https://crates.io/crates/crossterm) library for terminal + interactions such as drawing and receiving events. + +- `termion`: Enabling this feature will use the + [`termion`](https://crates.io/crates/termion) library for terminal + interactions such as drawing and receiving events. + +## Minimum Supported Rust Version (MSRV) + +Minimum supported rust version (as per +[cargo-msrv](https://crates.io/crates/cargo-msrv)) is `1.47` diff --git a/requestty-macro/Cargo.toml b/requestty-macro/Cargo.toml index 005bac6..0d61c50 100644 --- a/requestty-macro/Cargo.toml +++ b/requestty-macro/Cargo.toml @@ -1,8 +1,14 @@ [package] name = "requestty-macro" -version = "0.0.1" +version = "0.1.0" authors = ["Lutetium Vanadium"] edition = "2018" +description = "The `questions` macro for `requestty`" +homepage="https://github.com/Lutetium-Vanadium/requestty#readme" +repository = "https://github.com/Lutetium-Vanadium/requestty" +documentation="https://docs.rs/requestty-macro" +readme = "../README.md" +license = "MIT" [lib] proc-macro = true diff --git a/requestty-macro/src/lib.rs b/requestty-macro/src/lib.rs index 74faf36..ab74851 100644 --- a/requestty-macro/src/lib.rs +++ b/requestty-macro/src/lib.rs @@ -1,8 +1,7 @@ //! This crate is the declaration of the [`questions!`] macro. It should not be used directly. Use //! [`requestty`] instead. //! -//! [`requestty`]: https://github.com/lutetium-vanadium/requestty -// TODO: [`requestty`]: https://crates.io/crates/requestty +//! [`requestty`]: https://crates.io/crates/requestty extern crate proc_macro; use proc_macro::TokenStream; diff --git a/requestty-ui/Cargo.toml b/requestty-ui/Cargo.toml index 98ce744..5780661 100644 --- a/requestty-ui/Cargo.toml +++ b/requestty-ui/Cargo.toml @@ -1,8 +1,16 @@ [package] name = "requestty-ui" -version = "0.0.1" +version = "0.1.0" authors = ["Lutetium Vanadium"] edition = "2018" +description = "A widget based terminal ui rendering library." +homepage="https://github.com/Lutetium-Vanadium/requestty#readme" +repository = "https://github.com/Lutetium-Vanadium/requestty" +documentation="https://docs.rs/requestty-ui" +license = "MIT" +keywords = ["interactive", "prompt", "cli", "inquirer", "enquirer"] +categories = ["command-line-interface", "command-line-utilities"] +exclude = ["*-snapshots"] [dependencies] bitflags = "1.2" diff --git a/requestty-ui/src/lib.rs b/requestty-ui/src/lib.rs index 881ab51..463b4cc 100644 --- a/requestty-ui/src/lib.rs +++ b/requestty-ui/src/lib.rs @@ -6,7 +6,7 @@ //! While this crate was built for the [`requestty`] crate and other crates which implement the //! `Prompt` trait in [`requestty`], it can be used otherwise as well. //! -//! [`requestty`]: https://github.com/lutetium-vanadium/requestty +//! [`requestty`]: https://crates.io/crates/requestty //! //! # Backends //! @@ -15,7 +15,6 @@ //! - [`termion`](https://crates.io/crates/termion) //! //! The different backends can be enabled using the features of the same name. -// TODO: [`requestty`]: https://crates.io/crates/requestty #![deny( missing_docs, missing_debug_implementations, diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index ad2160e..0000000 --- a/src/main.rs +++ /dev/null @@ -1,176 +0,0 @@ -// TODO: delete -// this is a temporary file, for testing out the prompts -use requestty::{DefaultSeparator, Question, Separator}; -use std::env; - -fn main() { - let s = String::from("Hello there "); - - let q = match env::args().nth(1).as_deref() { - Some("b") => vec![ - Question::confirm("a").message("Hello there 1").build(), - Question::confirm("b") - .message("Hello there 2") - .default(true) - .build(), - ], - Some("s") => vec![ - Question::input("a").message("Hello there 2").into(), - Question::input("b") - .message(|_: &requestty::Answers| s[0..(s.len() - 1)].to_owned()) - .filter(|mut ans, _| { - ans.insert_str(0, &s); - ans - }) - .validate(|_, _| Ok(())) - .default("Yes") - .into(), - ], - Some("p") => vec![ - Question::password("a") - .message("password 1") - .filter(|ans, _| ans + &s) - .mask('*') - .into(), - Question::password("b").message("password 2").into(), - ], - Some("i") => vec![ - Question::int("a").message("int 1").into(), - Question::int("b").message("int 2").default(3).into(), - ], - Some("f") => vec![ - Question::float("a").message("float 1").into(), - Question::float("b").message("float 2").default(3.12).into(), - ], - Some("e") => vec![ - Question::editor("a") - .message("editor 1") - .default("Hello there") - .into(), - Question::editor("b") - .message("editor 2") - .extension(".rs") - .into(), - ], - - Some("l") => vec![ - Question::select("a") - .message("select 1") - .choices(vec![ - "0".into(), - DefaultSeparator, - "1".into(), - "2".into(), - "3".into(), - Separator("== Hello separator".into()), - ]) - .default(3) - .into(), - Question::select("b") - .message("select 2") - .choices(vec![ - Separator("=== TITLE BOI ===".into()), - "hello worldssssss 1\nMulti-line description about it".into(), - "hello worldssssss 2".into(), - "hello worldssssss 3".into(), - "hello worldssssss 4".into(), - "hello worldssssss 5".into(), - DefaultSeparator, - "hello worldssssss 6".into(), - "hello worldssssss 7".into(), - "hello worldssssss 8".into(), - ]) - .page_size(6) - .should_loop(false) - .into(), - ], - - Some("c") => vec![ - Question::multi_select("a") - .message("multi select 1") - .choice_with_default("0", true) - .default_separator() - .choices_with_default(vec![("1", false), ("2", true), ("3", false)]) - .separator("== Hello separator") - .into(), - Question::multi_select("b") - .message("multi select 2") - .choices(vec![ - Separator("=== TITLE BOI ===".into()), - "hello worldssssss 1\nMulti-line description about it".into(), - "hello worldssssss 2".into(), - "hello worldssssss 3".into(), - "hello worldssssss 4".into(), - "hello worldssssss 5".into(), - DefaultSeparator, - "hello worldssssss 6".into(), - "hello worldssssss 7".into(), - "hello worldssssss 8".into(), - ]) - .page_size(6) - .should_loop(false) - .into(), - ], - - Some("r") => vec![ - Question::raw_select("a") - .message("select 1") - .choices(vec![ - "0".into(), - DefaultSeparator, - "1".into(), - "2".into(), - "3".into(), - Separator("== Hello separator".into()), - ]) - .default(2) - .into(), - Question::raw_select("b") - .message("select 2") - .choices(vec![ - Separator("=== TITLE BOI ===".into()), - "hello worldssssss 1\nMulti-line description about it".into(), - "hello worldssssss 2".into(), - "hello worldssssss 3".into(), - "hello worldssssss 4".into(), - "hello worldssssss 5".into(), - DefaultSeparator, - "hello worldssssss 6".into(), - "hello worldssssss 7".into(), - "hello worldssssss 8".into(), - ]) - .page_size(6) - // .should_loop(false) - .into(), - ], - - Some("x") => vec![ - Question::expand("a") - .message("expand 1") - .choices(vec![ - ('y', "Overwrite").into(), - ('a', "Overwrite this one and all next").into(), - ('d', "Show diff").into(), - DefaultSeparator, - ('x', "Abort").into(), - ]) - .into(), - Question::expand("b") - .message("expand 2") - .choice('a', "Name for a") - .default_separator() - .choices(vec![ - ('b', "Name for b\nMulti-line description"), - ('c', "Name for c"), - ]) - .default_separator() - .choice('d', "Name for d") - .separator("== Hello separator") - .default('b') - .into(), - ], - _ => panic!("no arg"), - }; - - println!("{:#?}", requestty::prompt(q)); -}