From 50f36066e6b297bcc808c11c0e0aca33586ea834 Mon Sep 17 00:00:00 2001 From: mo8it Date: Sat, 26 Aug 2023 12:31:51 +0200 Subject: [PATCH] Replace argh with bpaf --- Cargo.lock | 159 +++++++++++++++++++++++++++++----------- Cargo.toml | 2 +- src/main.rs | 207 +++++++++++++++++++++++----------------------------- 3 files changed, 209 insertions(+), 159 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8268d90..0de24573 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,34 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "argh" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab257697eb9496bf75526f0217b5ed64636a9cfafa78b8365c71bd283fcef93e" -dependencies = [ - "argh_derive", - "argh_shared", -] - -[[package]] -name = "argh_derive" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b382dbd3288e053331f03399e1db106c9fb0d8562ad62cb04859ae926f324fa6" -dependencies = [ - "argh_shared", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "argh_shared" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cb94155d965e3d37ffbbe7cc5b82c3dd79dd33bd48e536f73d2cfb8d85506f" - [[package]] name = "assert_cmd" version = "0.11.1" @@ -63,6 +35,43 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "bpaf" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dc3b1bd654a8d16eea03586c3eee8ffd25c7f242b9eae9730cc442834fe56d9" +dependencies = [ + "bpaf_derive", + "owo-colors", + "supports-color", +] + +[[package]] +name = "bpaf_derive" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cbaba260bbcbb69b0d54e9f0d83038a4568f3a5d1c95591fed5e8fee964539" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + [[package]] name = "cfg-if" version = "0.1.10" @@ -100,6 +109,27 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "errno" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "escargot" version = "0.4.0" @@ -139,7 +169,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "fsevent-sys", ] @@ -158,7 +188,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags", + "bitflags 1.3.2", "fuchsia-zircon-sys", ] @@ -174,6 +204,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + [[package]] name = "home" version = "0.5.5" @@ -201,7 +237,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" dependencies = [ - "bitflags", + "bitflags 1.3.2", "inotify-sys", "libc", ] @@ -224,6 +260,23 @@ dependencies = [ "libc", ] +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "is_ci" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" + [[package]] name = "itoa" version = "1.0.8" @@ -258,6 +311,12 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "linux-raw-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" + [[package]] name = "log" version = "0.4.19" @@ -336,7 +395,7 @@ version = "4.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" dependencies = [ - "bitflags", + "bitflags 1.3.2", "filetime", "fsevent", "fsevent-sys", @@ -363,6 +422,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + [[package]] name = "predicates" version = "1.0.8" @@ -416,7 +481,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -448,12 +513,25 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +[[package]] +name = "rustix" +version = "0.38.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rustlings" version = "5.5.1" dependencies = [ - "argh", "assert_cmd", + "bpaf", "console", "glob", "home", @@ -498,7 +576,7 @@ checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn", ] [[package]] @@ -522,14 +600,13 @@ dependencies = [ ] [[package]] -name = "syn" -version = "1.0.109" +name = "supports-color" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "4950e7174bffabe99455511c39707310e7e9b440364a2fcb1cc21521be57b354" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "is-terminal", + "is_ci", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index eca091f4..1d0a9c9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ authors = [ edition = "2021" [dependencies] -argh = "0.1" indicatif = "0.16" console = "0.15" notify = "4.0" @@ -19,6 +18,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.81" home = "0.5.3" glob = "0.3.0" +bpaf = { version = "0.9.5", features = ["derive", "bright-color"] } [[bin]] name = "rustlings" diff --git a/src/main.rs b/src/main.rs index 0a9af2ec..2e67931f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use crate::exercise::{Exercise, ExerciseList}; use crate::project::RustAnalyzerProject; use crate::run::{reset, run}; use crate::verify::verify; -use argh::FromArgs; +use bpaf::Bpaf; use console::Emoji; use notify::DebouncedEvent; use notify::{RecommendedWatcher, RecursiveMode, Watcher}; @@ -25,111 +25,77 @@ mod project; mod run; mod verify; -// In sync with crate version -const VERSION: &str = "5.5.1"; - -#[derive(FromArgs, PartialEq, Debug)] /// Rustlings is a collection of small exercises to get you used to writing and reading Rust code +#[derive(Bpaf)] +#[bpaf(options, version)] struct Args { - /// show outputs from the test exercises - #[argh(switch)] + /// Show outputs from the test exercises nocapture: bool, - /// show the executable version - #[argh(switch, short = 'v')] - version: bool, - #[argh(subcommand)] - nested: Option, + #[bpaf(external, optional)] + subcommand: Option, } -#[derive(FromArgs, PartialEq, Debug)] -#[argh(subcommand)] -enum Subcommands { - Verify(VerifyArgs), - Watch(WatchArgs), - Run(RunArgs), - Reset(ResetArgs), - Hint(HintArgs), - List(ListArgs), - Lsp(LspArgs), -} - -#[derive(FromArgs, PartialEq, Debug)] -#[argh(subcommand, name = "verify")] -/// Verifies all exercises according to the recommended order -struct VerifyArgs {} - -#[derive(FromArgs, PartialEq, Debug)] -#[argh(subcommand, name = "watch")] -/// Reruns `verify` when files were edited -struct WatchArgs { - /// show hints on success - #[argh(switch)] - success_hints: bool, -} - -#[derive(FromArgs, PartialEq, Debug)] -#[argh(subcommand, name = "run")] -/// Runs/Tests a single exercise -struct RunArgs { - #[argh(positional)] - /// the name of the exercise - name: String, -} - -#[derive(FromArgs, PartialEq, Debug)] -#[argh(subcommand, name = "reset")] -/// Resets a single exercise using "git stash -- " -struct ResetArgs { - #[argh(positional)] - /// the name of the exercise - name: String, -} - -#[derive(FromArgs, PartialEq, Debug)] -#[argh(subcommand, name = "hint")] -/// Returns a hint for the given exercise -struct HintArgs { - #[argh(positional)] - /// the name of the exercise - name: String, -} - -#[derive(FromArgs, PartialEq, Debug)] -#[argh(subcommand, name = "lsp")] -/// Enable rust-analyzer for exercises -struct LspArgs {} - -#[derive(FromArgs, PartialEq, Debug)] -#[argh(subcommand, name = "list")] -/// Lists the exercises available in Rustlings -struct ListArgs { - #[argh(switch, short = 'p')] - /// show only the paths of the exercises - paths: bool, - #[argh(switch, short = 'n')] - /// show only the names of the exercises - names: bool, - #[argh(option, short = 'f')] - /// provide a string to match exercise names - /// comma separated patterns are acceptable - filter: Option, - #[argh(switch, short = 'u')] - /// display only exercises not yet solved - unsolved: bool, - #[argh(switch, short = 's')] - /// display only exercises that have been solved - solved: bool, +#[derive(Bpaf, Clone)] +enum Subcommand { + /// Verify all exercises according to the recommended order + #[bpaf(command)] + Verify, + /// Rerun `verify` when files were edited + #[bpaf(command)] + Watch { + /// Show hints on success + success_hints: bool, + }, + /// Run/Test a single exercise + #[bpaf(command)] + Run { + /// The name of the exercise + #[bpaf(positional("NAME"))] + name: String, + }, + /// Reset a single exercise using "git stash -- " + #[bpaf(command)] + Reset { + /// The name of the exercise + #[bpaf(positional("NAME"))] + name: String, + }, + /// Return a hint for the given exercise + #[bpaf(command)] + Hint { + /// The name of the exercise + #[bpaf(positional("NAME"))] + name: String, + }, + /// List the exercises available in Rustlings + #[bpaf(command)] + List { + /// Show only the paths of the exercises + #[bpaf(short, long)] + paths: bool, + /// Show only the names of the exercises + #[bpaf(short, long)] + names: bool, + /// Provide a string to match exercise names. + /// Comma separated patterns are accepted + #[bpaf(short, long)] + filter: Option, + /// Display only exercises not yet solved + #[bpaf(short, long)] + unsolved: bool, + /// Display only exercises that have been solved + #[bpaf(short, long)] + solved: bool, + }, + /// Enable rust-analyzer for exercises + #[bpaf(command)] + Lsp, } fn main() { - let args: Args = argh::from_env(); + let args = args().run(); - if args.version { - println!("v{VERSION}"); - std::process::exit(0); - } - - if args.nested.is_none() { + if args.subcommand.is_none() { println!("\n{WELCOME}\n"); } @@ -153,17 +119,24 @@ fn main() { let exercises = toml::from_str::(toml_str).unwrap().exercises; let verbose = args.nocapture; - let command = args.nested.unwrap_or_else(|| { + let subcommand = args.subcommand.unwrap_or_else(|| { println!("{DEFAULT_OUT}\n"); std::process::exit(0); }); - match command { - Subcommands::List(subargs) => { - if !subargs.paths && !subargs.names { + + match subcommand { + Subcommand::List { + paths, + names, + filter, + unsolved, + solved, + } => { + if !paths && !names { println!("{:<17}\t{:<46}\t{:<7}", "Name", "Path", "Status"); } let mut exercises_done: u16 = 0; - let filters = subargs.filter.clone().unwrap_or_default().to_lowercase(); + let filters = filter.clone().unwrap_or_default().to_lowercase(); exercises.iter().for_each(|e| { let fname = format!("{}", e.path.display()); let filter_cond = filters @@ -177,14 +150,14 @@ fn main() { "Pending" }; let solve_cond = { - (e.looks_done() && subargs.solved) - || (!e.looks_done() && subargs.unsolved) - || (!subargs.solved && !subargs.unsolved) + (e.looks_done() && solved) + || (!e.looks_done() && unsolved) + || (!solved && !unsolved) }; - if solve_cond && (filter_cond || subargs.filter.is_none()) { - let line = if subargs.paths { + if solve_cond && (filter_cond || filter.is_none()) { + let line = if paths { format!("{fname}\n") - } else if subargs.names { + } else if names { format!("{}\n", e.name) } else { format!("{:<17}\t{fname:<46}\t{status:<7}\n", e.name) @@ -214,30 +187,30 @@ fn main() { std::process::exit(0); } - Subcommands::Run(subargs) => { - let exercise = find_exercise(&subargs.name, &exercises); + Subcommand::Run { name } => { + let exercise = find_exercise(&name, &exercises); run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1)); } - Subcommands::Reset(subargs) => { - let exercise = find_exercise(&subargs.name, &exercises); + Subcommand::Reset { name } => { + let exercise = find_exercise(&name, &exercises); reset(exercise).unwrap_or_else(|_| std::process::exit(1)); } - Subcommands::Hint(subargs) => { - let exercise = find_exercise(&subargs.name, &exercises); + Subcommand::Hint { name } => { + let exercise = find_exercise(&name, &exercises); println!("{}", exercise.hint); } - Subcommands::Verify(_subargs) => { + Subcommand::Verify => { verify(&exercises, (0, exercises.len()), verbose, false) .unwrap_or_else(|_| std::process::exit(1)); } - Subcommands::Lsp(_subargs) => { + Subcommand::Lsp => { let mut project = RustAnalyzerProject::new(); project .get_sysroot_src() @@ -256,7 +229,7 @@ fn main() { } } - Subcommands::Watch(_subargs) => match watch(&exercises, verbose, _subargs.success_hints) { + Subcommand::Watch { success_hints } => match watch(&exercises, verbose, success_hints) { Err(e) => { println!( "Error: Could not watch your progress. Error message was {:?}.",