From 56d862e7a767373b8f360622d63f0f64f2da3b43 Mon Sep 17 00:00:00 2001 From: vasilito Date: Sun, 5 Jul 2026 04:32:28 +0300 Subject: [PATCH] tlc: wire all remaining F9 editor menubar commands Wire New, Open, Save, SaveAs, Quit, Find, FindNext, FindPrev, Replace, BookmarkNext, BookmarkPrev through dispatch_editor_cmd. Previously these printed 'F9: Cmd (not yet wired)'. Now each one performs the actual operation matching its Alt-key/F-key equivalent. open_save_before_close_prompt made pub(crate) so the Quit handler can intercept dirty buffers. --- .../tui/tlc/source/src/editor/handlers.rs | 2 +- .../recipes/tui/tlc/source/src/editor/mod.rs | 114 +++++++++++++++++- 2 files changed, 113 insertions(+), 3 deletions(-) diff --git a/local/recipes/tui/tlc/source/src/editor/handlers.rs b/local/recipes/tui/tlc/source/src/editor/handlers.rs index 2a174ec4aa..e4d84d0280 100644 --- a/local/recipes/tui/tlc/source/src/editor/handlers.rs +++ b/local/recipes/tui/tlc/source/src/editor/handlers.rs @@ -1075,7 +1075,7 @@ impl Editor { } /// Open the "Save before close?" prompt. - fn open_save_before_close_prompt(&mut self) { + pub(crate) fn open_save_before_close_prompt(&mut self) { self.prompt_input.clear(); self.mode = Mode::Prompt(PromptKind::SaveBeforeClose); } diff --git a/local/recipes/tui/tlc/source/src/editor/mod.rs b/local/recipes/tui/tlc/source/src/editor/mod.rs index 9bc1843749..d1a4ff35a7 100644 --- a/local/recipes/tui/tlc/source/src/editor/mod.rs +++ b/local/recipes/tui/tlc/source/src/editor/mod.rs @@ -995,8 +995,118 @@ bracket_flash: None, EditorCmd::Settings => { self.message = Some("Settings dialog (TBD)".to_string()); } - // Items not yet wired: New, Open, Save, SaveAs, Quit, - // Find, FindNext, FindPrev, Replace, BookmarkNext/Prev. + EditorCmd::New => { + let mut new_editor = Self::new_empty(); + std::mem::swap(&mut self.buffer, &mut new_editor.buffer); + std::mem::swap(&mut self.cursor, &mut new_editor.cursor); + self.path = None; + self.modified = false; + self.title = "*new*".to_string(); + self.message = Some("New buffer".to_string()); + } + EditorCmd::Open => { + self.prompt_input.clear(); + self.mode = Mode::Prompt(PromptKind::InsertFile); + } + EditorCmd::Save => { + match self.save() { + Ok(()) => self.message = Some("Saved".to_string()), + Err(e) => self.message = Some(format!("Save error: {e}")), + } + } + EditorCmd::SaveAs => { + self.prompt_input.clear(); + self.mode = Mode::Prompt(PromptKind::SaveAs); + } + EditorCmd::Quit => { + if self.modified { + self.open_save_before_close_prompt(); + } else { + return EditorResult::Close; + } + } + EditorCmd::Find => { + self.prompt_input.clear(); + self.mode = Mode::Prompt(PromptKind::Find); + } + EditorCmd::FindNext => { + let from = self.cursor.position(); + if let Some(m) = self.search.find_next(&self.buffer, from) { + self.buffer.set_cursor(m.range.start); + self.cursor.set_position(m.range.start, &self.buffer); + self.message = Some("Match found".to_string()); + } else { + self.message = Some("No more matches".to_string()); + } + } + EditorCmd::FindPrev => { + let from = self.cursor.position(); + if let Some(m) = self.search.find_prev(&self.buffer, from) { + self.buffer.set_cursor(m.range.start); + self.cursor.set_position(m.range.start, &self.buffer); + self.message = Some("Match found".to_string()); + } else { + self.message = Some("No more matches".to_string()); + } + } + EditorCmd::Replace => { + self.prompt_input.clear(); + self.mode = Mode::Prompt(PromptKind::Replace); + } + EditorCmd::BookmarkNext => { + let cur_line = self.buffer.line_of_cursor() as u32; + let all: Vec<(char, crate::editor::bookmark::Mark)> = self + .bookmarks + .names() + .into_iter() + .filter_map(|n| self.bookmarks.get(n).map(|m| (n, m))) + .collect(); + let target = all + .iter() + .find(|(_, m)| m.line > cur_line) + .or_else(|| all.first()); + if let Some((name, mark)) = target { + if let Ok(off) = crate::editor::goto::col_to_offset( + &self.buffer, + mark.line + 1, + mark.col + 1, + ) { + self.buffer.set_cursor(off); + self.cursor.set_position(self.buffer.cursor(), &self.buffer); + self.message = Some(format!("Bookmark '{}'", name)); + } + } else { + self.message = Some("No bookmarks set".to_string()); + } + } + EditorCmd::BookmarkPrev => { + let cur_line = self.buffer.line_of_cursor() as u32; + let mut all: Vec<(char, crate::editor::bookmark::Mark)> = self + .bookmarks + .names() + .into_iter() + .filter_map(|n| self.bookmarks.get(n).map(|m| (n, m))) + .collect(); + all.sort_by_key(|(_, m)| m.line); + let target = all + .iter() + .rev() + .find(|(_, m)| m.line < cur_line) + .or_else(|| all.last()); + if let Some((name, mark)) = target { + if let Ok(off) = crate::editor::goto::col_to_offset( + &self.buffer, + mark.line + 1, + mark.col + 1, + ) { + self.buffer.set_cursor(off); + self.cursor.set_position(self.buffer.cursor(), &self.buffer); + self.message = Some(format!("Bookmark '{}'", name)); + } + } else { + self.message = Some("No bookmarks set".to_string()); + } + } _ => { self.message = Some(format!("F9: {:?} (not yet wired)", cmd)); }