use anyhow::Result;
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use parking_lot::RwLock;
use std::sync::{Arc, OnceLock};
#[derive(Debug, Clone)]
pub struct GeneratedRegion {
pub start_line: usize,
pub end_line: usize,
pub generator_tool: String,
pub allow_manual_edit: bool,
}
static CODE_REGIONS: OnceLock<Arc<RwLock<HashMap<PathBuf, Vec<GeneratedRegion>>>>> = OnceLock::new();
static FILE_OWNERSHIP: OnceLock<Arc<RwLock<HashMap<PathBuf, String>>>> = OnceLock::new();
fn get_regions() -> Arc<RwLock<HashMap<PathBuf, Vec<GeneratedRegion>>>> {
CODE_REGIONS.get_or_init(|| Arc::new(RwLock::new(HashMap::new()))).clone()
}
fn get_ownership() -> Arc<RwLock<HashMap<PathBuf, String>>> {
FILE_OWNERSHIP.get_or_init(|| Arc::new(RwLock::new(HashMap::new()))).clone()
}
pub fn mark_code_region_as_dx_generated(
file: &Path,
start_line: usize,
end_line: usize,
generator_tool: &str
) -> Result<()> {
let regions = get_regions();
let mut regions = regions.write();
let region = GeneratedRegion {
start_line,
end_line,
generator_tool: generator_tool.to_string(),
allow_manual_edit: false,
};
regions.entry(file.to_path_buf())
.or_insert_with(Vec::new)
.push(region);
tracing::debug!("🏷️ Marked lines {}-{} in {:?} as generated by {}",
start_line, end_line, file, generator_tool);
Ok(())
}
pub fn is_region_dx_generated(file: &Path, line: usize) -> Result<bool> {
let regions = get_regions();
let regions = regions.read();
if let Some(file_regions) = regions.get(file) {
Ok(file_regions.iter().any(|r| line >= r.start_line && line <= r.end_line))
} else {
Ok(false)
}
}
pub fn allow_safe_manual_edit_of_generated_code(file: &Path, line: usize) -> Result<()> {
let regions = get_regions();
let mut regions = regions.write();
if let Some(file_regions) = regions.get_mut(file) {
for region in file_regions {
if line >= region.start_line && line <= region.end_line {
region.allow_manual_edit = true;
tracing::info!("✏️ Allowed manual editing of generated region in {:?}", file);
return Ok(());
}
}
}
anyhow::bail!("No generated region found at line {} in {:?}", line, file)
}
pub fn claim_full_ownership_of_file(file: &Path, owner_tool: &str) -> Result<()> {
let ownership = get_ownership();
let mut ownership = ownership.write();
tracing::info!("🔒 Tool '{}' claimed ownership of {:?}", owner_tool, file);
ownership.insert(file.to_path_buf(), owner_tool.to_string());
Ok(())
}
pub fn release_ownership_of_file(file: &Path) -> Result<()> {
let ownership = get_ownership();
let mut ownership = ownership.write();
if ownership.remove(file).is_some() {
tracing::info!("🔓 Released ownership of {:?}", file);
}
Ok(())
}