Lowercase word-final Σ as ς in title and sentence case

Found while testing crates/model/src/edit.rs:470-497 (change_case_parts, title/sentence branch)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-11-01 00:08:51 +01:00
co-authored by Claude Haiku 5.5
parent 82573331a8
commit 3fb6c43136
+23 -1
View File
@@ -469,6 +469,9 @@ pub fn change_case(s: &str, mode: &str) -> String {
/// piece is the changed form of the matching input piece, even where a character changes length.
pub fn change_case_parts(parts: &[&str], mode: &str) -> Vec<String> {
let mut start = true;
// All characters of all pieces, so word-final sigma sees neighbours across piece boundaries.
let all: Vec<char> = parts.iter().flat_map(|s| s.chars()).collect();
let mut base = 0;
parts
.iter()
.map(|s| match mode {
@@ -479,10 +482,14 @@ pub fn change_case_parts(parts: &[&str], mode: &str) -> Vec<String> {
// `title` restarts after whitespace, sentence case after sentence punctuation.
let title = mode == "title";
let mut out = String::new();
for c in s.chars() {
for (j, c) in s.chars().enumerate() {
let i = base + j;
if start && c.is_alphabetic() {
out.extend(c.to_uppercase());
start = false;
} else if c == 'Σ' && i > 0 && all[i - 1].is_alphabetic() && !all.get(i + 1).is_some_and(|n| n.is_alphabetic()) {
// Word-final capital sigma lowercases to ς, as `str::to_lowercase` does.
out.push('ς');
} else {
out.extend(c.to_lowercase());
}
@@ -490,6 +497,7 @@ pub fn change_case_parts(parts: &[&str], mode: &str) -> Vec<String> {
start = true;
}
}
base += s.chars().count();
out
}
})
@@ -504,6 +512,20 @@ mod tests {
TextBody::from_text(t)
}
#[test]
fn title_and_sentence_final_sigma() {
assert_eq!(change_case("ΟΔΟΣ", "title"), "Οδος");
assert_eq!(change_case("ΟΔΟΣ ΜΟΥ.", "sentence"), "Οδος μου.");
assert_eq!(change_case("ΟΔΟΣ", "lower"), "οδος");
}
#[test]
fn title_sigma_across_runs_is_not_final() {
assert_eq!(change_case_parts(&["ΟΔΟΣ", "ΑΣ"], "title"), ["Οδοσ", "ας"]);
assert_eq!(change_case_parts(&["ΟΔΟ", "ΣΑ"], "title"), ["Οδο", "σα"]);
assert_eq!(change_case_parts(&["ΟΔΟΣ", " ΜΟΥ"], "title"), ["Οδος", " Μου"]);
}
#[test]
fn insert_and_split() {
let mut b = body("Hello");