1use templates_resolver::resolve_template_args;
2use thiserror::Error;
3use tokens::LexingError;
4
5use std::str::Split;
6
7use crate::cli::Cli;
8
9mod templates_resolver;
10mod tokens;
11
12#[derive(Debug, PartialEq, Eq)]
14enum ArgTemplatePart<'a> {
15 Index(usize),
17 IndexSplit(usize, &'a str),
19 IndexSplitIndex(usize, &'a str, usize),
21 SplitIndex(&'a str, usize),
23 Split(&'a str),
25 Empty,
27 FreeText(&'a str),
29}
30
31#[derive(Error, Debug)]
32pub enum ResolveError {
33 #[error("Index {0} is out of bounds")]
36 InvalidIndex(usize),
37 #[error("unknown data store error")]
38 Other,
39}
40
41pub fn resolve_cmd_args(stdin_entries: Vec<String>, cli: &Cli) -> Vec<Vec<String>> {
43 let mut entries = Vec::new();
44 let args_resolver = ArgumentResolver::new(&cli.args_templates).unwrap();
46
47 for stdin_entry in stdin_entries {
48 let input_args = stdin_entry
49 .split(&cli.args_separator)
50 .collect::<Vec<&str>>();
51 let entry = args_resolver.resolve(input_args).unwrap();
57 entries.push(entry);
58 }
59 entries
60}
61
62type ResolvedArgument<'a> = Vec<ArgTemplatePart<'a>>;
63
64struct ArgumentResolver<'a> {
65 resolved_args: Vec<ResolvedArgument<'a>>,
66 has_any_placeholder: bool,
67}
68
69impl<'a> ArgumentResolver<'a> {
70 fn new(arg_templates: &'a [String]) -> Result<ArgumentResolver<'a>, LexingError> {
71 let resolved_args = resolve_template_args(arg_templates)?;
72 let has_any_placeholder = resolved_args.iter().any(|arg_template| {
73 arg_template
74 .iter()
75 .any(|part| !matches!(part, ArgTemplatePart::FreeText(_)))
76 });
77 Ok(ArgumentResolver {
78 resolved_args,
79 has_any_placeholder,
80 })
81 }
82
83 fn resolve(&self, input_args: Vec<&str>) -> Result<Vec<String>, ResolveError> {
84 if !self.has_any_placeholder {
85 return Ok(input_args.into_iter().map(|a| a.to_string()).collect());
86 }
87 let mut result = Vec::new();
88 for arg_template in &self.resolved_args {
89 let mut resolved = self.resolve_arg_template(arg_template, &input_args)?;
90 result.append(&mut resolved);
91 }
92 Ok(result)
93 }
94
95 fn resolve_arg_template(
96 &self,
97 arg_template: &[ArgTemplatePart],
98 input_args: &[&str],
99 ) -> Result<Vec<String>, ResolveError> {
100 let mut resolved = Vec::new();
101 for part in arg_template {
102 let single_part = resolve_single_arg_part(part, input_args)?;
103 resolved = multiply_args_parts(resolved, single_part);
104 }
105 Ok(resolved)
106 }
107}
108
109fn resolve_single_arg_part(
110 arg_template: &ArgTemplatePart,
111 input_args: &[&str],
112) -> Result<Vec<String>, ResolveError> {
113 let resolved = match arg_template {
114 ArgTemplatePart::Index(idx) => vec![get_input_arg(*idx, input_args)?.to_string()],
115 ArgTemplatePart::IndexSplit(idx, split_by) => {
116 let input_arg = get_input_arg(*idx, input_args)?;
117 input_arg.split(*split_by).map(|s| s.to_string()).collect()
118 }
119 ArgTemplatePart::IndexSplitIndex(idx, split_by, split_idx) => {
120 let input_arg = get_input_arg(*idx, input_args)?;
121 let mut splitted = input_arg.split(*split_by);
122 vec![get_split_arg(*split_idx, &mut splitted)?.to_string()]
123 }
124 ArgTemplatePart::SplitIndex(split_by, split_idx) => input_args
125 .iter()
126 .map(|a| {
127 let mut splitted = a.split(*split_by);
128 get_split_arg(*split_idx, &mut splitted).map(|s| s.to_string())
129 })
130 .collect::<Result<Vec<String>, ResolveError>>()?,
131 ArgTemplatePart::Split(split_by) => input_args
132 .iter()
133 .map(|a| a.split(split_by).map(|s| s.to_string()))
134 .flat_map(|a| a.into_iter())
135 .collect::<Vec<String>>(),
136 ArgTemplatePart::Empty => input_args.iter().map(|a| a.to_string()).collect(),
137 ArgTemplatePart::FreeText(text) => vec![text.to_string()],
138 };
139 Ok(resolved)
140}
141
142fn get_input_arg<'a>(idx: usize, input_args: &'a [&'a str]) -> Result<&'a str, ResolveError> {
143 input_args
144 .get(idx)
145 .copied()
146 .ok_or(ResolveError::InvalidIndex(idx))
147}
148
149fn get_split_arg<'a>(
150 idx: usize,
151 splitted: &'a mut Split<&'a str>,
152) -> Result<&'a str, ResolveError> {
153 splitted.nth(idx).ok_or(ResolveError::InvalidIndex(idx))
154}
155
156fn multiply_args_parts(a: Vec<String>, b: Vec<String>) -> Vec<String> {
161 if a.is_empty() {
162 return b;
163 }
164 if b.is_empty() {
165 return a;
166 }
167 let mut result = Vec::with_capacity(a.len() * b.len());
168 for a_part in a {
169 for b_part in b.clone() {
170 result.push(format!("{}{}", a_part, b_part));
171 }
172 }
173
174 result
175}