use std::path::{Path, PathBuf}; pub fn apply_template( template: &str, name: &str, ext: &str, counter: u32, dimensions: Option<(u32, u32)>, ) -> String { let mut result = template.to_string(); result = result.replace("{name}", name); result = result.replace("{ext}", ext); // Handle {counter:N} with padding if let Some(start) = result.find("{counter:") { if let Some(end) = result[start..].find('}') { let spec = &result[start + 9..start + end]; if let Ok(padding) = spec.parse::() { let counter_str = format!("{:0>width$}", counter, width = padding); result = format!("{}{}{}", &result[..start], counter_str, &result[start + end + 1..]); } } } else { result = result.replace("{counter}", &counter.to_string()); } if let Some((w, h)) = dimensions { result = result.replace("{width}", &w.to_string()); result = result.replace("{height}", &h.to_string()); } result } pub fn resolve_collision(path: &Path) -> PathBuf { if !path.exists() { return path.to_path_buf(); } let parent = path.parent().unwrap_or(Path::new(".")); let stem = path .file_stem() .and_then(|s| s.to_str()) .unwrap_or("file"); let ext = path .extension() .and_then(|e| e.to_str()) .unwrap_or(""); for i in 1..1000 { let candidate = if ext.is_empty() { parent.join(format!("{}_{}", stem, i)) } else { parent.join(format!("{}_{}.{}", stem, i, ext)) }; if !candidate.exists() { return candidate; } } // Fallback - should never happen with 1000 attempts parent.join(format!("{}_{}.{}", stem, "overflow", ext)) }