From 08063e464353531cebe4c4a8d51f516985786d0a Mon Sep 17 00:00:00 2001 From: vasilito Date: Wed, 8 Jul 2026 13:48:42 +0300 Subject: [PATCH] tlc: word completion and spell check in editor menubar --- .../tui/tlc/source/src/editor/menubar.rs | 6 +++ .../recipes/tui/tlc/source/src/editor/mod.rs | 41 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/local/recipes/tui/tlc/source/src/editor/menubar.rs b/local/recipes/tui/tlc/source/src/editor/menubar.rs index 739988dfd6..660d004c63 100644 --- a/local/recipes/tui/tlc/source/src/editor/menubar.rs +++ b/local/recipes/tui/tlc/source/src/editor/menubar.rs @@ -95,6 +95,10 @@ pub enum EditorCmd { Delete, /// Toggle column/stream selection mode (MC CK_Mark). ToggleColumnMode, + /// Alt-Tab — complete the word before the cursor (MC CK_Complete). + WordComplete, + /// Check spelling of the word at cursor (MC CK_SpellCheck). + SpellCheck, } /// Outcome of a menu-bar key press. @@ -221,6 +225,7 @@ impl EditorMenuBar { MenuItem::item("Paste", 'v', EditorCmd::Paste), MenuItem::item("Delete", 'd', EditorCmd::Delete), MenuItem::separator(), + MenuItem::item("Complete word", 'w', EditorCmd::WordComplete), MenuItem::item("Select all", 'a', EditorCmd::MarkAll), MenuItem::item("Toggle column", 't', EditorCmd::ToggleColumnMode), ], @@ -271,6 +276,7 @@ impl EditorMenuBar { MenuItem::item("Relative line numbers", 'r', EditorCmd::ToggleRelativeLines), MenuItem::separator(), MenuItem::item("Insert/Overwrite", 'i', EditorCmd::ToggleOverwrite), + MenuItem::item("Spell check", 's', EditorCmd::SpellCheck), ], ), ]; diff --git a/local/recipes/tui/tlc/source/src/editor/mod.rs b/local/recipes/tui/tlc/source/src/editor/mod.rs index b3ec1c6f6e..9845b61355 100644 --- a/local/recipes/tui/tlc/source/src/editor/mod.rs +++ b/local/recipes/tui/tlc/source/src/editor/mod.rs @@ -1293,6 +1293,26 @@ impl Editor { EditorCmd::Redo => { self.redo(); } + EditorCmd::WordComplete => { + self.word_complete(); + } + EditorCmd::SpellCheck => { + let misspelled = self.find_next_misspelled( + self.cursor.position(), + ); + if let Some((start, end)) = misspelled { + self.cursor.set_position(end, &self.buffer); + self.cursor.start_selection(); + self.cursor.set_position(start, &self.buffer); + self.message = Some( + "Misspelled word — press Alt-Tab for suggestions" + .to_string(), + ); + } else { + self.message = + Some("No more misspelled words".to_string()); + } + } EditorCmd::Cut => { if let Some(text) = self.cursor.selected_text(&self.buffer) { self.clipboard = Some(text.clone()); @@ -3970,5 +3990,26 @@ mod tests { let _ = e.dispatch_editor_cmd(crate::editor::menubar::EditorCmd::ToggleOverwrite); assert_eq!(e.message, Some("[INS]".to_string())); } + + #[test] + fn spell_check_finds_misspelled_word() { + let mut e = make_empty(); + e.toggle_spell_check(); + assert!(e.spell_check_enabled()); + e.insert_str("hello wrdl"); + e.buffer.set_cursor(0); + e.cursor.set_position(0, &e.buffer); + let _ = e.dispatch_editor_cmd(crate::editor::menubar::EditorCmd::SpellCheck); + assert!(e.cursor.has_selection()); + } + + #[test] + fn word_complete_dispatches_without_panic() { + let mut e = make_empty(); + e.insert_str("hello help"); + e.buffer.set_cursor(12); + e.cursor.set_position(12, &e.buffer); + let _ = e.dispatch_editor_cmd(crate::editor::menubar::EditorCmd::WordComplete); + } }