Find and Replace #5

Merged
candle merged 9 commits from master into release 2025-07-16 21:36:23 +00:00
13 changed files with 59 additions and 77 deletions
Showing only changes of commit 1edf0995c0 - Show all commits

View File

@ -149,7 +149,7 @@ fn get_shortcuts() -> Vec<ShortcutDefinition> {
] ]
} }
fn execute_action(action: ShortcutAction, editor: &mut TextEditor, _ctx: &egui::Context) -> bool { fn execute_action(action: ShortcutAction, editor: &mut TextEditor, ctx: &egui::Context) -> bool {
match action { match action {
ShortcutAction::NewFile => { ShortcutAction::NewFile => {
io::new_file(editor); io::new_file(editor);

View File

@ -57,7 +57,7 @@ impl TextEditor {
cc.egui_ctx.options_mut(|o| o.zoom_with_keyboard = false); cc.egui_ctx.options_mut(|o| o.zoom_with_keyboard = false);
let mut style = (*cc.egui_ctx.style()).clone(); let mut style = (*cc.egui_ctx.style()).to_owned();
style style
.text_styles .text_styles
.insert(egui::TextStyle::Body, egui::FontId::proportional(16.0)); .insert(egui::TextStyle::Body, egui::FontId::proportional(16.0));
@ -85,7 +85,7 @@ impl TextEditor {
word_wrap: self.word_wrap, word_wrap: self.word_wrap,
theme: self.theme, theme: self.theme,
line_side: self.line_side, line_side: self.line_side,
font_family: self.font_family.clone(), font_family: self.font_family.to_string(),
font_size: self.font_size, font_size: self.font_size,
// vim_mode: self.vim_mode, // vim_mode: self.vim_mode,
} }

View File

@ -14,13 +14,13 @@ impl TextEditor {
if let Some(tab) = self.get_active_tab() { if let Some(tab) = self.get_active_tab() {
let content = &tab.content; let content = &tab.content;
let query = if self.case_sensitive_search { let query = if self.case_sensitive_search {
self.find_query.clone() self.find_query.to_owned()
} else { } else {
self.find_query.to_lowercase() self.find_query.to_lowercase()
}; };
let search_content = if self.case_sensitive_search { let search_content = if self.case_sensitive_search {
content.clone() content.to_string()
} else { } else {
content.to_lowercase() content.to_lowercase()
}; };
@ -138,13 +138,13 @@ impl TextEditor {
} }
if let Some((start_byte, end_byte)) = self.get_current_match_position() { if let Some((start_byte, end_byte)) = self.get_current_match_position() {
let replace_query = self.replace_query.clone(); let replace_query = self.replace_query.to_owned();
let replacement_end = start_byte + replace_query.len(); let replacement_end = start_byte + replace_query.len();
if let Some(active_tab) = self.get_active_tab_mut() { if let Some(active_tab) = self.get_active_tab_mut() {
let content = &active_tab.content; let content = &active_tab.content;
let mut new_content = content.clone(); let mut new_content = content.to_string();
new_content.replace_range(start_byte..end_byte, &replace_query); new_content.replace_range(start_byte..end_byte, &replace_query);
active_tab.content = new_content; active_tab.content = new_content;
@ -176,10 +176,10 @@ impl TextEditor {
return; return;
} }
let find_query = self.find_query.clone(); let find_query = self.find_query.to_owned();
let replace_query = self.replace_query.clone(); let replace_query = self.replace_query.to_owned();
let case_sensitive = self.case_sensitive_search; let case_sensitive = self.case_sensitive_search;
let find_matches = self.find_matches.clone(); let find_matches = self.find_matches.to_owned();
if let Some(active_tab) = self.get_active_tab_mut() { if let Some(active_tab) = self.get_active_tab_mut() {
let content = &active_tab.content; let content = &active_tab.content;

View File

@ -10,7 +10,7 @@ impl TextEditor {
self.tabs self.tabs
.iter() .iter()
.filter(|tab| tab.is_modified) .filter(|tab| tab.is_modified)
.map(|tab| tab.title.clone()) .map(|tab| tab.title.to_owned())
.collect() .collect()
} }
@ -40,19 +40,19 @@ impl TextEditor {
"Unsaved Changes".to_string(), "Unsaved Changes".to_string(),
"You have unsaved changes.".to_string(), "You have unsaved changes.".to_string(),
"Quit Without Saving".to_string(), "Quit Without Saving".to_string(),
action.clone(), action.to_owned(),
), ),
UnsavedAction::CloseTab(tab_index) => { UnsavedAction::CloseTab(tab_index) => {
let file_name = self let file_name = self
.tabs .tabs
.get(*tab_index) .get(*tab_index)
.map_or_else(|| "unknown file".to_string(), |tab| tab.title.clone()); .map_or_else(|| "unknown file".to_string(), |tab| tab.title.to_owned());
( (
vec![file_name], vec![file_name],
"Unsaved Changes".to_string(), "Unsaved Changes".to_string(),
"The file has unsaved changes.".to_string(), "The file has unsaved changes.".to_string(),
"Close Without Saving".to_string(), "Close Without Saving".to_string(),
action.clone(), action.to_owned(),
) )
} }
} }

View File

@ -171,7 +171,6 @@ impl TextEditor {
let min_len = old_content.len().min(new_content.len()); let min_len = old_content.len().min(new_content.len());
let mut common_prefix = 0; let mut common_prefix = 0;
let mut common_suffix = 0; let mut common_suffix = 0;
for i in 0..min_len { for i in 0..min_len {
if old_content.as_bytes()[i] == new_content.as_bytes()[i] { if old_content.as_bytes()[i] == new_content.as_bytes()[i] {
common_prefix += 1; common_prefix += 1;
@ -221,7 +220,6 @@ impl TextEditor {
} else { } else {
let current_line = self.extract_current_line(new_content, new_cursor_pos); let current_line = self.extract_current_line(new_content, new_cursor_pos);
let current_line_length = current_line.chars().count(); let current_line_length = current_line.chars().count();
self.update_line_if_longer( self.update_line_if_longer(
self.current_cursor_line, self.current_cursor_line,
&current_line, &current_line,
@ -372,7 +370,7 @@ impl TextEditor {
pub fn get_text_processing_result(&self) -> TextProcessingResult { pub fn get_text_processing_result(&self) -> TextProcessingResult {
self.text_processing_result self.text_processing_result
.lock() .lock()
.map(|result| result.clone()) .map(|result| result.to_owned())
.unwrap_or_default() .unwrap_or_default()
} }

View File

@ -17,6 +17,7 @@ impl TextEditor {
if self.show_find && !self.find_query.is_empty() { if self.show_find && !self.find_query.is_empty() {
self.update_find_matches(); self.update_find_matches();
} }
self.text_needs_processing = true;
} }
pub fn close_tab(&mut self, tab_index: usize) { pub fn close_tab(&mut self, tab_index: usize) {
@ -30,6 +31,7 @@ impl TextEditor {
if self.show_find && !self.find_query.is_empty() { if self.show_find && !self.find_query.is_empty() {
self.update_find_matches(); self.update_find_matches();
} }
self.text_needs_processing = true;
} }
} }
@ -39,6 +41,7 @@ impl TextEditor {
if self.show_find && !self.find_query.is_empty() { if self.show_find && !self.find_query.is_empty() {
self.update_find_matches(); self.update_find_matches();
} }
self.text_needs_processing = true;
} }
} }
} }

View File

@ -45,7 +45,7 @@ impl TextEditor {
_ => egui::FontFamily::Proportional, _ => egui::FontFamily::Proportional,
}; };
let mut style = (*ctx.style()).clone(); let mut style = (*ctx.style()).to_owned();
style.text_styles.insert( style.text_styles.insert(
egui::TextStyle::Monospace, egui::TextStyle::Monospace,
egui::FontId::new(self.font_size, font_family), egui::FontId::new(self.font_size, font_family),
@ -66,10 +66,7 @@ impl TextEditor {
/// Trigger immediate text reprocessing when font settings change /// Trigger immediate text reprocessing when font settings change
pub fn reprocess_text_for_font_change(&mut self, ui: &egui::Ui) { pub fn reprocess_text_for_font_change(&mut self, ui: &egui::Ui) {
if let Some(active_tab) = self.get_active_tab() { if let Some(active_tab) = self.get_active_tab() {
let content = active_tab.content.clone(); self.process_text_for_rendering(&active_tab.content.to_string(), ui);
if !content.is_empty() {
self.process_text_for_rendering(&content, ui);
}
} }
} }

View File

@ -24,13 +24,10 @@ pub(crate) fn open_file(app: &mut TextEditor) {
if should_replace_current_tab { if should_replace_current_tab {
if let Some(active_tab) = app.get_active_tab_mut() { if let Some(active_tab) = app.get_active_tab_mut() {
let title = path.file_name().and_then(|n| n.to_str()).unwrap_or("Untitled");
active_tab.content = content; active_tab.content = content;
active_tab.file_path = Some(path.clone()); active_tab.file_path = Some(path.to_path_buf());
active_tab.title = path active_tab.title = title.to_string();
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("Untitled")
.to_string();
active_tab.mark_as_saved(); active_tab.mark_as_saved();
} }
app.text_needs_processing = true; app.text_needs_processing = true;
@ -54,7 +51,7 @@ pub(crate) fn open_file(app: &mut TextEditor) {
pub(crate) fn save_file(app: &mut TextEditor) { pub(crate) fn save_file(app: &mut TextEditor) {
if let Some(active_tab) = app.get_active_tab() { if let Some(active_tab) = app.get_active_tab() {
if let Some(path) = &active_tab.file_path { if let Some(path) = &active_tab.file_path {
save_to_path(app, path.clone()); save_to_path(app, path.to_path_buf());
} else { } else {
save_as_file(app); save_as_file(app);
} }
@ -74,12 +71,9 @@ pub(crate) fn save_to_path(app: &mut TextEditor, path: PathBuf) {
if let Some(active_tab) = app.get_active_tab_mut() { if let Some(active_tab) = app.get_active_tab_mut() {
match fs::write(&path, &active_tab.content) { match fs::write(&path, &active_tab.content) {
Ok(()) => { Ok(()) => {
active_tab.file_path = Some(path.clone()); let title = path.file_name().and_then(|n| n.to_str()).unwrap_or("Untitled");
active_tab.title = path active_tab.file_path = Some(path.to_path_buf());
.file_name() active_tab.title = title.to_string();
.and_then(|n| n.to_str())
.unwrap_or("Untitled")
.to_string();
active_tab.mark_as_saved(); active_tab.mark_as_saved();
} }
Err(err) => { Err(err) => {

View File

@ -35,8 +35,8 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R
let find_data = if show_find && !app.find_matches.is_empty() { let find_data = if show_find && !app.find_matches.is_empty() {
app.get_active_tab().map(|tab| { app.get_active_tab().map(|tab| {
( (
tab.content.clone(), tab.content.to_owned(),
app.find_matches.clone(), app.find_matches.to_owned(),
app.current_match_index, app.current_match_index,
) )
}) })
@ -58,7 +58,7 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R
.text_styles .text_styles
.get(&egui::TextStyle::Monospace) .get(&egui::TextStyle::Monospace)
.unwrap_or(&egui::FontId::monospace(font_size)) .unwrap_or(&egui::FontId::monospace(font_size))
.clone(); .to_owned();
let desired_width = if word_wrap { let desired_width = if word_wrap {
ui.available_width() ui.available_width()
@ -68,8 +68,8 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R
let temp_galley = ui.fonts(|fonts| { let temp_galley = ui.fonts(|fonts| {
fonts.layout( fonts.layout(
content.clone(), content.to_owned(),
font_id.clone(), font_id.to_owned(),
ui.visuals().text_color(), ui.visuals().text_color(),
desired_width, desired_width,
) )
@ -125,7 +125,7 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R
let content_changed = output.response.changed(); let content_changed = output.response.changed();
let content_for_processing = if content_changed { let content_for_processing = if content_changed {
active_tab.update_modified_state(); active_tab.update_modified_state();
Some(active_tab.content.clone()) Some(active_tab.content.to_owned())
} else { } else {
None None
}; };
@ -141,7 +141,7 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R
.map(|range| range.primary.index); .map(|range| range.primary.index);
if let Some(content) = content_for_processing { if let Some(content) = content_for_processing {
let previous_content = app.previous_content.clone(); let previous_content = app.previous_content.to_owned();
let previous_cursor_pos = app.previous_cursor_char_index; let previous_cursor_pos = app.previous_cursor_char_index;
if !previous_content.is_empty() { if !previous_content.is_empty() {
@ -160,7 +160,7 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R
app.process_text_for_rendering(&content, ui); app.process_text_for_rendering(&content, ui);
} }
app.previous_content = content.clone(); app.previous_content = content.to_owned();
app.previous_cursor_char_index = current_cursor_pos; app.previous_cursor_char_index = current_cursor_pos;
if let Some(active_tab) = app.get_active_tab_mut() { if let Some(active_tab) = app.get_active_tab_mut() {
@ -169,21 +169,12 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R
} }
} }
if app.font_settings_changed { if app.font_settings_changed || app.text_needs_processing {
if let Some(active_tab) = app.get_active_tab() { if let Some(active_tab) = app.get_active_tab() {
let content = active_tab.content.clone(); let content = active_tab.content.to_owned();
if !content.is_empty() {
app.process_text_for_rendering(&content, ui);
}
}
app.font_settings_changed = false;
}
if app.text_needs_processing {
if let Some(active_tab) = app.get_active_tab() {
let content = active_tab.content.clone();
app.process_text_for_rendering(&content, ui); app.process_text_for_rendering(&content, ui);
} }
app.font_settings_changed = false;
app.text_needs_processing = false; app.text_needs_processing = false;
} }
@ -206,7 +197,7 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R
.text_styles .text_styles
.get(&egui::TextStyle::Monospace) .get(&egui::TextStyle::Monospace)
.unwrap_or(&egui::FontId::monospace(font_size)) .unwrap_or(&egui::FontId::monospace(font_size))
.clone(); .to_owned();
let line_height = ui.fonts(|fonts| fonts.row_height(&font_id)); let line_height = ui.fonts(|fonts| fonts.row_height(&font_id));
let y_pos = output.response.rect.top() + (cursor_line as f32 * line_height); let y_pos = output.response.rect.top() + (cursor_line as f32 * line_height);
@ -221,7 +212,6 @@ pub(super) fn editor_view_ui(ui: &mut egui::Ui, app: &mut TextEditor) -> egui::R
} }
} }
} }
app.previous_cursor_position = Some(cursor_pos); app.previous_cursor_position = Some(cursor_pos);
} }
} }

View File

@ -25,7 +25,7 @@ pub(super) fn draw_find_highlights(
.text_styles .text_styles
.get(&egui::TextStyle::Monospace) .get(&egui::TextStyle::Monospace)
.unwrap_or(&egui::FontId::monospace(font_size)) .unwrap_or(&egui::FontId::monospace(font_size))
.clone(); .to_owned();
for (match_index, &(start_pos, end_pos)) in matches.iter().enumerate() { for (match_index, &(start_pos, end_pos)) in matches.iter().enumerate() {
let is_current_match = current_match_index == Some(match_index); let is_current_match = current_match_index == Some(match_index);
@ -78,7 +78,7 @@ fn draw_single_highlight(
fonts fonts
.layout( .layout(
text_before_match, text_before_match,
font_id.clone(), font_id.to_owned(),
egui::Color32::WHITE, egui::Color32::WHITE,
f32::INFINITY, f32::INFINITY,
) )
@ -96,7 +96,7 @@ fn draw_single_highlight(
fonts fonts
.layout( .layout(
match_text.to_string(), match_text.to_string(),
font_id.clone(), font_id.to_owned(),
ui.visuals().text_color(), ui.visuals().text_color(),
f32::INFINITY, f32::INFINITY,
) )

View File

@ -29,7 +29,7 @@ pub(super) fn get_visual_line_mapping(
cache cache
.borrow() .borrow()
.as_ref() .as_ref()
.map(|(_, _, mapping)| mapping.clone()) .map(|(_, _, mapping)| mapping.to_owned())
.unwrap_or_default() .unwrap_or_default()
}) })
} }
@ -52,7 +52,7 @@ fn calculate_visual_line_mapping(
let galley = ui.fonts(|fonts| { let galley = ui.fonts(|fonts| {
fonts.layout( fonts.layout(
line.to_string(), line.to_string(),
font_id.clone(), font_id.to_owned(),
egui::Color32::WHITE, egui::Color32::WHITE,
available_width, available_width,
) )
@ -100,7 +100,7 @@ pub(super) fn render_line_numbers(
}; };
ui.label( ui.label(
egui::RichText::new(text) egui::RichText::new(text)
.font(font_id.clone()) .font(font_id.to_owned())
.color(text_color), .color(text_color),
); );
} }
@ -109,7 +109,7 @@ pub(super) fn render_line_numbers(
let text = format!("{:>width$}", i, width = line_count_width); let text = format!("{:>width$}", i, width = line_count_width);
ui.label( ui.label(
egui::RichText::new(text) egui::RichText::new(text)
.font(font_id.clone()) .font(font_id.to_owned())
.color(text_color), .color(text_color),
); );
} }

View File

@ -128,13 +128,13 @@ pub(crate) fn menu_bar(app: &mut TextEditor, ctx: &egui::Context) {
if let Some(active_tab) = app.get_active_tab_mut() { if let Some(active_tab) = app.get_active_tab_mut() {
let current_state = ( let current_state = (
state.cursor.char_range().unwrap_or_default(), state.cursor.char_range().unwrap_or_default(),
active_tab.content.clone(), active_tab.content.to_string(),
); );
let mut undoer = state.undoer(); let mut undoer = state.undoer();
if let Some((cursor_range, content)) = if let Some((cursor_range, content)) =
undoer.undo(&current_state) undoer.undo(&current_state)
{ {
active_tab.content = content.clone(); active_tab.content = content.to_string();
state.cursor.set_char_range(Some(*cursor_range)); state.cursor.set_char_range(Some(*cursor_range));
state.set_undoer(undoer); state.set_undoer(undoer);
egui::TextEdit::store_state(ui.ctx(), text_edit_id, state); egui::TextEdit::store_state(ui.ctx(), text_edit_id, state);
@ -155,13 +155,13 @@ pub(crate) fn menu_bar(app: &mut TextEditor, ctx: &egui::Context) {
if let Some(active_tab) = app.get_active_tab_mut() { if let Some(active_tab) = app.get_active_tab_mut() {
let current_state = ( let current_state = (
state.cursor.char_range().unwrap_or_default(), state.cursor.char_range().unwrap_or_default(),
active_tab.content.clone(), active_tab.content.to_string(),
); );
let mut undoer = state.undoer(); let mut undoer = state.undoer();
if let Some((cursor_range, content)) = if let Some((cursor_range, content)) =
undoer.redo(&current_state) undoer.redo(&current_state)
{ {
active_tab.content = content.clone(); active_tab.content = content.to_string();
state.cursor.set_char_range(Some(*cursor_range)); state.cursor.set_char_range(Some(*cursor_range));
state.set_undoer(undoer); state.set_undoer(undoer);
egui::TextEdit::store_state(ui.ctx(), text_edit_id, state); egui::TextEdit::store_state(ui.ctx(), text_edit_id, state);
@ -276,14 +276,14 @@ pub(crate) fn menu_bar(app: &mut TextEditor, ctx: &egui::Context) {
if app.hide_tab_bar { if app.hide_tab_bar {
let tab_title = if let Some(tab) = app.get_active_tab() { let tab_title = if let Some(tab) = app.get_active_tab() {
tab.title.clone() tab.title.to_owned()
} else { } else {
let empty_tab = crate::app::tab::Tab::new_empty(1); let empty_tab = crate::app::tab::Tab::new_empty(1);
empty_tab.title.clone() empty_tab.title.to_owned()
}; };
let window_width = ctx.screen_rect().width(); let window_width = ctx.screen_rect().width();
let font_id = ui.style().text_styles[&egui::TextStyle::Body].clone(); let font_id = ui.style().text_styles[&egui::TextStyle::Body].to_owned();
let tab_title = if app.get_active_tab().is_some_and(|tab| tab.is_modified) { let tab_title = if app.get_active_tab().is_some_and(|tab| tab.is_modified) {
format!("{tab_title}*") format!("{tab_title}*")

View File

@ -78,7 +78,7 @@ pub(crate) fn preferences_window(app: &mut TextEditor, ctx: &egui::Context) {
.font_size_input .font_size_input
.as_ref() .as_ref()
.unwrap_or(&"14".to_string()) .unwrap_or(&"14".to_string())
.clone(); .to_owned();
let response = ui.add( let response = ui.add(
egui::TextEdit::singleline(&mut font_size_text) egui::TextEdit::singleline(&mut font_size_text)
.desired_width(50.0) .desired_width(50.0)
@ -86,7 +86,7 @@ pub(crate) fn preferences_window(app: &mut TextEditor, ctx: &egui::Context) {
.id(egui::Id::new("font_size_input")), .id(egui::Id::new("font_size_input")),
); );
app.font_size_input = Some(font_size_text.clone()); app.font_size_input = Some(font_size_text.to_owned());
if response.clicked() { if response.clicked() {
response.request_focus(); response.request_focus();
@ -132,18 +132,18 @@ pub(crate) fn preferences_window(app: &mut TextEditor, ctx: &egui::Context) {
egui::RichText::new( egui::RichText::new(
"The quick brown fox jumps over the lazy dog.", "The quick brown fox jumps over the lazy dog.",
) )
.font(preview_font.clone()), .font(preview_font.to_owned()),
); );
ui.label( ui.label(
egui::RichText::new("ABCDEFGHIJKLMNOPQRSTUVWXYZ") egui::RichText::new("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
.font(preview_font.clone()), .font(preview_font.to_owned()),
); );
ui.label( ui.label(
egui::RichText::new("abcdefghijklmnopqrstuvwxyz") egui::RichText::new("abcdefghijklmnopqrstuvwxyz")
.font(preview_font.clone()), .font(preview_font.to_owned()),
); );
ui.label( ui.label(
egui::RichText::new("1234567890 !@#$%^&*()").font(preview_font), egui::RichText::new("1234567890 !@#$%^&*()").font(preview_font.to_owned()),
); );
}); });
}); });