use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::path::PathBuf; pub fn compute_content_hash(content: &str, hasher: &mut DefaultHasher) -> u64 { content.hash(hasher); hasher.finish() } #[derive(Clone)] pub struct Tab { pub content: String, pub original_content_hash: u64, pub last_content_hash: u64, pub file_path: Option, pub is_modified: bool, pub title: String, pub hasher: DefaultHasher, } impl Tab { pub fn new_empty(tab_number: usize) -> Self { let content = String::new(); let mut hasher = DefaultHasher::new(); let hash = compute_content_hash(&content, &mut hasher); Self { original_content_hash: hash, last_content_hash: hash, content, file_path: None, is_modified: false, title: format!("new_{tab_number}"), hasher, } } pub fn new_with_file(content: String, file_path: PathBuf) -> Self { let title = file_path .file_name() .and_then(|n| n.to_str()) .unwrap_or("Untitled") .to_string(); let mut hasher = DefaultHasher::new(); let hash = compute_content_hash(&content, &mut hasher); Self { original_content_hash: hash, last_content_hash: hash, content, file_path: Some(file_path), is_modified: false, title, hasher, } } pub fn get_display_title(&self) -> String { let modified_indicator = if self.is_modified { "*" } else { "" }; format!("{}{}", self.title, modified_indicator) } pub fn update_modified_state(&mut self) { if self.title.starts_with("new_") { self.is_modified = !self.content.is_empty(); } else { let current_hash = compute_content_hash(&self.content, &mut self.hasher); self.is_modified = current_hash != self.last_content_hash; self.last_content_hash = current_hash; } } pub fn mark_as_saved(&mut self) { self.original_content_hash = compute_content_hash(&self.content, &mut self.hasher); self.last_content_hash = self.original_content_hash; self.is_modified = false; } }