From a86ff7f177acca07bbad9de02fac1199339570ce Mon Sep 17 00:00:00 2001 From: "Ayberk A." <105879357+AyberkA0@users.noreply.github.com> Date: Thu, 15 Oct 2026 11:35:19 +0300 Subject: [PATCH] Document Info: Objects gives the paths' total length (#1958) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document Info › Objects counts the paths but didn't say how long they are, which sign and print work reads there (an LED strip along the letters, a cut line). `document.info` now adds up the length of every path it counts, the pieces of compound paths included and guides left out, and returns it as `pathLength` (pt); the Objects section shows it as Path Length in the document's units, right after the Paths count, so Selection Only gives the selected paths' length. The label is translated in the catalogs that cover the menus; pt-br only takes strings the UI itself shows. --- crates/engine/src/cmd/docinfo.rs | 46 +++++++++++++++++++++++++++-- crates/ui-egui/src/i18n/cs.tsv | 1 + crates/ui-egui/src/i18n/de.tsv | 1 + crates/ui-egui/src/i18n/es.tsv | 1 + crates/ui-egui/src/i18n/fr.tsv | 1 + crates/ui-egui/src/i18n/hu.tsv | 1 + crates/ui-egui/src/i18n/it.tsv | 1 + crates/ui-egui/src/i18n/ja.tsv | 1 + crates/ui-egui/src/i18n/ko.tsv | 1 + crates/ui-egui/src/i18n/pl.tsv | 1 + crates/ui-egui/src/i18n/ru.tsv | 1 + crates/ui-egui/src/i18n/uk.tsv | 1 + crates/ui-egui/src/i18n/vi.tsv | 1 + crates/ui-egui/src/i18n/zh-hans.tsv | 1 + crates/ui-egui/src/i18n/zh-hant.tsv | 1 + docs/mcp.md | 6 ++-- 16 files changed, 61 insertions(+), 5 deletions(-) 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}}}