1use anyhow::Result;
4use std::path::{Path, PathBuf};
5use std::collections::HashMap;
6use parking_lot::RwLock;
7use std::sync::{Arc, OnceLock};
8
9#[derive(Debug, Clone)]
10pub struct GeneratedRegion {
11 pub start_line: usize,
12 pub end_line: usize,
13 pub generator_tool: String,
14 pub allow_manual_edit: bool,
15}
16
17static CODE_REGIONS: OnceLock<Arc<RwLock<HashMap<PathBuf, Vec<GeneratedRegion>>>>> = OnceLock::new();
18static FILE_OWNERSHIP: OnceLock<Arc<RwLock<HashMap<PathBuf, String>>>> = OnceLock::new();
19
20fn get_regions() -> Arc<RwLock<HashMap<PathBuf, Vec<GeneratedRegion>>>> {
21 CODE_REGIONS.get_or_init(|| Arc::new(RwLock::new(HashMap::new()))).clone()
22}
23
24fn get_ownership() -> Arc<RwLock<HashMap<PathBuf, String>>> {
25 FILE_OWNERSHIP.get_or_init(|| Arc::new(RwLock::new(HashMap::new()))).clone()
26}
27
28pub fn mark_code_region_as_dx_generated(
29 file: &Path,
30 start_line: usize,
31 end_line: usize,
32 generator_tool: &str
33) -> Result<()> {
34 let regions = get_regions();
35 let mut regions = regions.write();
36
37 let region = GeneratedRegion {
38 start_line,
39 end_line,
40 generator_tool: generator_tool.to_string(),
41 allow_manual_edit: false,
42 };
43
44 regions.entry(file.to_path_buf())
45 .or_insert_with(Vec::new)
46 .push(region);
47
48 tracing::debug!("🏷️ Marked lines {}-{} in {:?} as generated by {}",
49 start_line, end_line, file, generator_tool);
50
51 Ok(())
52}
53
54pub fn is_region_dx_generated(file: &Path, line: usize) -> Result<bool> {
55 let regions = get_regions();
56 let regions = regions.read();
57
58 if let Some(file_regions) = regions.get(file) {
59 Ok(file_regions.iter().any(|r| line >= r.start_line && line <= r.end_line))
60 } else {
61 Ok(false)
62 }
63}
64
65pub fn allow_safe_manual_edit_of_generated_code(file: &Path, line: usize) -> Result<()> {
66 let regions = get_regions();
67 let mut regions = regions.write();
68
69 if let Some(file_regions) = regions.get_mut(file) {
70 for region in file_regions {
71 if line >= region.start_line && line <= region.end_line {
72 region.allow_manual_edit = true;
73 tracing::info!("✏️ Allowed manual editing of generated region in {:?}", file);
74 return Ok(());
75 }
76 }
77 }
78
79 anyhow::bail!("No generated region found at line {} in {:?}", line, file)
80}
81
82pub fn claim_full_ownership_of_file(file: &Path, owner_tool: &str) -> Result<()> {
83 let ownership = get_ownership();
84 let mut ownership = ownership.write();
85
86 tracing::info!("🔒 Tool '{}' claimed ownership of {:?}", owner_tool, file);
87 ownership.insert(file.to_path_buf(), owner_tool.to_string());
88
89 Ok(())
90}
91
92pub fn release_ownership_of_file(file: &Path) -> Result<()> {
93 let ownership = get_ownership();
94 let mut ownership = ownership.write();
95
96 if ownership.remove(file).is_some() {
97 tracing::info!("🔓 Released ownership of {:?}", file);
98 }
99
100 Ok(())
101}