diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-08-15 03:42:31 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-08-15 03:42:31 +0800 |
| commit | 57e20f69efea609d8332cc39d223f4aa46be3c78 (patch) | |
| tree | 42e0aa5435a9cb03bba49b4aa3838105f056bae2 /mingling_core/src | |
| parent | ec6c87d12062576271231b88364a4aa00765ae65 (diff) | |
feat(core): add public ArgumentSplitter utility
Move the REPL's argument splitting logic into a new public `utils`
module exposing the `ArgumentSplitter` trait for reuse by downstream
code.
Diffstat (limited to 'mingling_core/src')
| -rw-r--r-- | mingling_core/src/lib.rs | 3 | ||||
| -rw-r--r-- | mingling_core/src/program/repl_exec.rs | 6 | ||||
| -rw-r--r-- | mingling_core/src/utils.rs | 3 | ||||
| -rw-r--r-- | mingling_core/src/utils/splitter.rs (renamed from mingling_core/src/program/repl_exec/splitter.rs) | 78 |
4 files changed, 69 insertions, 21 deletions
diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs index 7048307..641118c 100644 --- a/mingling_core/src/lib.rs +++ b/mingling_core/src/lib.rs @@ -110,3 +110,6 @@ pub mod __private { /// Mingling's convention metadatas, which can be bound to types using `#[metadata]`, to provide identification for types pub mod metadata; + +/// Some common utilities in Mingling, providing a collection of functionality needed by many modules. +pub mod utils; diff --git a/mingling_core/src/program/repl_exec.rs b/mingling_core/src/program/repl_exec.rs index b91f7bc..2db5c5a 100644 --- a/mingling_core/src/program/repl_exec.rs +++ b/mingling_core/src/program/repl_exec.rs @@ -7,10 +7,8 @@ use std::io::Write; #[doc(hidden)] pub mod res; -mod splitter; - use crate::error::{ProgramInternalExecuteError, ProgramPanic}; -use crate::program::repl_exec::splitter::split_input_string; +use crate::utils::ArgumentSplitter; use crate::{Program, ProgramCollect, RenderResult}; use crate::{program::repl_exec::res::ResREPL, this}; @@ -58,7 +56,7 @@ where line: &mut readline, }); - let mut args = split_input_string(&readline); + let mut args = readline.split_args(); p.run_hook_repl_pre_exec(&crate::hook::HookREPLPreExecInfo { args: &args }); match might_be_async::invoke!(exec_once(p, &mut args)) { diff --git a/mingling_core/src/utils.rs b/mingling_core/src/utils.rs new file mode 100644 index 0000000..89fcd8f --- /dev/null +++ b/mingling_core/src/utils.rs @@ -0,0 +1,3 @@ +mod splitter; + +pub use splitter::ArgumentSplitter; diff --git a/mingling_core/src/program/repl_exec/splitter.rs b/mingling_core/src/utils/splitter.rs index 312ad73..6b2ea11 100644 --- a/mingling_core/src/program/repl_exec/splitter.rs +++ b/mingling_core/src/utils/splitter.rs @@ -1,12 +1,56 @@ -// Doc Not Optimize -/// Wraps `split_input` to work with owned `String` inputs. -pub fn split_input_string(input: &str) -> Vec<String> { - split_input(input) +/// A trait for splitting strings into arguments, respecting quotes and escapes. +/// +/// # Examples +/// +/// ``` +/// use mingling_core::utils::ArgumentSplitter; +/// +/// let args = "echo \"hello world\"".split_args(); +/// assert_eq!(args, vec!["echo", "hello world"]); +/// ``` +pub trait ArgumentSplitter { + /// Splits the input string into a vector of argument strings. + /// + /// # Examples + /// + /// ``` + /// use mingling_core::utils::ArgumentSplitter; + /// + /// let args = "a 'b c' d".split_args(); + /// assert_eq!(args, vec!["a", "b c", "d"]); + /// ``` + fn split_args(self) -> Vec<String>; +} + +impl<S: AsRef<str>> ArgumentSplitter for S { + /// Splits the string into arguments, respecting single quotes, double + /// quotes, and backslash escaping. + /// + /// # Examples + /// + /// ``` + /// use mingling_core::utils::ArgumentSplitter; + /// + /// let args = r#"cmd --flag "value with spaces""#.split_args(); + /// assert_eq!(args, vec!["cmd", "--flag", "value with spaces"]); + /// ``` + /// + /// Escaped characters are unescaped: + /// + /// ``` + /// use mingling_core::utils::ArgumentSplitter; + /// + /// let args = r#"echo a\ b"#.split_args(); + /// assert_eq!(args, vec!["echo", "a b"]); + /// ``` + fn split_args(self) -> Vec<String> { + split_args(self.as_ref()) + } } /// Splits a string input into arguments, respecting single quotes, double quotes, /// and backslash escaping. -pub fn split_input(input: &str) -> Vec<String> { +fn split_args(input: &str) -> Vec<String> { let mut result: Vec<String> = Vec::new(); let mut current = String::new(); let mut chars = input.chars(); @@ -63,72 +107,72 @@ pub fn split_input(input: &str) -> Vec<String> { #[cfg(test)] mod splitter_tests { - use crate::program::repl_exec::splitter::split_input; + use crate::utils::splitter::split_args; #[test] fn test_split_with_double_quotes() { let input = r#"a "b c" d"#; - let result = split_input(input); + let result = split_args(input); assert_eq!(result, vec!["a", "b c", "d"]); } #[test] fn test_split_with_single_quotes() { let input = "a 'b c' d"; - let result = split_input(input); + let result = split_args(input); assert_eq!(result, vec!["a", "b c", "d"]); } #[test] fn test_empty_input() { - assert!(split_input("").is_empty()); + assert!(split_args("").is_empty()); } #[test] fn test_no_quotes() { - let result = split_input("hello world"); + let result = split_args("hello world"); assert_eq!(result, vec!["hello", "world"]); } #[test] fn test_double_quotes_at_edges() { - let result = split_input(r#""hello world" foo"#); + let result = split_args(r#""hello world" foo"#); assert_eq!(result, vec!["hello world", "foo"]); } #[test] fn test_single_quotes_at_edges() { - let result = split_input("'hello world' foo"); + let result = split_args("'hello world' foo"); assert_eq!(result, vec!["hello world", "foo"]); } #[test] fn test_multiple_double_quoted_parts() { - let result = split_input(r#"a "b c" d "e f g""#); + let result = split_args(r#"a "b c" d "e f g""#); assert_eq!(result, vec!["a", "b c", "d", "e f g"]); } #[test] fn test_multiple_single_quoted_parts() { - let result = split_input("a 'b c' d 'e f g'"); + let result = split_args("a 'b c' d 'e f g'"); assert_eq!(result, vec!["a", "b c", "d", "e f g"]); } #[test] fn test_backslash_escaped_space() { - let result = split_input("a b\\ c d"); + let result = split_args("a b\\ c d"); assert_eq!(result, vec!["a", "b c", "d"]); } #[test] fn test_backslash_escaped_double_quote() { - let result = split_input(r#"a b\"c d"#); + let result = split_args(r#"a b\"c d"#); assert_eq!(result, vec!["a", r#"b"c"#, "d"]); } #[test] fn test_backslash_escaped_single_quote() { - let result = split_input("a b\\'c d"); + let result = split_args("a b\\'c d"); assert_eq!(result, vec!["a", "b'c", "d"]); } } |
