# comlexr `comlexr` is a Rust procedural macro crate designed to simplify command expression generation by using flexible syntax constructs. It allows you to dynamically build command-line instructions based on conditional statements, loops, pattern matching, closures, and more. ## Installation Add `comlexr` to your project's `Cargo.toml`: ```toml [dependencies] comlexr = "1.3.1" ``` ## MSRV The minimum supported Rust version is `1.60.0` for broader support. ## Usage ### Basic Command Construction Create simple command expressions using the `cmd!` macro. ```rust use comlexr::cmd; let command = cmd!("echo", "test"); assert_eq!(format!("{command:?}"), r#""echo" "test""#.to_string()); ``` ### Conditional Argument Inclusion Use `if` statements to conditionally include arguments. ```rust use comlexr::cmd; let single = true; let multi = false; let command = cmd!( "echo", "test", if single => "single", if multi => [ "multi", "arg", ], ); assert_eq!(format!("{command:?}"), r#""echo" "test" "single""#.to_string()); ``` ### Conditional Pattern Matching Use `if let` syntax to conditionally include arguments based on pattern matching. ```rust use comlexr::cmd; let single_option = Some("single"); let multi_option: Option<&str> = None; let command = cmd!( "echo", "test", if let Some(arg) = single_option => arg, if let Some(arg) = multi_option => [ "multi", arg, ], ); assert_eq!(format!("{command:?}"), r#""echo" "test" "single""#.to_string()); ``` ### Iterative Argument Inclusion Use the `for` syntax to iterate over collections and include multiple arguments. ```rust use comlexr::cmd; let iter = &["1", "2"]; let command = cmd!( "echo", "test", for iter, ); assert_eq!(format!("{command:?}"), r#""echo" "test" "1" "2""#.to_string()); ``` ### Iteration with `for in` Leverage the `for in` syntax to map collection elements to arguments dynamically. ```rust use comlexr::cmd; let single_iter = &["arg1", "arg2"]; let multi_iter = &["multi1", "multi2"]; let command = cmd!( "echo", "test", for arg in single_iter => arg, for arg in multi_iter => [ "multi", arg, ], ); assert_eq!(format!("{command:?}"), r#""echo" "test" "arg1" "arg2" "multi" "multi1" "multi" "multi2""#.to_string()); ``` ### Pattern Matching with `match` Dynamically choose arguments based on pattern matching. ```rust use comlexr::cmd; enum TestArgs { Arg1, Arg2, Arg3, } let match_arg = TestArgs::Arg2; let command = cmd!( "echo", "test", match match_arg { TestArgs::Arg1 => "arg1", TestArgs::Arg2 => ["arg1", "arg2"], TestArgs::Arg3 => ["arg1", "arg2", "arg3"], } ); assert_eq!(format!("{command:?}"), r#""echo" "test" "arg1" "arg2""#.to_string()); ``` ### Closures for Dynamic Argument Generation Generate arguments on the fly using closures. The closure must return a type that implements `IntoIterator`. ```rust use comlexr::cmd; let arr = vec![1, 2, 3]; let input = 2; let command = cmd!( "echo", "test", || arr.into_iter().map(|i| format!("{}", i * input)) ); assert_eq!(format!("{command:?}"), r#""echo" "test" "2" "4" "6""#.to_string()); ``` ### Set Current Directory Specify the directory to run the command. ```rust use comlexr::cmd; let command = cmd!( cd "~/"; "echo", "test", ); assert_eq!(format!("{command:?}"), r#"cd "~/" && "echo" "test""#); ``` ### Setting Environment Variables Set environment variables for the command. ```rust use comlexr::cmd; const NEW_VAR: &str = "NEW_VAR"; let command = cmd!( env { "TEST": "test", NEW_VAR: "new_var" }; "echo", "test", ); assert_eq!(format!("{command:?}"), r#"NEW_VAR="new_var" TEST="test" "echo" "test""#); ``` #### Current Directory and Env Variable Order Matters Environment variable declarations **MUST** come after the current directory declaration. ```rust use comlexr::cmd; let command = cmd!( cd "~/"; env { "TEST": "test", }; "echo", "test", ); assert_eq!( format!("{command:?}"), r#"cd "~/" && TEST="test" "echo" "test""# ); ``` ### Piping commands When using the `pipe` feature, you can make use of `pipe!` to chain the stdout of commands to stdin. Execution is lazy so commands aren't run until `status()` or `output()` is called. ```rust use comlexr::{pipe, cmd}; let dir = tempfile::tempdir().unwrap(); let file = dir.path().join("out"); let mut pipe = pipe!(cmd!("echo", "test") | cmd!("tee", &file)); let status = pipe.status().unwrap(); assert!(status.success()); ``` ### Sending variables to stdin You can also send data to the stdin of the first command in the chain. ```rust use comlexr::{pipe, cmd}; let mut pipe = pipe!(stdin = "test"; cmd!("sed", "s|e|oa|")); let output = pipe.output().unwrap(); assert!(output.status.success()); assert_eq!(String::from_utf8_lossy(&output.stdout), "toast"); ``` ## Features - Conditional expressions (`if`, `if let`) - Iteration constructs (`for`, `for in`) - Pattern matching (`match`) - Support for closures and dynamic expressions - Piping stdout from one command to the stdin of another ## Examples See the [tests](./tests/) directory for more examples on how to use `comlexr` effectively in your project. ## License This project is licensed under the [MIT License](./LICENSE).