use super::editor::TextEditor; use eframe::egui; impl TextEditor { pub fn update_find_matches(&mut self) { let previous_match_index = self.current_match_index; self.find_matches.clear(); self.current_match_index = None; if self.find_query.is_empty() { return; } if let Some(tab) = self.get_active_tab() { let content = &tab.content; let query = if self.case_sensitive_search { self.find_query.clone() } else { self.find_query.to_lowercase() }; let search_content = if self.case_sensitive_search { content.clone() } else { content.to_lowercase() }; let mut start = 0; while let Some(pos) = search_content[start..].find(&query) { let absolute_pos = start + pos; self.find_matches .push((absolute_pos, absolute_pos + query.len())); start = absolute_pos + 1; } if !self.find_matches.is_empty() { if let Some(prev_index) = previous_match_index { if prev_index < self.find_matches.len() { self.current_match_index = Some(prev_index); } else { self.current_match_index = Some(0); } } else { self.current_match_index = Some(0); } } } } pub fn find_next(&mut self, ctx: &egui::Context) { if self.find_matches.is_empty() { return; } if let Some(current) = self.current_match_index { self.current_match_index = Some((current + 1) % self.find_matches.len()); } else { self.current_match_index = Some(0); } self.select_current_match(ctx); self.should_select_current_match = true; } pub fn find_previous(&mut self, ctx: &egui::Context) { if self.find_matches.is_empty() { return; } if let Some(current) = self.current_match_index { self.current_match_index = Some(if current == 0 { self.find_matches.len() - 1 } else { current - 1 }); } else { self.current_match_index = Some(0); } self.select_current_match(ctx); self.should_select_current_match = true; } pub fn get_current_match_position(&self) -> Option<(usize, usize)> { if let Some(index) = self.current_match_index { self.find_matches.get(index).copied() } else { None } } pub fn select_current_match(&self, ctx: &egui::Context) { if let Some((start_byte, end_byte)) = self.get_current_match_position() { if let Some(active_tab) = self.get_active_tab() { let content = &active_tab.content; let start_char = content[..start_byte.min(content.len())].chars().count(); let end_char = content[..end_byte.min(content.len())].chars().count(); let text_edit_id = egui::Id::new("main_text_editor"); if let Some(mut state) = egui::TextEdit::load_state(ctx, text_edit_id) { let selection_range = egui::text::CCursorRange::two( egui::text::CCursor::new(start_char), egui::text::CCursor::new(end_char), ); state.cursor.set_char_range(Some(selection_range)); egui::TextEdit::store_state(ctx, text_edit_id, state); } } } } pub fn replace_current_match(&mut self, ctx: &egui::Context) { if self.find_query.is_empty() || self.find_matches.is_empty() { return; } if let Some((start_byte, end_byte)) = self.get_current_match_position() { let replace_query = self.replace_query.clone(); let replacement_end = start_byte + replace_query.len(); if let Some(active_tab) = self.get_active_tab_mut() { let content = &active_tab.content; let mut new_content = content.clone(); new_content.replace_range(start_byte..end_byte, &replace_query); active_tab.content = new_content; active_tab.is_modified = true; } self.update_find_matches(); if let Some(active_tab) = self.get_active_tab() { let replacement_end_char = active_tab.content [..replacement_end.min(active_tab.content.len())] .chars() .count(); let text_edit_id = egui::Id::new("main_text_editor"); if let Some(mut state) = egui::TextEdit::load_state(ctx, text_edit_id) { state .cursor .set_char_range(Some(egui::text::CCursorRange::one( egui::text::CCursor::new(replacement_end_char), ))); egui::TextEdit::store_state(ctx, text_edit_id, state); } } } } pub fn replace_all(&mut self, ctx: &egui::Context) { if self.find_query.is_empty() || self.find_matches.is_empty() { return; } let find_query = self.find_query.clone(); let replace_query = self.replace_query.clone(); let case_sensitive = self.case_sensitive_search; let find_matches = self.find_matches.clone(); if let Some(active_tab) = self.get_active_tab_mut() { let content = &active_tab.content; let new_content = if case_sensitive { content.replace(&find_query, &replace_query) } else { let mut result = String::new(); let mut last_end = 0; for (start_byte, end_byte) in &find_matches { result.push_str(&content[last_end..*start_byte]); result.push_str(&replace_query); last_end = *end_byte; } result.push_str(&content[last_end..]); result }; active_tab.content = new_content; active_tab.is_modified = true; } self.update_find_matches(); self.current_match_index = None; let text_edit_id = egui::Id::new("main_text_editor"); if let Some(mut state) = egui::TextEdit::load_state(ctx, text_edit_id) { state .cursor .set_char_range(Some(egui::text::CCursorRange::one( egui::text::CCursor::new(0), ))); egui::TextEdit::store_state(ctx, text_edit_id, state); } } }