Find and Replace #5
@ -26,11 +26,33 @@ impl TextEditor {
|
||||
};
|
||||
|
||||
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;
|
||||
while start < search_content.len() {
|
||||
let search_slice = if search_content.is_char_boundary(start) {
|
||||
&search_content[start..]
|
||||
} else {
|
||||
// Find next valid boundary
|
||||
while start < search_content.len() && !search_content.is_char_boundary(start) {
|
||||
start += 1;
|
||||
}
|
||||
if start >= search_content.len() {
|
||||
break;
|
||||
}
|
||||
&search_content[start..]
|
||||
};
|
||||
|
||||
if let Some(pos) = search_slice.find(&query) {
|
||||
let absolute_pos = start + pos;
|
||||
self.find_matches
|
||||
.push((absolute_pos, absolute_pos + query.len()));
|
||||
|
||||
// Advance to next valid character boundary instead of just +1
|
||||
start = absolute_pos + 1;
|
||||
while start < search_content.len() && !search_content.is_char_boundary(start) {
|
||||
start += 1;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !self.find_matches.is_empty() {
|
||||
@ -94,8 +116,8 @@ impl TextEditor {
|
||||
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 start_char = Self::safe_slice_to_pos(content, start_byte).chars().count();
|
||||
let end_char = Self::safe_slice_to_pos(content, end_byte).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) {
|
||||
@ -132,8 +154,7 @@ impl TextEditor {
|
||||
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())]
|
||||
let replacement_end_char = Self::safe_slice_to_pos(&active_tab.content, replacement_end)
|
||||
.chars()
|
||||
.count();
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ use super::editor::{TextEditor, TextProcessingResult};
|
||||
use eframe::egui;
|
||||
|
||||
impl TextEditor {
|
||||
fn safe_slice_to_pos(content: &str, pos: usize) -> &str {
|
||||
pub(crate) fn safe_slice_to_pos(content: &str, pos: usize) -> &str {
|
||||
let pos = pos.min(content.len());
|
||||
let mut boundary_pos = pos;
|
||||
while boundary_pos > 0 && !content.is_char_boundary(boundary_pos) {
|
||||
|
||||
@ -1,5 +1,15 @@
|
||||
use eframe::egui;
|
||||
|
||||
/// Safely get a string slice up to a byte position, ensuring UTF-8 boundaries
|
||||
fn safe_slice_to_pos(content: &str, pos: usize) -> &str {
|
||||
let pos = pos.min(content.len());
|
||||
let mut boundary_pos = pos;
|
||||
while boundary_pos > 0 && !content.is_char_boundary(boundary_pos) {
|
||||
boundary_pos -= 1;
|
||||
}
|
||||
&content[..boundary_pos]
|
||||
}
|
||||
|
||||
pub(super) fn draw_find_highlights(
|
||||
ui: &mut egui::Ui,
|
||||
content: &str,
|
||||
@ -44,7 +54,7 @@ fn draw_single_highlight(
|
||||
font_id: &egui::FontId,
|
||||
is_current_match: bool,
|
||||
) {
|
||||
let text_up_to_start = &content[..start_pos.min(content.len())];
|
||||
let text_up_to_start = safe_slice_to_pos(content, start_pos);
|
||||
let start_line = text_up_to_start.chars().filter(|&c| c == '\n').count();
|
||||
|
||||
if start_line >= galley.rows.len() {
|
||||
@ -52,8 +62,8 @@ fn draw_single_highlight(
|
||||
}
|
||||
|
||||
let line_start_byte_pos = text_up_to_start.rfind('\n').map(|pos| pos + 1).unwrap_or(0);
|
||||
let line_start_char_pos = content[..line_start_byte_pos].chars().count();
|
||||
let start_char_pos = content[..start_pos].chars().count();
|
||||
let line_start_char_pos = safe_slice_to_pos(content, line_start_byte_pos).chars().count();
|
||||
let start_char_pos = safe_slice_to_pos(content, start_pos).chars().count();
|
||||
let start_col = start_char_pos - line_start_char_pos;
|
||||
|
||||
let lines: Vec<&str> = content.lines().collect();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user