diff --git a/crates/engine/src/cmd/docinfo.rs b/crates/engine/src/cmd/docinfo.rs index 8538ece84..dd98fa6f3 100644 --- a/crates/engine/src/cmd/docinfo.rs +++ b/crates/engine/src/cmd/docinfo.rs @@ -18,7 +18,7 @@ pub fn specs() -> Vec { "Document Info", ["Window", "Document Info"], None, - "{selectionOnly?, category?: document|objects|graphicStyles|spotColors|patterns|gradients|symbols|fonts|fontDetails|linkedImages|embeddedImages (only that one in sections and the text), format?: \"text\" (→ {text}: the report Document Info › Save… and Package write)} → {document, objects: {paths, compoundPaths, groups, …}, fonts, images, swatches, graphicStyleNames (with selectionOnly: the styles the selected objects are linked to), …, sections: [{id, title, rows: [[label, value]]}] (the panel's categories; fontDetails: each font's file and whether its licence lets it be embedded)}", + "{selectionOnly?, category?: document|objects|graphicStyles|spotColors|patterns|gradients|symbols|fonts|fontDetails|linkedImages|embeddedImages (only that one in sections and the text), format?: \"text\" (→ {text}: the report Document Info › Save… and Package write)} → {document, objects: {paths, compoundPaths, groups, …}, pathLength: pt (the paths' total length, compound paths' included, guides left out), fonts, images, swatches, graphicStyleNames (with selectionOnly: the styles the selected objects are linked to), …, sections: [{id, title, rows: [[label, value]]}] (the panel's categories; fontDetails: each font's file and whether its licence lets it be embedded)}", has_doc, info ), @@ -128,7 +128,13 @@ fn sections(d: &Document, info: &Value, fonts: &BTreeSet rows } "objects" => { - OBJECT_LABELS.iter().filter_map(|(k, label)| Some((label.to_string(), info["objects"][k].as_u64()?.to_string()))).collect() + let mut rows: Vec<(String, String)> = + OBJECT_LABELS.iter().filter_map(|(k, label)| Some((label.to_string(), info["objects"][k].as_u64()?.to_string()))).collect(); + // The paths' total length, in the document's units, right after their count. + if let Some(at) = rows.iter().position(|(label, _)| label == "Paths") { + rows.insert(at + 1, ("Path Length".into(), u.format(info["pathLength"].as_f64().unwrap_or(0.0)))); + } + rows } "graphicStyles" => names("graphicStyleNames"), "spotColors" => names("spotColors"), @@ -229,6 +235,9 @@ fn info(s: &mut Session, p: &Value) -> Result { let roots: Vec<&Node> = if selection_only { st.selection.objects.iter().filter_map(|id| d.node(*id)).collect() } else { d.layers.iter().map(|l| &**l).collect() }; let mut counts: BTreeMap<&str, usize> = BTreeMap::new(); + // The paths' total length, as Document Info › Objects shows it (the length of a cut line, a + // strip of LEDs along the letters, #1958). + let mut path_length = 0.0; let mut fonts = BTreeSet::new(); let mut images: BTreeMap = BTreeMap::new(); let mut image_rows: Vec = vec![]; @@ -243,7 +252,13 @@ fn info(s: &mut Session, p: &Value) -> Result { NodeKind::Group { clip: true, .. } => Some("clipGroups"), NodeKind::Group { .. } => Some("groups"), NodeKind::Path { guide: true, .. } => Some("guides"), - NodeKind::Path { .. } => Some("paths"), + NodeKind::Path { path, .. } => { + let l = path.length(); + if l.is_finite() { + path_length += l; + } + Some("paths") + } NodeKind::Compound { .. } => Some("compoundPaths"), NodeKind::Text(t) => { for run in &t.runs { @@ -308,6 +323,7 @@ fn info(s: &mut Session, p: &Value) -> Result { let mut out = json!({ "document": document_summary(d), "objects": counts, + "pathLength": path_length, "fonts": font_names, "images": images, "symbols": symbols, @@ -405,6 +421,30 @@ mod tests { assert!(i["objects"]["textObjects"].is_null() && i["objects"]["paths"] == 1); } + /// Document Info › Objects gives the paths' total length in the document's units (#1958): an + /// open line, a closed rectangle's perimeter and a compound path's pieces count, a guide doesn't. + #[test] + fn info_gives_the_paths_total_length() { + let mut s = Session::new(); + s.execute("file.new", &json!({"width": 400, "height": 400, "units": "Millimeters"})).unwrap(); + let line = s.execute("shape.line", &json!({"x1": 0, "y1": 0, "x2": 72, "y2": 0})).unwrap()["id"].clone(); + let rect = s.execute("shape.rectangle", &json!({"x": 100, "y": 100, "width": 10, "height": 20})).unwrap()["id"].clone(); + let length = |s: &mut Session, p: Value| s.execute("document.info", &p).unwrap()["pathLength"].as_f64().unwrap(); + assert!((length(&mut s, json!({})) - 132.0).abs() < 1e-6); + s.execute("select.set", &json!({"ids": [line]})).unwrap(); + assert!((length(&mut s, json!({"selectionOnly": true})) - 72.0).abs() < 1e-6); + let rows = s.execute("document.info", &json!({"selectionOnly": true, "category": "objects"})).unwrap()["sections"][0]["rows"].clone(); + assert_eq!(rows, json!([["Paths", "1"], ["Path Length", "25.4 mm"]])); + // A compound path's pieces are paths: their lengths count. + let other = s.execute("shape.rectangle", &json!({"x": 200, "y": 200, "width": 5, "height": 5})).unwrap()["id"].clone(); + s.execute("select.set", &json!({"ids": [rect, other]})).unwrap(); + s.execute("object.compoundPath.make", &json!({})).unwrap(); + assert!((length(&mut s, json!({"selectionOnly": true})) - 80.0).abs() < 1e-6); + // Nothing with no paths, and no length row. + s.execute("select.none", &json!({})).unwrap(); + assert_eq!(length(&mut s, json!({"selectionOnly": true})), 0.0); + } + #[test] fn embedding_permissions_read_from_fs_type() { assert_eq!(embedding_label(0), "embedding allowed"); diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 766444f22..f643849d2 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -2856,6 +2856,7 @@ theme Appearance Motiv Width Profile Profil šířky Objects Objekty Paths Cesty + Path Length Délka cest Add Guide Přidat vodítko Edit Selection Upravit výběr Recall Selection Vyvolat výběr diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index 70d20c969..49e1121dc 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -2002,6 +2002,7 @@ Pathfinder Options… Pathfinder-Optionen… Pathfinders: Pathfinder: Paths Pfade + Path Length Pfadlänge Paths: {paths} Anchors: {anchors} Colors: {colors} Pfade: {paths} Ankerpunkte: {anchors} Farben: {colors} Pattern Muster Pattern Editing Musterbearbeitung diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 492ec1b82..912dfd547 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -2051,6 +2051,7 @@ Pathfinder Options… Opciones de Buscatrazos… Pathfinders: Buscatrazos: Paths Trazados + Path Length Longitud de los trazados Paths: {paths} Anchors: {anchors} Colors: {colors} Trazados: {paths} Anclas: {anchors} Colores: {colors} Pattern Motivo Pattern Editing Edición de motivo diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index b87d78400..5d2b877aa 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -2048,6 +2048,7 @@ Pathfinder Options… Options Pathfinder… Pathfinders: Pathfinders : Paths Tracés + Path Length Longueur des tracés Paths: {paths} Anchors: {anchors} Colors: {colors} Tracés : {paths} Points d’ancrage : {anchors} Couleurs : {colors} Pattern Motif Pattern Editing Modification du motif diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index ff71d8e2e..ac6a532d5 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -2512,6 +2512,7 @@ Pathfinder Options… Útvonalkezelő beállításai… Pathfinders: Útvonalkezelők: Paths Útvonalak + Path Length Útvonalak hossza Paths: {paths} Anchors: {anchors} Colors: {colors} Útvonalak: {paths} Horgonypontok: {anchors} Színek: {colors} Pattern Mintázat Pattern Brush Options Mintázatecset beállításai diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index b1ef63abd..6968d2356 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -2053,6 +2053,7 @@ Pathfinder Options… Opzioni elaborazione tracciati… Pathfinders: Elaborazioni tracciati: Paths Tracciati + Path Length Lunghezza dei tracciati Paths: {paths} Anchors: {anchors} Colors: {colors} Tracciati: {paths} Ancoraggi: {anchors} Colori: {colors} Pattern Motivo Pattern Editing Modifica motivo diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index aa4c97f51..286446343 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -2111,6 +2111,7 @@ Pathfinder Options… パスファインダーオプション… Pathfinders: パスファインダー: Paths パス + Path Length パスの長さ Paths: {paths} Anchors: {anchors} Colors: {colors} パス:{paths} アンカー:{anchors} カラー:{colors} Pattern Editing パターン編集 Pattern options are available in pattern editing mode. パターンオプションはパターン編集モードで使用できます。 diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 824c16fff..fdca17e32 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -2106,6 +2106,7 @@ Pathfinder Options… 패스파인더 옵션… Pathfinders: 패스파인더: Paths 패스 + Path Length 패스 길이 Paths: {paths} Anchors: {anchors} Colors: {colors} 패스: {paths} 앵커: {anchors} 색상: {colors} Pattern Editing 패턴 편집 Pattern options are available in pattern editing mode. 패턴 옵션은 패턴 편집 모드에서 사용할 수 있습니다. diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 89065c917..632ccb480 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -2727,6 +2727,7 @@ theme Appearance Wygląd Width Profile Profil szerokości Objects Obiekty Paths Ścieżki + Path Length Długość ścieżek Add Guide Dodaj linię pomocniczą Edit Selection Edytuj zaznaczenie Recall Selection Przywołaj zaznaczenie diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 23353ed73..216fd3c0f 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -2049,6 +2049,7 @@ Pathfinder Options… Параметры обработки контуров… Pathfinders: Обработка контуров: Paths Контуры + Path Length Длина контуров Paths: {paths} Anchors: {anchors} Colors: {colors} Контуры: {paths} Опорные точки: {anchors} Цвета: {colors} Pattern Узор Pattern Editing Редактирование узора diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 7cb2a80c2..254522990 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -2045,6 +2045,7 @@ Pathfinder Options… Параметри обробки контурів… Pathfinders: Обробка контурів: Paths Контури + Path Length Довжина контурів Paths: {paths} Anchors: {anchors} Colors: {colors} Контури: {paths} Опорні точки: {anchors} Кольори: {colors} Pattern Візерунок Pattern Editing Редагування візерунка diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 8961b7677..6c57c7cf3 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -2305,6 +2305,7 @@ Pathfinder Options… Tùy chọn Pathfinder… Pathfinders: Pathfinder: Paths Đường dẫn + Path Length Độ dài đường dẫn Paths: {paths} Anchors: {anchors} Colors: {colors} Đường dẫn: {paths} Điểm neo: {anchors} Màu: {colors} Pattern Họa tiết Pattern Brush Options Tùy chọn cọ họa tiết diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 57f5ccc74..942a2880c 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -1936,6 +1936,7 @@ Pathfinder Options… 路径查找器选项… Pathfinders: 路径查找器: Paths 路径 + Path Length 路径长度 Paths: {paths} Anchors: {anchors} Colors: {colors} 路径:{paths} 锚点:{anchors} 颜色:{colors} Pattern 图案 Pattern Editing 图案编辑 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 04e700586..8d3a4b424 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -2026,6 +2026,7 @@ Pathfinder Options… 路徑管理員選項… Pathfinders: 路徑管理員: Paths 路徑 + Path Length 路徑長度 Paths: {paths} Anchors: {anchors} Colors: {colors} 路徑:{paths} 錨點:{anchors} 顏色:{colors} Pattern 圖樣 Pattern Editing 圖樣編輯 diff --git a/docs/mcp.md b/docs/mcp.md index d781ed463..77dd26fdb 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -2422,8 +2422,10 @@ result carries the same files as a zip (`{name: ".zip", dataBase64}`, entr `document.info {selectionOnly?, category?, format?: "text"}` adds `sections` (`[{id, title, rows: [[label, value]]}]`: document, objects, graphicStyles, spotColors, patterns, gradients, symbols, fonts, fontDetails, linkedImages, -embeddedImages); `format: "text"` returns the plain-text report Document Info › Save… (`docInfo.save {path?}`) and -the package report write. +embeddedImages) and `pathLength` (pt: the total length of the paths, compound paths' pieces included and guides left +out, which objects lists as Path Length in the document's units, say for a cut line or an LED strip along the letters); +`format: "text"` returns the plain-text report Document Info › Save… (`docInfo.save {path?}`) and the package report +write. ```json {"name":"run_command","arguments":{"command":"file.package","params":{"folder":"/tmp/handoff","copyFonts":false}}}