From 6fbfea12a6ffdba18a23fb3eba4012f2af64a373 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Thu, 29 Oct 2026 10:09:07 +0000 Subject: [PATCH 1/2] Suggest corrections for misspelt all-caps words Found while testing crates/engine/src/spell.rs:396-448 (Dictionary::suggest) Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Opus 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/engine/src/spell.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/crates/engine/src/spell.rs b/crates/engine/src/spell.rs index 44d1c6b7..94de3365 100644 --- a/crates/engine/src/spell.rs +++ b/crates/engine/src/spell.rs @@ -394,7 +394,8 @@ impl Dictionary { return vec![]; } let cap = word.chars().next().is_some_and(char::is_uppercase); - let lower = if cap && word.chars().skip(1).all(|c| !c.is_uppercase()) { word.to_lowercase() } else { word.to_string() }; + let upper = word.chars().count() > 1 && word.chars().any(char::is_uppercase) && !word.chars().any(char::is_lowercase); + let lower = if upper || (cap && word.chars().skip(1).all(|c| !c.is_uppercase())) { word.to_lowercase() } else { word.to_string() }; let w: Vec = lower.chars().collect(); let mut out: Vec = vec![]; let mut seen = HashSet::new(); @@ -443,7 +444,9 @@ impl Dictionary { push(format!("{} {}", s(&w[..i]), s(&w[i..])), &mut out); } out.truncate(n); - if cap { + if upper { + out = out.into_iter().map(|x| x.to_uppercase()).collect(); + } else if cap { out = out.into_iter().map(|x| capitalise(&x)).collect(); } out @@ -843,6 +846,13 @@ SFX D Y 1\nSFX D 0 ed/S .\n"; assert!(d.suggest("workingslides", 5).contains(&"working slides".to_string())); } + #[test] + fn all_caps_words_get_uppercase_suggestions() { + let d = d(); + assert!(d.suggest("SLDE", 5).contains(&"SLIDE".to_string())); + assert!(d.suggest("FOTO", 5).contains(&"PHOTO".to_string())); + } + #[test] fn compounds_join_flagged_parts() { let aff = "COMPOUNDFLAG X\nCOMPOUNDMIN 3\nONLYINCOMPOUND O\nSFX S Y 1\nSFX S 0 en .\n"; From 1841ab75dac874f7194ab2e87baca682fd23f370 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Fri, 30 Oct 2026 15:57:45 -0400 Subject: [PATCH 2/2] Spelling: check all-caps candidates in capitals so KEEPCASE words are suggested Co-Authored-By: Claude Opus 5.5 --- crates/engine/src/spell.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/engine/src/spell.rs b/crates/engine/src/spell.rs index 94de3365..b36f33dc 100644 --- a/crates/engine/src/spell.rs +++ b/crates/engine/src/spell.rs @@ -400,7 +400,12 @@ impl Dictionary { let mut out: Vec = vec![]; let mut seen = HashSet::new(); let mut push = |s: String, out: &mut Vec| { - if s != lower && seen.insert(s.to_lowercase()) && s.split(' ').all(|p| self.suggestible(p)) { + if s == lower { + return; + } + // Checked in capitals, so a KEEPCASE entry ("NASA") is offered for an all-caps word. + let s = if upper { s.to_uppercase() } else { s }; + if seen.insert(s.to_lowercase()) && s.split(' ').all(|p| self.suggestible(p)) { out.push(s); } }; @@ -444,9 +449,7 @@ impl Dictionary { push(format!("{} {}", s(&w[..i]), s(&w[i..])), &mut out); } out.truncate(n); - if upper { - out = out.into_iter().map(|x| x.to_uppercase()).collect(); - } else if cap { + if cap && !upper { out = out.into_iter().map(|x| capitalise(&x)).collect(); } out @@ -851,6 +854,7 @@ SFX D Y 1\nSFX D 0 ed/S .\n"; let d = d(); assert!(d.suggest("SLDE", 5).contains(&"SLIDE".to_string())); assert!(d.suggest("FOTO", 5).contains(&"PHOTO".to_string())); + assert!(d.suggest("NSSA", 5).contains(&"NASA".to_string())); } #[test]