From 87be33e969a8ca05f780cab0e71ec77ec88b8814 Mon Sep 17 00:00:00 2001 From: aiongg Date: Sat, 24 Oct 2026 05:56:36 +0000 Subject: [PATCH] Hyphenation: new documents start with Capitalized Words, Last Word and Across Column off --- ROADMAP.md | 3 ++- crates/engine/src/cmd/file.rs | 49 +++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index ea6de1069..cc080e604 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -350,6 +350,7 @@ list) · [roadmap.md](docs/roadmap.md) (milestones, plan) · [parity-checklist.m Newest first. +- **2026-10-24** · New documents start with Hyphenate Capitalized Words, Hyphenate Last Word and Hyphenate Across Column off in [Basic Paragraph], as in InDesign. Opened and imported files keep the values they carry. No readiness percentage change. - **2026-10-24** · The baseline grid's Relative To setting applies: with Top Margin, the grid starts at each page's own top margin in text composition, on the canvas and for snapping. It started at the page top, so grid-aligned text sat on the wrong lines and a page could fit one line fewer. No readiness percentage change. - **2026-10-24** · Custom-positioned anchored objects honour Relative to Spine (`anchored.options {spineRelative}`, IDML `SpineRelative`): the settings describe a left-hand page and mirror on a right-hand page, so marginal notes stay in the outside margin on both pages of a spread. On right-hand pages they took the left-hand placement and landed in the inside margin, across the spine or over the body text. No readiness percentage change. - **2026-10-24** · Text frames: a custom baseline grid (Text Frame Options › Baseline Options) from an IDML file sets lines from its start by its increment. The composer read the two values in the other order, so lines landed on the wrong grid. No readiness percentage change. @@ -358,7 +359,7 @@ Newest first. - **2026-10-16** · Edit › Keyboard Shortcuts imports a set saved by InDesign's Show Set (.txt, Windows or Mac key names, UTF-8 or UTF-16): matched commands take its Default shortcuts or lose theirs, other commands give up keys it takes, and a report lists what it changed and the items it could not match (`window.importShortcuts`, #1180). Tool keys stay fixed. No readiness percentage change. - **2026-10-23** · Translations: a missing string shows in English and fails no test; `cargo xtask i18n-report`, run by `cargo xtask ci`, prints the missing strings per language. Tests keep duplicate-key and placeholder checks and the language mechanics (lookup, context captions, plural captions, right-to-left). No readiness percentage change. - **2026-10-22** · Hyphenation Settings, as in InDesign: the Paragraph panel menu's Hyphenation… (`app.hyphenationDialog`) sets the selected paragraphs' Hyphenate, Words with at Least, After First, Before Last, Hyphen Limit, Hyphenation Zone, the Better Spacing ↔ Fewer Hyphens slider (InDesign's 0–10 steps), Hyphenate Capitalized Words, Last Word and Across Column, with Preview, as one undo step; Paragraph Style Options › Hyphenation has the same form. The panel menu lists its items in InDesign's order. Replicated from a hyphenation tutorial: the same text in Minion Pro breaks into the same lines as InDesign's with hyphenation on, off, and at Fewer Hyphens. No readiness percentage change. -- **2026-10-22** · Hyphenate Across Column (Hyphenation Settings; IDML HyphenateAcrossColumns) is applied: with it off, a paragraph whose line ending in an automatic hyphen would end a column or frame is re-composed without that hyphenation point, so the word moves on whole, as in InDesign. On by default, as in InDesign, so existing layouts don't change. No readiness percentage change. +- **2026-10-22** · Hyphenate Across Column (Hyphenation Settings; IDML HyphenateAcrossColumns) is applied: with it off, a paragraph whose line ending in an automatic hyphen would end a column or frame is re-composed without that hyphenation point, so the word moves on whole, as in InDesign. Opened and imported files keep their own setting, so their layouts don't change. No readiness percentage change. - **2026-10-22** · A ruler guide dragged with the Selection tools, out of a ruler, on its own or with other selected guides, snaps along its axis as objects do (#1221): to other ruler guides, margins, columns, bleed, page and object edges and centers (with the smart-guide mark) and the document grid, within the snap zone and following Snap to Guides and Smart Guides. Shift snaps to the ruler's ticks and Cmd suspends snapping. The preview line, the position readout and the drop use the same snapped position. No readiness percentage change. - **2026-10-22** · macOS: the app menu has a Language submenu after Settings… with each interface language in its own name and the current one checked, as in the suite's other apps; Preferences › General › Interface Language stays. No readiness percentage change. - **2026-10-22** · macOS menu bar: the menus keep working after the interface language or Show CJK Features changes (a rebuilt menu bar lost every click, Quit included), and its key equivalents are the shortcuts in effect, so a shortcut moved in the Keyboard Shortcuts editor leaves its old menu item. No readiness percentage change. diff --git a/crates/engine/src/cmd/file.rs b/crates/engine/src/cmd/file.rs index c644284d1..73896060e 100644 --- a/crates/engine/src/cmd/file.rs +++ b/crates/engine/src/cmd/file.rs @@ -231,11 +231,24 @@ fn new_document_settings(s: &Session, p: &Value) -> Result { Ok(nd) } +/// A document as `file.new` makes it. Its Basic Paragraph doesn't hyphenate capitalized words, a +/// paragraph's last word or across a column. Opened and imported files keep their own values, +/// which is why `ParaProps` keeps the IDML defaults (on). +fn new_document(nd: &NewDocument) -> Document { + let mut d = Document::new(nd); + if let Some(st) = Arc::make_mut(&mut d.styles).para_mut(designcraft_doc::BASIC_PARAGRAPH) { + st.para.hyph_capitalized = Some(false); + st.para.hyph_last_word = Some(false); + st.para.hyph_across_column = Some(false); + } + d +} + fn file_new(s: &mut Session, p: &Value) -> Result { let mut nd = new_document_settings(s, p)?; s.untitled += 1; nd.title = str_param(p, "title").map(str::to_string).unwrap_or_else(|| format!("Untitled-{}", s.untitled)); - let d = Document::new(&nd); + let d = new_document(&nd); let i = s.add_document(DocState::new(d, None)); Ok(json!({"index": i})) } @@ -259,7 +272,7 @@ impl Session { self.untitled += 1; } nd.title = str_param(p, "title").map(str::to_string).unwrap_or_else(|| self.next_untitled_title()); - let st = DocState::new(Document::new(&nd), None); + let st = DocState::new(new_document(&nd), None); let uid = st.uid; match replace.and_then(|i| self.docs.get_mut(i).map(|d| (i, d))) { Some((i, d)) => { @@ -2124,3 +2137,35 @@ mod recent_tests { assert!(old.recent_files.is_empty(), "older prefs.json without the list still load"); } } + +#[cfg(test)] +mod hyphenation_default_tests { + use std::sync::Arc; + + use designcraft_doc::BASIC_PARAGRAPH; + use designcraft_doc::build::NewDocument; + use serde_json::json; + + use crate::Session; + + fn hyph_flags(d: &designcraft_doc::Document) -> (bool, bool, bool) { + let (pp, _) = d.styles.resolve_para(&designcraft_doc::ParaFormat::default()); + (pp.hyph_capitalized, pp.hyph_last_word, pp.hyph_across_column) + } + + #[test] + fn new_documents_hyphenate_no_capitalized_last_or_column_end_words_and_imports_keep_theirs() { + let mut s = Session::new(); + s.execute("file.new", &json!({})).unwrap(); + assert_eq!(hyph_flags(&s.doc().unwrap().doc), (false, false, false)); + + let mut d = designcraft_doc::Document::new(&NewDocument::default()); + let st = Arc::make_mut(&mut d.styles).para_mut(BASIC_PARAGRAPH).unwrap(); + st.para.hyph_capitalized = Some(true); + st.para.hyph_last_word = Some(true); + st.para.hyph_across_column = Some(true); + let b64 = super::base64_encode(&designcraft_idml::export_idml(&d)); + s.execute("file.openIdml", &json!({"base64": b64, "name": "in.idml"})).unwrap(); + assert_eq!(hyph_flags(&s.doc().unwrap().doc), (true, true, true)); + } +}