diff --git a/contributors/people.toml b/contributors/people.toml index 4a44f5ab..23ff0917 100644 --- a/contributors/people.toml +++ b/contributors/people.toml @@ -37,3 +37,8 @@ real_name = "Jeffrey Thayne" [people.webdevtodayjason] display_name = "Jason Brashear" + +[people.Nmarello] +real_name = "Nick Marello" +display_name = "Nick Marello" +sync_github_name = false diff --git a/crates/engine/src/cmd/file.rs b/crates/engine/src/cmd/file.rs index 5a38b734..0b689370 100644 --- a/crates/engine/src/cmd/file.rs +++ b/crates/engine/src/cmd/file.rs @@ -158,8 +158,24 @@ fn file_sample(s: &mut Session, _p: &Value) -> Result { Ok(json!({"index": i})) } +/// An InDesign file that DesignCraft can't open yet, with how to bring it over. Decoding one as a +/// DesignCraft document only reported "not a DesignCraft document: expected value at line 1 +/// column 1" (#21). +fn foreign_document(name: &str) -> Option<&'static str> { + let ext = std::path::Path::new(name).extension().and_then(|e| e.to_str())?.to_ascii_lowercase(); + match ext.as_str() { + "indd" | "indt" => Some( + "InDesign documents (.indd) and templates (.indt) can't be opened yet. In InDesign, choose File ▸ Export… ▸ InDesign Markup (IDML) and open the .idml in DesignCraft.", + ), + _ => None, + } +} + fn file_open(s: &mut Session, p: &Value) -> Result { let path = str_param(p, "path").ok_or_else(|| bad("file.open", "missing `path`"))?; + if let Some(hint) = foreign_document(path) { + return Err(EngineError::Other(format!("{path}: {hint}"))); + } #[cfg(not(target_arch = "wasm32"))] { if path.to_ascii_lowercase().ends_with(".idml") { @@ -223,6 +239,11 @@ fn document_fonts_folder(dir: &std::path::Path) -> std::path::PathBuf { } fn file_open_bytes(s: &mut Session, p: &Value) -> Result { + if let Some(name) = str_param(p, "name") + && let Some(hint) = foreign_document(name) + { + return Err(EngineError::Other(format!("{name}: {hint}"))); + } let b = base64_decode(str_param(p, "base64").unwrap_or("")); // IDML packages are recognised by their stored `mimetype` first entry. if designcraft_idml::is_idml(&b) { @@ -912,6 +933,21 @@ mod document_fonts_tests { let _ = std::fs::remove_dir_all(&dir); } + #[test] + fn an_indesign_file_says_how_to_bring_it_over() { + // The extension decides (any case), not the bytes: no InDesign-made file is needed. + let dir = temp_dir("indd"); + let path = dir.join("Brochure.INDD"); + std::fs::write(&path, b"not a DesignCraft document").unwrap(); + let mut s = Session::new(); + let e = s.execute("file.open", &json!({"path": path.to_string_lossy()})).unwrap_err().to_string(); + assert!(e.contains("InDesign Markup (IDML)") && !e.contains("expected value"), "{e}"); + let e = s.execute("file.openBytes", &json!({"name": "Brochure.indt", "base64": ""})).unwrap_err().to_string(); + assert!(e.contains("InDesign Markup (IDML)"), "{e}"); + assert!(s.doc().is_err(), "nothing was opened"); + let _ = std::fs::remove_dir_all(&dir); + } + #[test] fn the_document_fonts_folder_is_found_whatever_its_case() { const FAMILY: &str = "DocFont Case Test"; diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index f6fa64fa..72502388 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -1432,7 +1432,9 @@ impl DesignApp { /// and IDML. pub fn opens_as_document(name: &str) -> bool { let n = name.to_ascii_lowercase(); - [".designcraft", ".idml"].iter().any(|ext| n.ends_with(ext)) + // InDesign files go to the open path too, which says how to bring them over (as IDML) + // instead of failing to place them as a graphic. + [".designcraft", ".idml", ".indd", ".indt"].iter().any(|ext| n.ends_with(ext)) } pub fn now_ms() -> f64 { @@ -2069,7 +2071,7 @@ mod tests { #[test] fn dropped_documents_open_and_the_rest_is_placed() { - for name in ["a.designcraft", "B.IDML"] { + for name in ["a.designcraft", "B.IDML", "c.indd", "D.INDT"] { assert!(opens_as_document(name), "{name}"); } for name in ["a.png", "b.pdf", "idml.txt", "c.idml.zip"] {