Spell check: a mark on trailing punctuation is trimmed with it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas
2026-11-02 04:53:47 -05:00
co-authored by Claude Opus 5.5
parent 87a10fc8e2
commit ffd77c7db0
+15 -2
View File
@@ -726,8 +726,14 @@ pub fn paragraph_words(p: &deckcraft_model::Paragraph, default: &str) -> Vec<Wor
while a < b && !chars[a].0.is_alphanumeric() {
a += 1;
}
while b > a && !chars[b - 1].0.is_alphanumeric() && !deckcraft_model::words::is_combining_mark(chars[b - 1].0) {
b -= 1;
// Trim back to the last letter or digit, keeping only the marks that sit on it
// (a mark on a trailing apostrophe goes with the apostrophe).
while b > a {
let k = (a..b).rev().find(|&k| !deckcraft_model::words::is_combining_mark(chars[k].0)).unwrap_or(a);
if chars[k].0.is_alphanumeric() {
break;
}
b = k;
}
let text: String = chars[a..b].iter().map(|c| c.0).collect();
if text.is_empty() || text.chars().any(|c| c.is_ascii_digit()) || !text.chars().any(char::is_alphabetic) {
@@ -827,6 +833,13 @@ SFX D Y 1\nSFX D 0 ed/S .\n";
assert_eq!(w, ["Das", "na\u{ef}ve", "Caf\u{e9}", "und", "cafe\u{301}", "na\u{308}ive"]);
}
#[test]
fn a_mark_on_trailing_punctuation_is_trimmed_with_it() {
let p = deckcraft_model::Paragraph::new("word'\u{301} cafe\u{301}' x");
let w: Vec<String> = paragraph_words(&p, "en-US").into_iter().map(|w| w.text).collect();
assert_eq!(w, ["word", "cafe\u{301}", "x"]);
}
#[test]
fn curly_apostrophe_matches_ascii_entry() {
let d = Dictionary::parse(AFF.as_bytes(), "2\ndon't\nwork\n".as_bytes());