From f0475c2207181c13dabcd4e78a163cde70573ade Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Sat, 4 Apr 2026 17:52:19 +0800 Subject: Add vector pickers --- mingling/Cargo.lock | 8 +- mingling/Cargo.toml | 6 +- mingling/src/parser/args.rs | 69 ++++++-- mingling/src/parser/picker/builtin.rs | 42 +++++ mingling_core/Cargo.lock | 2 +- mingling_core/Cargo.toml | 2 +- mingling_core/src/program/flag.rs | 320 ++++++++++++++++++++++++++++++++++ 7 files changed, 427 insertions(+), 22 deletions(-) diff --git a/mingling/Cargo.lock b/mingling/Cargo.lock index b3559d8..ef9be06 100644 --- a/mingling/Cargo.lock +++ b/mingling/Cargo.lock @@ -16,7 +16,7 @@ checksum = "5454cda0d57db59778608d7a47bff5b16c6705598265869fb052b657f66cf05e" [[package]] name = "mingling" -version = "0.1.3" +version = "0.1.4" dependencies = [ "mingling", "mingling_core", @@ -27,9 +27,7 @@ dependencies = [ [[package]] name = "mingling_core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "582a051d0598bb23b4b5103f9a3f5cf6b3b825f3b01b1612640ba88bbeb4ff07" +version = "0.1.3" dependencies = [ "just_fmt", "serde", @@ -40,8 +38,6 @@ dependencies = [ [[package]] name = "mingling_macros" version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e324eedf81f8b4c2947d6ce96dbd763a2da0d3b182c3f9c550974407f81c19" dependencies = [ "just_fmt", "once_cell", diff --git a/mingling/Cargo.toml b/mingling/Cargo.toml index 10bf41d..68f37f9 100644 --- a/mingling/Cargo.toml +++ b/mingling/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mingling" -version = "0.1.3" +version = "0.1.4" edition = "2024" authors = ["Weicao-CatilGrass"] license = "MIT OR Apache-2.0" @@ -25,7 +25,7 @@ general_renderer = [ parser = ["dep:size"] [dependencies] -mingling_core = { version = "0.1.2", default-features = false } -mingling_macros = { version = "0.1.2", default-features = false } +mingling_core = { path = "../mingling_core", default-features = false } +mingling_macros = { path = "../mingling_macros", default-features = false } serde = { version = "1.0", features = ["derive"], optional = true } size = { version = "0.5", optional = true } diff --git a/mingling/src/parser/args.rs b/mingling/src/parser/args.rs index 0210b56..084051d 100644 --- a/mingling/src/parser/args.rs +++ b/mingling/src/parser/args.rs @@ -1,6 +1,6 @@ use std::mem::replace; -use mingling_core::{Flag, special_argument, special_flag}; +use mingling_core::{Flag, special_argument, special_arguments, special_flag}; /// User input arguments #[derive(Debug, Default)] @@ -67,32 +67,79 @@ impl std::ops::DerefMut for Argument { } impl Argument { - /// Extracts argument (with value) from arguments + /// Picks a single argument with the given flag pub fn pick_argument(&mut self, flag: F) -> Option where F: Into, { + if self.len() < 1 { + return None; + } + let flag: Flag = flag.into(); - for argument in flag.iter() { - let value = special_argument!(self.vec, argument); - if value.is_some() { - return value; + if flag.len() > 0 { + // Has any flag + for argument in flag.iter() { + let value = special_argument!(self.vec, argument); + if value.is_some() { + return value; + } } + } else { + // No flag + return Some(self.vec.remove(0)); } None } - /// Extracts flags from arguments - pub fn pick_flag(&mut self, flag: F) -> bool + /// Picks arguments with the given flag + pub fn pick_arguments(&mut self, flag: F) -> Vec where F: Into, { + let mut str_result = Vec::new(); + + if self.len() < 1 { + return str_result; + } + let flag: Flag = flag.into(); for argument in flag.iter() { - let enabled = special_flag!(self.vec, argument); - if enabled { - return enabled; + let value = special_arguments!(self.vec, argument); + str_result.extend(value); + } + + str_result + } + + /// Picks a flag with the given flag + pub fn pick_flag(&mut self, flag: F) -> bool + where + F: Into, + { + if self.len() < 1 { + return false; + } + + let flag: Flag = flag.into(); + if flag.len() > 0 { + // Has any flag + for argument in flag.iter() { + let enabled = special_flag!(self.vec, argument); + if enabled { + return enabled; + } } + } else { + let first = self.vec.remove(0); + let first_lower = first.to_lowercase(); + let trimmed = first_lower.trim(); + let result = match trimmed { + "y" | "yes" | "true" | "1" => return true, + "n" | "no" | "false" | "0" => return false, + _ => false, + }; + return result; } false } diff --git a/mingling/src/parser/picker/builtin.rs b/mingling/src/parser/picker/builtin.rs index 9184813..8a10dfc 100644 --- a/mingling/src/parser/picker/builtin.rs +++ b/mingling/src/parser/picker/builtin.rs @@ -10,6 +10,14 @@ impl Pickable for String { } } +impl Pickable for Vec { + type Output = Vec; + + fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option { + Some(args.pick_arguments(flag)) + } +} + macro_rules! impl_pickable_for_number { ($($t:ty),*) => { $( @@ -23,6 +31,23 @@ macro_rules! impl_pickable_for_number { picked.parse().ok() } } + + impl Pickable for Vec<$t> { + type Output = Vec<$t>; + + fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option { + let picked_vec = args.pick_arguments(flag); + let mut result = Vec::new(); + for picked in picked_vec { + if let Ok(parsed) = picked.parse() { + result.push(parsed); + } else { + return None; + } + } + Some(result) + } + } )* }; } @@ -52,6 +77,23 @@ impl Pickable for usize { } } +impl Pickable for Vec { + type Output = Vec; + + fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option { + let picked_vec = args.pick_arguments(flag); + let mut result = Vec::new(); + for picked in picked_vec { + let size_parse = Size::from_str(picked.as_str()); + match size_parse { + Ok(size) => result.push(size.bytes() as usize), + Err(_) => return None, + } + } + Some(result) + } +} + impl Pickable for Argument { type Output = Argument; diff --git a/mingling_core/Cargo.lock b/mingling_core/Cargo.lock index 5def9e6..a938576 100644 --- a/mingling_core/Cargo.lock +++ b/mingling_core/Cargo.lock @@ -16,7 +16,7 @@ checksum = "5454cda0d57db59778608d7a47bff5b16c6705598265869fb052b657f66cf05e" [[package]] name = "mingling_core" -version = "0.1.2" +version = "0.1.3" dependencies = [ "just_fmt", "serde", diff --git a/mingling_core/Cargo.toml b/mingling_core/Cargo.toml index 40b4c41..4660f78 100644 --- a/mingling_core/Cargo.toml +++ b/mingling_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mingling_core" -version = "0.1.2" +version = "0.1.3" edition = "2024" license = "MIT OR Apache-2.0" description = "Core of the mingling library" diff --git a/mingling_core/src/program/flag.rs b/mingling_core/src/program/flag.rs index a520495..edc3dfd 100644 --- a/mingling_core/src/program/flag.rs +++ b/mingling_core/src/program/flag.rs @@ -131,6 +131,326 @@ macro_rules! special_argument { }}; } +#[macro_export] +#[doc(hidden)] +macro_rules! special_arguments { + ($args:expr, $flag:expr) => {{ + let flag = $flag; + let mut values: Vec = Vec::new(); + let mut i = 0; + while i < $args.len() { + if &$args[i] == flag { + $args.remove(i); + while i < $args.len() && !$args[i].starts_with('-') { + values.push($args[i].clone()); + $args.remove(i); + } + break; + } + i += 1; + } + values + }}; +} + +#[cfg(test)] +mod tests { + #[test] + fn test_special_flag() { + // Test flag found and removed + let mut args = vec![ + "a".to_string(), + "b".to_string(), + "--help".to_string(), + "c".to_string(), + ]; + let result = special_flag!(args, "--help"); + assert!(result); + assert_eq!(args, vec!["a", "b", "c"]); + + // Test flag found at beginning + let mut args = vec![ + "--help".to_string(), + "a".to_string(), + "b".to_string(), + "c".to_string(), + ]; + let result = special_flag!(args, "--help"); + assert!(result); + assert_eq!(args, vec!["a", "b", "c"]); + + // Test flag found at end + let mut args = vec![ + "a".to_string(), + "b".to_string(), + "c".to_string(), + "--help".to_string(), + ]; + let result = special_flag!(args, "--help"); + assert!(result); + assert_eq!(args, vec!["a", "b", "c"]); + + // Test flag not found + let mut args = vec![ + "a".to_string(), + "b".to_string(), + "--other".to_string(), + "c".to_string(), + ]; + let result = special_flag!(args, "--help"); + assert!(!result); + assert_eq!(args, vec!["a", "b", "--other", "c"]); + + // Test multiple same flags all removed + let mut args = vec![ + "--help".to_string(), + "a".to_string(), + "--help".to_string(), + "b".to_string(), + "--help".to_string(), + ]; + let result = special_flag!(args, "--help"); + assert!(result); + assert_eq!(args, vec!["a", "b"]); + + // Test empty args + let mut args: Vec = Vec::new(); + let result = special_flag!(args, "--help"); + assert!(!result); + assert_eq!(args, Vec::::new()); + + // Test flag with empty string + let mut args = vec!["a".to_string(), "".to_string(), "b".to_string()]; + let result = special_flag!(args, ""); + assert!(result); + assert_eq!(args, vec!["a", "b"]); + + // Test flag with dash in middle + let mut args = vec!["a".to_string(), "test-flag".to_string(), "b".to_string()]; + let result = special_flag!(args, "test-flag"); + assert!(result); + assert_eq!(args, vec!["a", "b"]); + + // Test flag that's a substring of another flag (should not match) + let mut args = vec!["a".to_string(), "--helpful".to_string(), "b".to_string()]; + let result = special_flag!(args, "--help"); + assert!(!result); + assert_eq!(args, vec!["a", "--helpful", "b"]); + } + + #[test] + fn test_special_argument() { + // Test extracting value after flag + let mut args = vec![ + "a".to_string(), + "b".to_string(), + "--file".to_string(), + "test.txt".to_string(), + "c".to_string(), + ]; + let result = special_argument!(args, "--file"); + assert_eq!(result, Some("test.txt".to_string())); + assert_eq!(args, vec!["a", "b", "c"]); + + // Test extracting value when flag is at beginning + let mut args = vec![ + "--file".to_string(), + "test.txt".to_string(), + "a".to_string(), + "b".to_string(), + ]; + let result = special_argument!(args, "--file"); + assert_eq!(result, Some("test.txt".to_string())); + assert_eq!(args, vec!["a", "b"]); + + // Test extracting value when flag is at end + let mut args = vec![ + "a".to_string(), + "b".to_string(), + "--file".to_string(), + "test.txt".to_string(), + ]; + let result = special_argument!(args, "--file"); + assert_eq!(result, Some("test.txt".to_string())); + assert_eq!(args, vec!["a", "b"]); + + // Test flag without value (at end) + let mut args = vec!["a".to_string(), "b".to_string(), "--file".to_string()]; + let result = special_argument!(args, "--file"); + assert_eq!(result, None); + assert_eq!(args, vec!["a", "b"]); + + // Test flag without value (not at end) + let mut args = vec!["a".to_string(), "--file".to_string(), "b".to_string()]; + let result = special_argument!(args, "--file"); + assert_eq!(result, Some("b".to_string())); + assert_eq!(args, vec!["a"]); + + // Test flag not found + let mut args = vec![ + "a".to_string(), + "b".to_string(), + "--other".to_string(), + "value".to_string(), + ]; + let result = special_argument!(args, "--file"); + assert_eq!(result, None); + assert_eq!(args, vec!["a", "b", "--other", "value"]); + + // Test empty args + let mut args: Vec = Vec::new(); + let result = special_argument!(args, "--file"); + assert_eq!(result, None); + assert_eq!(args, Vec::::new()); + + // Test multiple same flags (should only extract first) + let mut args = vec![ + "--file".to_string(), + "first.txt".to_string(), + "--file".to_string(), + "second.txt".to_string(), + ]; + let result = special_argument!(args, "--file"); + assert_eq!(result, Some("first.txt".to_string())); + assert_eq!(args, vec!["--file", "second.txt"]); + + // Test flag with empty string value + let mut args = vec![ + "a".to_string(), + "--file".to_string(), + "".to_string(), + "b".to_string(), + ]; + let result = special_argument!(args, "--file"); + assert_eq!(result, Some("".to_string())); + assert_eq!(args, vec!["a", "b"]); + + // Test flag with value starting with dash + let mut args = vec![ + "a".to_string(), + "--file".to_string(), + "-value".to_string(), + "b".to_string(), + ]; + let result = special_argument!(args, "--file"); + assert_eq!(result, Some("-value".to_string())); + assert_eq!(args, vec!["a", "b"]); + } + + #[test] + fn test_special_arguments() { + // Test extracting multiple values after flag + let mut args = vec![ + "a".to_string(), + "b".to_string(), + "--list".to_string(), + "a".to_string(), + "b".to_string(), + "c".to_string(), + "d".to_string(), + "--next".to_string(), + "1".to_string(), + ]; + let result = special_arguments!(args, "--list"); + assert_eq!(result, vec!["a", "b", "c", "d"]); + assert_eq!(args, vec!["a", "b", "--next", "1"]); + + // Test extracting single value + let mut args = vec![ + "a".to_string(), + "b".to_string(), + "--next".to_string(), + "1".to_string(), + ]; + let result = special_arguments!(args, "--next"); + assert_eq!(result, vec!["1"]); + assert_eq!(args, vec!["a", "b"]); + + // Test extracting from beginning + let mut args = vec![ + "--list".to_string(), + "a".to_string(), + "b".to_string(), + "--next".to_string(), + "1".to_string(), + ]; + let result = special_arguments!(args, "--list"); + assert_eq!(result, vec!["a", "b"]); + assert_eq!(args, vec!["--next", "1"]); + + // Test extracting when no values after flag + let mut args = vec![ + "a".to_string(), + "b".to_string(), + "--list".to_string(), + "--next".to_string(), + "1".to_string(), + ]; + let result = special_arguments!(args, "--list"); + assert_eq!(result, Vec::::new()); + assert_eq!(args, vec!["a", "b", "--next", "1"]); + + // Test extracting when flag not found + let mut args = vec![ + "a".to_string(), + "b".to_string(), + "--list".to_string(), + "c".to_string(), + "d".to_string(), + ]; + let result = special_arguments!(args, "--none"); + assert_eq!(result, Vec::::new()); + assert_eq!(args, vec!["a", "b", "--list", "c", "d"]); + + // Test extracting empty args + let mut args: Vec = Vec::new(); + let result = special_arguments!(args, "--list"); + assert_eq!(result, Vec::::new()); + assert_eq!(args, Vec::::new()); + + // Test extracting with only flag at end + let mut args = vec!["--list".to_string()]; + let result = special_arguments!(args, "--list"); + assert_eq!(result, Vec::::new()); + assert_eq!(args, Vec::::new()); + + // Test extracting multiple values until end of args + let mut args = vec![ + "--list".to_string(), + "a".to_string(), + "b".to_string(), + "c".to_string(), + ]; + let result = special_arguments!(args, "--list"); + assert_eq!(result, vec!["a", "b", "c"]); + assert_eq!(args, Vec::::new()); + + // Test extracting with mixed non-dash values + let mut args = vec![ + "--list".to_string(), + "value1".to_string(), + "value2".to_string(), + "-next".to_string(), + "value3".to_string(), + ]; + let result = special_arguments!(args, "--list"); + assert_eq!(result, vec!["value1", "value2"]); + assert_eq!(args, vec!["-next", "value3"]); + + // Test extracting with single dash values + let mut args = vec![ + "--list".to_string(), + "-a".to_string(), + "-b".to_string(), + "--next".to_string(), + "1".to_string(), + ]; + let result = special_arguments!(args, "--list"); + assert_eq!(result, Vec::::new()); + assert_eq!(args, vec!["-a", "-b", "--next", "1"]); + } +} + impl Program where C: ProgramCollect, -- cgit