From e2c9c26dfd269a25764646ecf1f45b8017e635fb Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 21 Oct 2026 06:55:31 +0800 Subject: [PATCH] Spelling & Grammar button now shows suggestions (#3340) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit review.spelling (the Review tab's Spelling & Grammar button and the Home tab's Editor button) only moved the selection to the next issue, with no way to see or apply a suggestion — just the generic selection toolbar, so it looked broken. Running it now also opens the same suggestions menu Shift+F10 and a Control-click already open for the word at the caret, via the WordApp::run() chokepoint (not the ribbon call sites: keytips call app.run() directly, bypassing a button's own .clicked() check). Exposing this path also surfaced two latent i18n-audit gaps: the suggestions popup's dictionary/grammar-rule words aren't interface text (added an Exempt case, as the audit already does for font names and the user dictionary), and "Possible spelling mistake" was missing from the ru/tr/bg catalogs. Co-Authored-By: Claude Sonnet 5 --- crates/ui-egui/src/canvas.rs | 32 ++++++++++++++++++++++++++++++++ crates/ui-egui/src/i18n/audit.rs | 7 ++++++- crates/ui-egui/src/i18n/bg.tsv | 1 + crates/ui-egui/src/i18n/ru.tsv | 1 + crates/ui-egui/src/i18n/tr.tsv | 1 + crates/ui-egui/src/lib.rs | 10 ++++++++++ 6 files changed, 51 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index fabe1d43d..579fd32f9 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -4827,6 +4827,38 @@ mod tests { assert_eq!(h.state().session.doc.plain_text(StoryRef::Body), "The quick brown fox"); } + /// #3340: review.spelling (the Review tab's Spelling & Grammar button and the Home tab's + /// Editor button both run it) only moved the selection to the next issue — with no way to see + /// or apply a suggestion from there, just the generic selection toolbar, it looked broken. + /// Running it now also opens the same suggestions menu Shift+F10 and a Control-click already + /// open for the word at the caret. + #[test] + fn spelling_and_grammar_opens_suggestions_for_the_issue_it_selects() { + use egui_kittest::kittest::Queryable; + let mut a = WordApp::new(wordcraft_engine::Session::new(wordcraft_doc::Document::new()), Default::default()); + a.run("text.insert", json!({"text": "The quick brwn fox"})).unwrap(); + a.session.sel = wordcraft_engine::Selection::caret(Pos::body(0, 0)); + a.run("review.spelling", json!({})).unwrap(); + assert!(a.canvas.context_menu_from_keys, "queues the open the context menu already uses for Shift+F10"); + let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1440.0, 900.0)).build_ui_state( + |ui, app: &mut WordApp| { + let ctx = ui.ctx().clone(); + app.logic(&ctx); + app.ui(ui); + }, + a, + ); + for _ in 0..6 { + h.step(); + } + assert!(h.state().canvas.context_menu_open, "Spelling & Grammar opens the suggestions menu"); + h.get_by_label("brown").click(); + for _ in 0..3 { + h.step(); + } + assert_eq!(h.state().session.doc.plain_text(StoryRef::Body), "The quick brown fox"); + } + #[test] fn floating_picture_can_be_dragged_in_front_of_or_behind_text() { for wrap in ["inFrontOfText", "behindText"] { diff --git a/crates/ui-egui/src/i18n/audit.rs b/crates/ui-egui/src/i18n/audit.rs index f356fb3dc..49ef07e59 100644 --- a/crates/ui-egui/src/i18n/audit.rs +++ b/crates/ui-egui/src/i18n/audit.rs @@ -5,7 +5,7 @@ use std::cell::Cell; use std::collections::BTreeMap; -use serde_json::json; +use serde_json::{Value, json}; use super::pseudo; use crate::WordApp; @@ -147,6 +147,11 @@ impl Exempt { for m in crate::credits::MODELS { names.extend([m.company, m.model, m.version].map(str::to_string)); } + // The spelling/grammar suggestions popup (#3340): dictionary and grammar-rule words, not + // interface text. + if let Some(sugg) = app.canvas.context_issue.as_ref().and_then(|i| i.get("suggestions")).and_then(Value::as_array) { + names.extend(sugg.iter().filter_map(Value::as_str).map(str::to_string)); + } Exempt { body: app.session.doc.plain_text(wordcraft_doc::StoryRef::Body), names } } diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index 1994f2a15..dabaec5f8 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -802,6 +802,7 @@ Spelling & Grammar Правопис и граматика Spelling &\nGrammar Правопис и\nграматика Spelling Suggestions Предложения за правопис + Possible spelling mistake Възможна правописна грешка Split Разделяне Split Cells Разделяне на клетки Split Table Разделяне на таблица diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index cd064b4ee..7462b581e 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -703,6 +703,7 @@ Spelling & Grammar Орфография и грамматика Spelling &\nGrammar Орфография\nи грамматика Spelling Suggestions Варианты написания + Possible spelling mistake Возможная орфографическая ошибка Split Разделить Split Cells Разделить ячейки Split Table Разделить таблицу diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index 50799c62d..50cee2a69 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -708,6 +708,7 @@ Spelling & Grammar Yazım ve Dilbilgisi Spelling &\nGrammar Yazım ve\nDilbilgisi Spelling Suggestions Yazım Önerileri + Possible spelling mistake Olası yazım hatası Split Böl Split Cells Hücreleri Böl Split Table Tabloyu Böl diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index c7f687a4e..fce086ac3 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -898,6 +898,16 @@ impl WordApp { if matches!(id, "insert.picture" | "insert.icon") { self.select_inserted_picture(&r); } + // review.spelling only moves the selection to the next issue; without this, the ribbon's + // Spelling & Grammar and Editor buttons looked broken — just a selection with no way to + // see or apply a suggestion (#3340). Reuse the context menu's suggestions, as Shift+F10 + // already does for the word at the caret. + if id == "review.spelling" + && let Ok(v) = &r + && v.get("done").and_then(serde_json::Value::as_bool) != Some(true) + { + self.canvas.context_menu_from_keys = true; + } let r = system_clipboard::explain(self, id, r); // Check Accessibility shows its findings in the Accessibility pane, kept up to date there. if id == "file.accessibility" && r.is_ok() {