M7: ignore ellipses in sentence capitalization proofing (storytold/wordcraft#742)

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
authored and GitHub committed 2026-10-12 05:29:57 -04:00
1 parent 27f6e01853
commit dda47d482d
1 file changed
+28 -2
+28 -2
View File
@@ -539,8 +539,12 @@ pub fn check_grammar(text: &str) -> Vec<Issue> {
});
}
let tail = text.get(*b..).unwrap_or("");
let next_non_space = tail.trim_start_matches(['"', '”', ')', '\'']).chars().next();
after_end = matches!(next_non_space, Some('.' | '!' | '?')) && tail.trim_start_matches(['.', '!', '?', '"', '”', ')']).starts_with(' ');
let punctuation = tail.trim_start_matches(['"', '”', ')', '\'']);
// Two or more dots are an ellipsis, not a full stop ending a sentence.
// A Unicode ellipsis (U+2026) does not match sentence-ending punctuation either.
after_end = matches!(punctuation.chars().next(), Some('.' | '!' | '?'))
&& !punctuation.starts_with("..")
&& punctuation.trim_start_matches(['.', '!', '?', '"', '”', ')']).starts_with(' ');
}
v.sort_by_key(|i| i.start);
v
@@ -655,6 +659,28 @@ mod tests {
assert!(check_grammar("A university is an hour away.").is_empty(), "{:?}", check_grammar("A university is an hour away."));
}
#[test]
fn ellipses_do_not_start_sentences() {
for text in [
"I saw... a figure right outside.",
"I saw… a figure right outside.",
"I saw.... a figure right outside.",
"I saw... \"a figure\" right outside.",
"I saw… “a figure” right outside.",
] {
let capitals: Vec<_> =
check_grammar(text).into_iter().filter(|issue| issue.message == "Capitalize the first word of a sentence").collect();
assert!(capitals.is_empty(), "{text}: {capitals:?}");
}
for text in ["I saw. a figure.", "I saw! a figure.", "I saw? a figure.", "I saw.\" a figure."] {
let capitals: Vec<_> =
check_grammar(text).into_iter().filter(|issue| issue.message == "Capitalize the first word of a sentence").collect();
assert_eq!(capitals.len(), 1, "{text}: {capitals:?}");
assert_eq!(capitals[0].suggestions, ["A"], "{text}");
}
}
#[test]
fn user_dictionary_works() {
assert!(!is_correct("zxqwordcrafty"));