elif_codegen/
writer.rs

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}