summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormo8it <mo8it@proton.me>2023-08-25 23:18:01 +0200
committerliv <shadows_withal@fastmail.com>2023-09-04 13:30:46 +0200
commit5a93f2a4f14d83d34aac69254262da7aaa5b752c (patch)
treefeef7dd69d154fc2ea6c5875b72ee0bdad3e27b4
parent2d1da2ab57080e32725612ffddb82006f47f7f71 (diff)
Port to Clap
-rw-r--r--Cargo.lock131
-rw-r--r--Cargo.toml15
-rw-r--r--src/main.rs195
3 files changed, 207 insertions, 134 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5a40b6f..e5b8553 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,20 +4,62 @@ version = 3
[[package]]
name = "aho-corasick"
-version = "1.0.4"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a"
+checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783"
dependencies = [
"memchr",
]
[[package]]
+name = "anstream"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "utf8parse",
+]
+
+[[package]]
name = "anstyle"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea"
[[package]]
+name = "anstyle-parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
+dependencies = [
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
name = "argh"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -77,9 +119,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bstr"
-version = "1.6.0"
+version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05"
+checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a"
dependencies = [
"memchr",
"regex-automata",
@@ -99,6 +141,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
+name = "clap"
+version = "4.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
+
+[[package]]
name = "console"
version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -210,6 +298,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
name = "home"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -330,9 +424,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
-version = "2.5.0"
+version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
[[package]]
name = "mio"
@@ -493,9 +587,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.9.4"
+version = "1.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29"
+checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
dependencies = [
"aho-corasick",
"memchr",
@@ -505,9 +599,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629"
+checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
dependencies = [
"aho-corasick",
"memchr",
@@ -526,6 +620,7 @@ version = "5.5.1"
dependencies = [
"argh",
"assert_cmd",
+ "clap",
"console",
"glob",
"home",
@@ -603,10 +698,16 @@ dependencies = [
]
[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
name = "syn"
-version = "2.0.29"
+version = "2.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
+checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
dependencies = [
"proc-macro2",
"quote",
@@ -666,6 +767,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
+name = "utf8parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
+
+[[package]]
name = "wait-timeout"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index f627dd7..2c2a92b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,15 +10,16 @@ edition = "2021"
[dependencies]
argh = "0.1"
-indicatif = "0.17"
+indicatif = "0.17.6"
console = "0.15"
notify = "4.0"
-toml = "0.7"
-regex = "1.9"
+toml = "0.7.6"
+regex = "1.5"
serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0.105"
-home = "0.5.5"
-glob = "0.3.1"
+serde_json = "1.0.81"
+home = "0.5.3"
+glob = "0.3.0"
+clap = { version = "4.4.0", features = ["derive"] }
[[bin]]
name = "rustlings"
@@ -27,4 +28,4 @@ path = "src/main.rs"
[dev-dependencies]
assert_cmd = "2.0.12"
predicates = "3.0.3"
-glob = "0.3.1"
+glob = "0.3.0"
diff --git a/src/main.rs b/src/main.rs
index 1a15086..a4b764d 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 clap::{Parser, Subcommand};
use console::Emoji;
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
@@ -25,111 +25,69 @@ 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(Parser)]
+#[command(version)]
struct Args {
- /// show outputs from the test exercises
- #[argh(switch)]
+ /// Show outputs from the test exercises
+ #[arg(long)]
nocapture: bool,
- /// show the executable version
- #[argh(switch, short = 'v')]
- version: bool,
- #[argh(subcommand)]
- nested: Option<Subcommands>,
+ #[command(subcommand)]
+ command: Option<Subcommands>,
}
-#[derive(FromArgs, PartialEq, Debug)]
-#[argh(subcommand)]
+#[derive(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 -- <filename>"
-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<String>,
- #[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,
+ /// Verify all exercises according to the recommended order
+ Verify,
+ /// Rerun `verify` when files were edited
+ Watch {
+ /// Show hints on success
+ #[arg(long)]
+ success_hints: bool,
+ },
+ /// Run/Test a single exercise
+ Run {
+ /// The name of the exercise
+ name: String,
+ },
+ /// Reset a single exercise using "git stash -- <filename>"
+ Reset {
+ /// The name of the exercise
+ name: String,
+ },
+ /// Return a hint for the given exercise
+ Hint {
+ /// The name of the exercise
+ name: String,
+ },
+ /// List the exercises available in Rustlings
+ List {
+ /// Show only the paths of the exercises
+ #[arg(short, long)]
+ paths: bool,
+ /// Show only the names of the exercises
+ #[arg(short, long)]
+ names: bool,
+ /// Provide a string to match exercise names.
+ /// Comma separated patterns are accepted
+ #[arg(short, long)]
+ filter: Option<String>,
+ /// Display only exercises not yet solved
+ #[arg(short, long)]
+ unsolved: bool,
+ /// Display only exercises that have been solved
+ #[arg(short, long)]
+ solved: bool,
+ },
+ /// Enable rust-analyzer for exercises
+ Lsp,
}
fn main() {
- let args: Args = argh::from_env();
+ let args = Args::parse();
- if args.version {
- println!("v{VERSION}");
- std::process::exit(0);
- }
-
- if args.nested.is_none() {
+ if args.command.is_none() {
println!("\n{WELCOME}\n");
}
@@ -153,17 +111,24 @@ fn main() {
let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises;
let verbose = args.nocapture;
- let command = args.nested.unwrap_or_else(|| {
+ let command = args.command.unwrap_or_else(|| {
println!("{DEFAULT_OUT}\n");
std::process::exit(0);
});
+
match command {
- Subcommands::List(subargs) => {
- if !subargs.paths && !subargs.names {
+ Subcommands::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 +142,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 +179,30 @@ fn main() {
std::process::exit(0);
}
- Subcommands::Run(subargs) => {
- let exercise = find_exercise(&subargs.name, &exercises);
+ Subcommands::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);
+ Subcommands::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);
+ Subcommands::Hint { name } => {
+ let exercise = find_exercise(&name, &exercises);
println!("{}", exercise.hint);
}
- Subcommands::Verify(_subargs) => {
+ Subcommands::Verify => {
verify(&exercises, (0, exercises.len()), verbose, false)
.unwrap_or_else(|_| std::process::exit(1));
}
- Subcommands::Lsp(_subargs) => {
+ Subcommands::Lsp => {
let mut project = RustAnalyzerProject::new();
project
.get_sysroot_src()
@@ -256,7 +221,7 @@ fn main() {
}
}
- Subcommands::Watch(_subargs) => match watch(&exercises, verbose, _subargs.success_hints) {
+ Subcommands::Watch { success_hints } => match watch(&exercises, verbose, success_hints) {
Err(e) => {
println!(
"Error: Could not watch your progress. Error message was {:?}.",