same thing for find
This commit is contained in:
parent
48cfcb9997
commit
6fa0aa0b61
@ -26,11 +26,33 @@ impl TextEditor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut start = 0;
|
let mut start = 0;
|
||||||
while let Some(pos) = search_content[start..].find(&query) {
|
while start < search_content.len() {
|
||||||
let absolute_pos = start + pos;
|
let search_slice = if search_content.is_char_boundary(start) {
|
||||||
self.find_matches
|
&search_content[start..]
|
||||||
.push((absolute_pos, absolute_pos + query.len()));
|
} else {
|
||||||
start = absolute_pos + 1;
|
// 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() {
|
if !self.find_matches.is_empty() {
|
||||||
@ -94,8 +116,8 @@ impl TextEditor {
|
|||||||
if let Some(active_tab) = self.get_active_tab() {
|
if let Some(active_tab) = self.get_active_tab() {
|
||||||
let content = &active_tab.content;
|
let content = &active_tab.content;
|
||||||
|
|
||||||
let start_char = content[..start_byte.min(content.len())].chars().count();
|
let start_char = Self::safe_slice_to_pos(content, start_byte).chars().count();
|
||||||
let end_char = content[..end_byte.min(content.len())].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");
|
let text_edit_id = egui::Id::new("main_text_editor");
|
||||||
if let Some(mut state) = egui::TextEdit::load_state(ctx, text_edit_id) {
|
if let Some(mut state) = egui::TextEdit::load_state(ctx, text_edit_id) {
|
||||||
@ -132,8 +154,7 @@ impl TextEditor {
|
|||||||
self.update_find_matches();
|
self.update_find_matches();
|
||||||
|
|
||||||
if let Some(active_tab) = self.get_active_tab() {
|
if let Some(active_tab) = self.get_active_tab() {
|
||||||
let replacement_end_char = active_tab.content
|
let replacement_end_char = Self::safe_slice_to_pos(&active_tab.content, replacement_end)
|
||||||
[..replacement_end.min(active_tab.content.len())]
|
|
||||||
.chars()
|
.chars()
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use super::editor::{TextEditor, TextProcessingResult};
|
|||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
|
|
||||||
impl TextEditor {
|
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 pos = pos.min(content.len());
|
||||||
let mut boundary_pos = pos;
|
let mut boundary_pos = pos;
|
||||||
while boundary_pos > 0 && !content.is_char_boundary(boundary_pos) {
|
while boundary_pos > 0 && !content.is_char_boundary(boundary_pos) {
|
||||||
|
|||||||
@ -1,5 +1,15 @@
|
|||||||
use eframe::egui;
|
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(
|
pub(super) fn draw_find_highlights(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
content: &str,
|
content: &str,
|
||||||
@ -44,7 +54,7 @@ fn draw_single_highlight(
|
|||||||
font_id: &egui::FontId,
|
font_id: &egui::FontId,
|
||||||
is_current_match: bool,
|
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();
|
let start_line = text_up_to_start.chars().filter(|&c| c == '\n').count();
|
||||||
|
|
||||||
if start_line >= galley.rows.len() {
|
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_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 line_start_char_pos = safe_slice_to_pos(content, line_start_byte_pos).chars().count();
|
||||||
let start_char_pos = content[..start_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 start_col = start_char_pos - line_start_char_pos;
|
||||||
|
|
||||||
let lines: Vec<&str> = content.lines().collect();
|
let lines: Vec<&str> = content.lines().collect();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user