bctx_forge/intercept/
chain.rs1pub fn split_pipeline(cmd: &str) -> Vec<String> {
3 let mut parts = Vec::new();
4 let mut current = String::new();
5 let chars: Vec<char> = cmd.chars().collect();
6 let mut i = 0;
7
8 while i < chars.len() {
9 match chars[i] {
10 '&' if i + 1 < chars.len() && chars[i + 1] == '&' => {
11 let trimmed = current.trim().to_string();
12 if !trimmed.is_empty() {
13 parts.push(trimmed);
14 }
15 current.clear();
16 i += 2;
17 }
18 '|' if i + 1 < chars.len() && chars[i + 1] == '|' => {
19 let trimmed = current.trim().to_string();
20 if !trimmed.is_empty() {
21 parts.push(trimmed);
22 }
23 current.clear();
24 i += 2;
25 }
26 '|' | ';' => {
27 let trimmed = current.trim().to_string();
28 if !trimmed.is_empty() {
29 parts.push(trimmed);
30 }
31 current.clear();
32 i += 1;
33 }
34 c => {
35 current.push(c);
36 i += 1;
37 }
38 }
39 }
40
41 let trimmed = current.trim().to_string();
42 if !trimmed.is_empty() {
43 parts.push(trimmed);
44 }
45 parts
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn splits_and_chain() {
54 let parts = split_pipeline("git status && cargo test");
55 assert_eq!(parts, vec!["git status", "cargo test"]);
56 }
57
58 #[test]
59 fn splits_pipe() {
60 let parts = split_pipeline("cargo build | grep error");
61 assert_eq!(parts, vec!["cargo build", "grep error"]);
62 }
63}