use crate::services::parameter::types::SystemParameter;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Placeholder {
Text(String),
UserArg,
System(SystemParameter),
}
pub struct TemplateParser;
impl TemplateParser {
pub fn parse(template: &str) -> Vec<Placeholder> {
let mut placeholders = Vec::new();
let chars: Vec<char> = template.chars().collect();
let mut i = 0;
let mut text_start = 0;
while i < chars.len() {
if chars[i] == '{' {
if i > text_start {
let text: String = chars[text_start..i].iter().collect();
placeholders.push(Placeholder::Text(text));
}
if let Some(end) = Self::find_closing_brace(&chars, i) {
let content: String = chars[i + 1..end].iter().collect();
let placeholder = if content.is_empty() {
Placeholder::UserArg
} else if let Some(sys_param) = SystemParameter::from_name(&content) {
Placeholder::System(sys_param)
} else {
Placeholder::UserArg
};
placeholders.push(placeholder);
i = end + 1;
text_start = i;
continue;
}
}
i += 1;
}
if text_start < chars.len() {
let text: String = chars[text_start..].iter().collect();
placeholders.push(Placeholder::Text(text));
}
placeholders
}
fn find_closing_brace(chars: &[char], start: usize) -> Option<usize> {
((start + 1)..chars.len()).find(|&i| chars[i] == '}')
}
pub fn count_user_args(template: &str) -> usize {
Self::parse(template)
.iter()
.filter(|p| matches!(p, Placeholder::UserArg))
.count()
}
pub fn has_system_params(template: &str) -> bool {
Self::parse(template)
.iter()
.any(|p| matches!(p, Placeholder::System(_)))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_empty_template() {
let placeholders = TemplateParser::parse("");
assert_eq!(placeholders.len(), 0);
}
#[test]
fn test_parse_no_parameters() {
let placeholders = TemplateParser::parse("notepad.exe test.txt");
assert_eq!(placeholders.len(), 1);
assert_eq!(
placeholders[0],
Placeholder::Text("notepad.exe test.txt".to_string())
);
}
#[test]
fn test_parse_positional_parameter() {
let placeholders = TemplateParser::parse("cmd /c echo {}");
assert_eq!(placeholders.len(), 2);
assert_eq!(
placeholders[0],
Placeholder::Text("cmd /c echo ".to_string())
);
assert_eq!(placeholders[1], Placeholder::UserArg);
}
#[test]
fn test_parse_multiple_positional() {
let placeholders = TemplateParser::parse("program {} {} {}");
assert_eq!(placeholders.len(), 6);
let user_args: Vec<_> = placeholders
.iter()
.filter(|p| matches!(p, Placeholder::UserArg))
.collect();
assert_eq!(user_args.len(), 3);
}
#[test]
fn test_parse_clipboard_parameter() {
let placeholders = TemplateParser::parse("notepad {clip}");
assert_eq!(placeholders.len(), 2);
assert_eq!(placeholders[0], Placeholder::Text("notepad ".to_string()));
assert_eq!(
placeholders[1],
Placeholder::System(SystemParameter::Clipboard)
);
}
#[test]
fn test_parse_hwnd_parameter() {
let placeholders = TemplateParser::parse("tool --hwnd {hwnd}");
assert_eq!(placeholders.len(), 2);
assert_eq!(
placeholders[1],
Placeholder::System(SystemParameter::WindowHandle)
);
}
#[test]
fn test_parse_selection_parameter() {
let placeholders = TemplateParser::parse("translate {selection}");
assert_eq!(placeholders.len(), 2);
assert_eq!(
placeholders[1],
Placeholder::System(SystemParameter::Selection)
);
}
#[test]
fn test_parse_mixed_parameters() {
let placeholders = TemplateParser::parse("program {} {clip} {} {hwnd}");
assert_eq!(placeholders.len(), 8);
}
#[test]
fn test_count_user_args() {
assert_eq!(
TemplateParser::count_user_args("program {} {clip} {} {hwnd}"),
2
);
assert_eq!(TemplateParser::count_user_args("program {clip} {hwnd}"), 0);
assert_eq!(TemplateParser::count_user_args("program {} {}"), 2);
assert_eq!(TemplateParser::count_user_args("program {selection}"), 0);
assert_eq!(
TemplateParser::count_user_args("program {} {selection} {}"),
2
);
}
#[test]
fn test_has_system_params() {
assert!(TemplateParser::has_system_params("program {clip}"));
assert!(TemplateParser::has_system_params("program {hwnd}"));
assert!(TemplateParser::has_system_params("program {selection}"));
assert!(TemplateParser::has_system_params("program {} {clip}"));
assert!(!TemplateParser::has_system_params("program {}"));
assert!(!TemplateParser::has_system_params("program"));
}
#[test]
fn test_parse_trailing_text() {
let placeholders = TemplateParser::parse("cmd /c echo {} --flag");
assert_eq!(placeholders.len(), 3);
assert_eq!(placeholders[2], Placeholder::Text(" --flag".to_string()));
}
}