zerolaunch_plugin_api/services/parameter/
template_parser.rs1use crate::services::parameter::types::SystemParameter;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum Placeholder {
12 Text(String),
14 UserArg,
16 System(SystemParameter),
18}
19
20pub struct TemplateParser;
24
25impl TemplateParser {
26 pub fn parse(template: &str) -> Vec<Placeholder> {
34 let mut placeholders = Vec::new();
35 let chars: Vec<char> = template.chars().collect();
36 let mut i = 0;
37 let mut text_start = 0;
38
39 while i < chars.len() {
40 if chars[i] == '{' {
41 if i > text_start {
43 let text: String = chars[text_start..i].iter().collect();
44 placeholders.push(Placeholder::Text(text));
45 }
46
47 if let Some(end) = Self::find_closing_brace(&chars, i) {
49 let content: String = chars[i + 1..end].iter().collect();
50
51 let placeholder = if content.is_empty() {
52 Placeholder::UserArg
54 } else if let Some(sys_param) = SystemParameter::from_name(&content) {
55 Placeholder::System(sys_param)
57 } else {
58 Placeholder::UserArg
60 };
61
62 placeholders.push(placeholder);
63 i = end + 1;
64 text_start = i;
65 continue;
66 }
67 }
68 i += 1;
69 }
70
71 if text_start < chars.len() {
73 let text: String = chars[text_start..].iter().collect();
74 placeholders.push(Placeholder::Text(text));
75 }
76
77 placeholders
78 }
79
80 fn find_closing_brace(chars: &[char], start: usize) -> Option<usize> {
82 ((start + 1)..chars.len()).find(|&i| chars[i] == '}')
83 }
84
85 pub fn count_user_args(template: &str) -> usize {
87 Self::parse(template)
88 .iter()
89 .filter(|p| matches!(p, Placeholder::UserArg))
90 .count()
91 }
92
93 pub fn has_system_params(template: &str) -> bool {
95 Self::parse(template)
96 .iter()
97 .any(|p| matches!(p, Placeholder::System(_)))
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn test_parse_empty_template() {
107 let placeholders = TemplateParser::parse("");
108 assert_eq!(placeholders.len(), 0);
109 }
110
111 #[test]
112 fn test_parse_no_parameters() {
113 let placeholders = TemplateParser::parse("notepad.exe test.txt");
114 assert_eq!(placeholders.len(), 1);
115 assert_eq!(
116 placeholders[0],
117 Placeholder::Text("notepad.exe test.txt".to_string())
118 );
119 }
120
121 #[test]
122 fn test_parse_positional_parameter() {
123 let placeholders = TemplateParser::parse("cmd /c echo {}");
124 assert_eq!(placeholders.len(), 2);
125 assert_eq!(
126 placeholders[0],
127 Placeholder::Text("cmd /c echo ".to_string())
128 );
129 assert_eq!(placeholders[1], Placeholder::UserArg);
130 }
131
132 #[test]
133 fn test_parse_multiple_positional() {
134 let placeholders = TemplateParser::parse("program {} {} {}");
135 assert_eq!(placeholders.len(), 6);
136 let user_args: Vec<_> = placeholders
137 .iter()
138 .filter(|p| matches!(p, Placeholder::UserArg))
139 .collect();
140 assert_eq!(user_args.len(), 3);
141 }
142
143 #[test]
144 fn test_parse_clipboard_parameter() {
145 let placeholders = TemplateParser::parse("notepad {clip}");
146 assert_eq!(placeholders.len(), 2);
147 assert_eq!(placeholders[0], Placeholder::Text("notepad ".to_string()));
148 assert_eq!(
149 placeholders[1],
150 Placeholder::System(SystemParameter::Clipboard)
151 );
152 }
153
154 #[test]
155 fn test_parse_hwnd_parameter() {
156 let placeholders = TemplateParser::parse("tool --hwnd {hwnd}");
157 assert_eq!(placeholders.len(), 2);
158 assert_eq!(
159 placeholders[1],
160 Placeholder::System(SystemParameter::WindowHandle)
161 );
162 }
163
164 #[test]
165 fn test_parse_selection_parameter() {
166 let placeholders = TemplateParser::parse("translate {selection}");
167 assert_eq!(placeholders.len(), 2);
168 assert_eq!(
169 placeholders[1],
170 Placeholder::System(SystemParameter::Selection)
171 );
172 }
173
174 #[test]
175 fn test_parse_mixed_parameters() {
176 let placeholders = TemplateParser::parse("program {} {clip} {} {hwnd}");
177 assert_eq!(placeholders.len(), 8);
178 }
179
180 #[test]
181 fn test_count_user_args() {
182 assert_eq!(
183 TemplateParser::count_user_args("program {} {clip} {} {hwnd}"),
184 2
185 );
186 assert_eq!(TemplateParser::count_user_args("program {clip} {hwnd}"), 0);
187 assert_eq!(TemplateParser::count_user_args("program {} {}"), 2);
188 assert_eq!(TemplateParser::count_user_args("program {selection}"), 0);
189 assert_eq!(
190 TemplateParser::count_user_args("program {} {selection} {}"),
191 2
192 );
193 }
194
195 #[test]
196 fn test_has_system_params() {
197 assert!(TemplateParser::has_system_params("program {clip}"));
198 assert!(TemplateParser::has_system_params("program {hwnd}"));
199 assert!(TemplateParser::has_system_params("program {selection}"));
200 assert!(TemplateParser::has_system_params("program {} {clip}"));
201 assert!(!TemplateParser::has_system_params("program {}"));
202 assert!(!TemplateParser::has_system_params("program"));
203 }
204
205 #[test]
206 fn test_parse_trailing_text() {
207 let placeholders = TemplateParser::parse("cmd /c echo {} --flag");
208 assert_eq!(placeholders.len(), 3);
209 assert_eq!(placeholders[2], Placeholder::Text(" --flag".to_string()));
210 }
211}