From 4f9b292213274dcf08e286e4aca64e7f15246eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabio=20William=20Concei=C3=A7=C3=A3o?= Date: Fri, 9 Oct 2026 20:23:32 +0100 Subject: [PATCH] =?UTF-8?q?Part=20of=20#394:=20headless=20tests=20for=20Hy?= =?UTF-8?q?phenation=20=E2=80=BA=20Exceptions=20UI=20and=20layout.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- crates/text/src/hyphen.rs | 12 +++++++++--- crates/text/src/tests_typo.rs | 20 ++++++++++++++++++++ crates/ui-egui/src/prefs_dialog.rs | 24 ++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/crates/text/src/hyphen.rs b/crates/text/src/hyphen.rs index 5ba9b392..9255d76c 100644 --- a/crates/text/src/hyphen.rs +++ b/crates/text/src/hyphen.rs @@ -186,14 +186,20 @@ thread_local! { static TEST_OVERRIDE: std::cell::RefCell> = const { std::cell::RefCell::new(None) }; } +/// Run `f` with Preferences › Hyphenation › Exceptions applied on this thread only (tests). +#[cfg(test)] +pub(crate) fn with_hyphenation_exceptions_for_test(source: &str, f: impl FnOnce()) { + TEST_OVERRIDE.with(|c| *c.borrow_mut() = Some(parse_list(source))); + f(); + TEST_OVERRIDE.with(|c| *c.borrow_mut() = None); +} + #[cfg(test)] mod tests { use super::*; fn with_exceptions(source: &str, f: impl FnOnce()) { - TEST_OVERRIDE.with(|c| *c.borrow_mut() = Some(parse_list(source))); - f(); - TEST_OVERRIDE.with(|c| *c.borrow_mut() = None); + with_hyphenation_exceptions_for_test(source, f); } /// #394 Preferences › Hyphenation › Exceptions contract (parse + override). diff --git a/crates/text/src/tests_typo.rs b/crates/text/src/tests_typo.rs index 136c7cc3..4897e53b 100644 --- a/crates/text/src/tests_typo.rs +++ b/crates/text/src/tests_typo.rs @@ -415,6 +415,26 @@ fn hyphenated_layout_adds_hyphens() { } } +/// Preferences › Hyphenation › Exceptions (#394): listing a word stops the layout from breaking it. +#[test] +fn hyphenation_exceptions_keep_listed_words_whole_in_layout() { + // Same copy as `hyphenated_layout_adds_hyphens` (known to produce soft hyphens at 120pt width). + let text = "Extraordinarily comprehensive typographical considerations notwithstanding everything."; + let mut t = area(text, style(14.0), Rect::new(0.0, 0.0, 120.0, 600.0), Justify::Left); + t.para.hyphenate = true; + let with_breaks = layout(db(), &t); + let hyphens = |l: &TextLayout| l.glyphs.iter().filter(|g| g.len == 0).count(); + assert!(hyphens(&with_breaks) > 0, "pattern produces soft hyphens"); + hyphen::with_hyphenation_exceptions_for_test( + "extraordinarily, comprehensive, typographical, considerations, notwithstanding, everything", + || { + let blocked = layout(db(), &t); + assert_eq!(hyphens(&blocked), 0, "every long word listed: no soft hyphens"); + assert!(blocked.lines.len() >= with_breaks.lines.len()); + }, + ); +} + #[test] fn soft_hyphen_is_invisible_mid_line() { let l = layout(db(), &TextObject::point(Point::ZERO, "co\u{00AD}operate", style(20.0))); diff --git a/crates/ui-egui/src/prefs_dialog.rs b/crates/ui-egui/src/prefs_dialog.rs index 300b570d..743631c4 100644 --- a/crates/ui-egui/src/prefs_dialog.rs +++ b/crates/ui-egui/src/prefs_dialog.rs @@ -577,4 +577,28 @@ mod tests { assert!(PREF_SPECS.iter().any(|s| s.category == *c)); } } + + /// Preferences › Hyphenation › Exceptions (#394): OK on the dialog pushes the list into the + /// hyphenator the same way `prefs.set` does (no need to drive the live Preferences window). + #[test] + fn hyphenation_exceptions_dialog_ok_reaches_the_hyphenator() { + struct Clear; + impl Drop for Clear { + fn drop(&mut self) { + vectorcraft_text::set_hyphenation_exceptions(""); + } + } + let _clear = Clear; + let mut a = app(); + open(&mut a, Some("Hyphenation")); + let d = a.ui.dialog.as_mut().unwrap(); + assert_eq!(d.str("__category"), "Hyphenation"); + d.fields.insert("hyphenationExceptions".into(), json!("typography, hap-pen")); + confirm(&mut a).unwrap(); + assert!(a.ui.dialog.is_none()); + assert_eq!(a.session.prefs.hyphenation_exceptions, "typography, hap-pen"); + assert_eq!(vectorcraft_text::hyphenation_exceptions(), "typography, hap-pen"); + assert!(vectorcraft_text::hyphen::hyphen_points("typography").is_empty()); + assert_eq!(vectorcraft_text::hyphen::hyphen_points("happen"), vec![3]); + } }