1use elif_core::ElifError;
2use std::path::Path;
3use std::fs;
4
5pub struct CodeWriter;
6
7impl CodeWriter {
8 pub fn new() -> Self {
9 Self
10 }
11
12 pub fn write_if_changed(&self, path: &Path, content: &str) -> Result<(), ElifError> {
13 if let Some(parent) = path.parent() {
14 fs::create_dir_all(parent)?;
15 }
16
17 if path.exists() {
18 let existing = fs::read_to_string(path)?;
19 if existing == content {
20 return Ok(());
21 }
22 }
23
24 fs::write(path, content)?;
25 Ok(())
26 }
27
28 pub fn write_preserving_markers(&self, path: &Path, new_content: &str) -> Result<(), ElifError> {
29 if let Some(parent) = path.parent() {
30 fs::create_dir_all(parent)?;
31 }
32
33 if !path.exists() {
34 fs::write(path, new_content)?;
35 return Ok(());
36 }
37
38 let existing = fs::read_to_string(path)?;
39 let merged = self.merge_with_markers(&existing, new_content)?;
40
41 if merged != existing {
42 fs::write(path, merged)?;
43 }
44
45 Ok(())
46 }
47
48 fn merge_with_markers(&self, existing: &str, new_content: &str) -> Result<String, ElifError> {
49 let marker_regex = regex::Regex::new(
50 r"// <<<ELIF:BEGIN agent-editable:([^>]+)>>>(.*?)// <<<ELIF:END agent-editable:[^>]+>>>"
51 ).map_err(|e| ElifError::Template { message: format!("Regex error: {}", e) })?;
52
53 let mut markers = std::collections::HashMap::new();
54
55 for cap in marker_regex.captures_iter(existing) {
56 let id = cap.get(1).unwrap().as_str();
57 let content = cap.get(2).unwrap().as_str();
58 markers.insert(id, content);
59 }
60
61 let mut result = new_content.to_string();
62
63 for (id, content) in markers {
64 let begin_marker = format!("// <<<ELIF:BEGIN agent-editable:{}>>>", id);
65 let end_marker = format!("// <<<ELIF:END agent-editable:{}>>>", id);
66
67 if let Some(start) = result.find(&begin_marker) {
68 if let Some(end_start) = result.find(&end_marker) {
69 let before = &result[..start + begin_marker.len()];
70 let after = &result[end_start..];
71 result = format!("{}{}{}", before, content, after);
72 }
73 }
74 }
75
76 Ok(result)
77 }
78}
79
80impl Default for CodeWriter {
81 fn default() -> Self {
82 Self::new()
83 }
84}