summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mingling/Cargo.lock8
-rw-r--r--mingling/Cargo.toml6
-rw-r--r--mingling/src/parser/args.rs69
-rw-r--r--mingling/src/parser/picker/builtin.rs42
-rw-r--r--mingling_core/Cargo.lock2
-rw-r--r--mingling_core/Cargo.toml2
-rw-r--r--mingling_core/src/program/flag.rs320
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<F>(&mut self, flag: F) -> Option<String>
where
F: Into<Flag>,
{
+ 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<F>(&mut self, flag: F) -> bool
+ /// Picks arguments with the given flag
+ pub fn pick_arguments<F>(&mut self, flag: F) -> Vec<String>
where
F: Into<Flag>,
{
+ 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<F>(&mut self, flag: F) -> bool
+ where
+ F: Into<Flag>,
+ {
+ 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<String> {
+ type Output = Vec<String>;
+
+ fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> {
+ 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<Self::Output> {
+ 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<usize> {
+ type Output = Vec<usize>;
+
+ fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> {
+ 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<String> = 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<String> = Vec::new();
+ let result = special_flag!(args, "--help");
+ assert!(!result);
+ assert_eq!(args, Vec::<String>::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<String> = Vec::new();
+ let result = special_argument!(args, "--file");
+ assert_eq!(result, None);
+ assert_eq!(args, Vec::<String>::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::<String>::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::<String>::new());
+ assert_eq!(args, vec!["a", "b", "--list", "c", "d"]);
+
+ // Test extracting empty args
+ let mut args: Vec<String> = Vec::new();
+ let result = special_arguments!(args, "--list");
+ assert_eq!(result, Vec::<String>::new());
+ assert_eq!(args, Vec::<String>::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::<String>::new());
+ assert_eq!(args, Vec::<String>::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::<String>::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::<String>::new());
+ assert_eq!(args, vec!["-a", "-b", "--next", "1"]);
+ }
+}
+
impl<C, G> Program<C, G>
where
C: ProgramCollect,