diff --git a/src/app/state/processing.rs b/src/app/state/processing.rs index b716553..09cfff7 100644 --- a/src/app/state/processing.rs +++ b/src/app/state/processing.rs @@ -2,6 +2,15 @@ use super::editor::{TextEditor, TextProcessingResult}; use eframe::egui; impl TextEditor { + 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 fn process_text_for_rendering(&mut self, content: &str, ui: &egui::Ui) { let line_count = content.bytes().filter(|&b| b == b'\n').count() + 1; @@ -119,12 +128,12 @@ impl TextEditor { old_cursor_pos: usize, new_cursor_pos: usize, ) -> isize { - let old_newlines = old_content[..old_cursor_pos.min(old_content.len())] + let old_newlines = Self::safe_slice_to_pos(old_content, old_cursor_pos) .bytes() .filter(|&b| b == b'\n') .count(); - let new_newlines = new_content[..new_cursor_pos.min(new_content.len())] + let new_newlines = Self::safe_slice_to_pos(new_content, new_cursor_pos) .bytes() .filter(|&b| b == b'\n') .count(); @@ -190,11 +199,11 @@ impl TextEditor { let mut current_result = self.get_text_processing_result(); current_result.line_count += newlines_added; - let addition_start_line = old_content[..added_start] + let addition_start_line = Self::safe_slice_to_pos(old_content, added_start) .bytes() .filter(|&b| b == b'\n') .count(); - let addition_end_line = old_content[..added_end.min(old_content.len())] + let addition_end_line = Self::safe_slice_to_pos(old_content, added_end) .bytes() .filter(|&b| b == b'\n') .count(); @@ -261,11 +270,11 @@ impl TextEditor { let mut current_result = self.get_text_processing_result(); current_result.line_count = current_result.line_count.saturating_sub(newlines_removed); - let removal_start_line = old_content[..removed_start] + let removal_start_line = Self::safe_slice_to_pos(old_content, removed_start) .bytes() .filter(|&b| b == b'\n') .count(); - let removal_end_line = old_content[..removed_end] + let removal_end_line = Self::safe_slice_to_pos(old_content, removed_end) .bytes() .filter(|&b| b == b'\n') .count(); @@ -304,18 +313,26 @@ impl TextEditor { fn extract_current_line(&self, content: &str, cursor_pos: usize) -> String { let bytes = content.as_bytes(); + let safe_cursor_pos = cursor_pos.min(bytes.len()); - let mut line_start = cursor_pos; + let mut line_start = safe_cursor_pos; while line_start > 0 && bytes[line_start - 1] != b'\n' { line_start -= 1; } - let mut line_end = cursor_pos; + let mut line_end = safe_cursor_pos; while line_end < bytes.len() && bytes[line_end] != b'\n' { line_end += 1; } - content[line_start..line_end].to_string() + let line_start_boundary = line_start; + let line_end_boundary = line_end; + + if content.is_char_boundary(line_start_boundary) && content.is_char_boundary(line_end_boundary) { + content[line_start_boundary..line_end_boundary].to_string() + } else { + Self::safe_slice_to_pos(content, line_end_boundary)[line_start_boundary..].to_string() + } } fn update_line_if_longer(