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