From a8b3bb74c8e51fdca1c4b156129c26a6e1b1385d Mon Sep 17 00:00:00 2001 From: Martin Ball Date: Mon, 2 Nov 2026 23:23:15 +0000 Subject: [PATCH] =?UTF-8?q?craft-proof=20it,=20pt=20=E2=80=94=20the=20obje?= =?UTF-8?q?ct=20placeholder=20is=20not=20a=20closing=20quote,=20so=20Chi?= =?UTF-8?q?=20era=3F\u{1}=20era=20Marco.=20still=20gets=20its=20capital=20?= =?UTF-8?q?mark=20(#496=20review)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- crates/proof/src/it/grammar.rs | 5 ++++- crates/proof/src/pt/grammar.rs | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/proof/src/it/grammar.rs b/crates/proof/src/it/grammar.rs index cad690c4..620e284a 100644 --- a/crates/proof/src/it/grammar.rs +++ b/crates/proof/src/it/grammar.rs @@ -165,9 +165,10 @@ fn ends_sentence(gap: &str, prev: &str) -> bool { } let after_marks = t.trim_start_matches(['.', '!', '?']); let rest = after_marks.trim_start_matches(CLOSING); + // (Not the object placeholder `\u{1}`: `Chi era?\u{1} era Marco.` still starts a sentence.) // `«Vai?» disse lui.` and `—Vai? —disse lui.`: the narration after a quoted question or // exclamation, or after a dialogue dash, goes on in lower case. - if rest.contains('—') || (end != '.' && after_marks.starts_with(CLOSING)) { + if rest.contains('—') || (end != '.' && after_marks.starts_with(|c| c != '\u{1}' && CLOSING.contains(&c))) { return false; } rest.starts_with(char::is_whitespace) && rest.trim_start().chars().all(|c| matches!(c, '"' | '“' | '«' | '(' | '[' | '\'' | '—')) @@ -416,6 +417,8 @@ mod tests { assert!(fixes(t).is_empty(), "{t}: {:?}", fixes(t)); } assert!(fixes("Vado a Roma? sì.").contains(&pair("sì", "Sì")), "a bare question still ends the sentence"); + // An inline object (`\u{1}`) is not a closing quote. + assert!(fixes("Chi era?\u{1} era Marco.").contains(&pair("era", "Era")), "{:?}", fixes("Chi era?\u{1} era Marco.")); } #[test] diff --git a/crates/proof/src/pt/grammar.rs b/crates/proof/src/pt/grammar.rs index fc658e22..23891238 100644 --- a/crates/proof/src/pt/grammar.rs +++ b/crates/proof/src/pt/grammar.rs @@ -64,8 +64,8 @@ fn ends_sentence(gap: &str, prev: &str) -> bool { } let after_marks = t.trim_start_matches(['.', '!', '?']); let rest = after_marks.trim_start_matches(CLOSING); - // `"Vai?" disse ele.`: narration after a quoted question or exclamation goes on in lower case. - if end != '.' && after_marks.starts_with(CLOSING) { + // `"Vai?" disse ele.` (not the object placeholder `\u{1}`): narration after a quoted question or exclamation goes on in lower case. + if end != '.' && after_marks.starts_with(|c| c != '\u{1}' && CLOSING.contains(&c)) { return false; } // A dialogue dash after the mark brings back the narration (`—Vai? —disse ele.`), which goes @@ -231,6 +231,8 @@ mod tests { clean("\"Vai?\" disse ele."); clean("«Vai!» gritou ela."); assert!(!messages("Vai? \"sim\".").is_empty(), "a bare question still ends the sentence"); + // An inline object (`\u{1}`) is not a closing quote. + assert!(!messages("Quem era?\u{1} era Marco.").is_empty()); clean("Ele disse: \"Volto amanhã\". E saiu."); // A list item may start in lower case. clean("maçãs,");