From 8ce6177c624539dc5e6cf6fe03f27e43baff492b Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sat, 24 Oct 2026 17:58:08 +0700 Subject: [PATCH] Arrange: a layer id given to Send to Back and the other selection commands is refused Squashed from #3951 onto main. --- crates/engine/src/lib.rs | 21 ++++++ crates/engine/src/tests_select_ids_first.rs | 72 +++++++++++++++++++++ crates/ui-egui/src/i18n/cs.tsv | 2 + crates/ui-egui/src/i18n/de.tsv | 2 + crates/ui-egui/src/i18n/el.tsv | 2 + crates/ui-egui/src/i18n/es.tsv | 2 + crates/ui-egui/src/i18n/fi.tsv | 2 + crates/ui-egui/src/i18n/fr.tsv | 2 + crates/ui-egui/src/i18n/hu.tsv | 2 + crates/ui-egui/src/i18n/it.tsv | 2 + crates/ui-egui/src/i18n/ja.tsv | 2 + crates/ui-egui/src/i18n/ka.tsv | 2 + crates/ui-egui/src/i18n/ko.tsv | 2 + crates/ui-egui/src/i18n/pl.tsv | 2 + crates/ui-egui/src/i18n/pt-br.tsv | 2 + crates/ui-egui/src/i18n/ru.tsv | 2 + crates/ui-egui/src/i18n/sv.tsv | 2 + crates/ui-egui/src/i18n/tr.tsv | 2 + crates/ui-egui/src/i18n/uk.tsv | 2 + crates/ui-egui/src/i18n/vi.tsv | 2 + crates/ui-egui/src/i18n/zh-hans.tsv | 2 + crates/ui-egui/src/i18n/zh-hant.tsv | 2 + docs/mcp.md | 5 ++ 23 files changed, 138 insertions(+) diff --git a/crates/engine/src/lib.rs b/crates/engine/src/lib.rs index aa6fe3e54..c26f734ad 100644 --- a/crates/engine/src/lib.rs +++ b/crates/engine/src/lib.rs @@ -1753,6 +1753,24 @@ impl Session { r } + /// Error, under the command's own id, at the first of `ids` that is malformed, names no node, or + /// names a layer or sublayer: a command in [`SELECTS_GIVEN_IDS`] acts on objects. + fn check_given_ids(&self, id: &str, params: &Value) -> Result<()> { + let (Some(st), Some(ids)) = (self.active(), params.get("ids")) else { return Ok(()) }; + let Some(given) = ids.as_array() else { return cmd::checked_ids_param(self, params, "ids", id).map(drop) }; + for value in given { + let node = cmd::checked_id(self, value, id)?; + if st.doc.node(node).is_some_and(|n| n.is_layer()) { + return Err(if id.starts_with("object.arrange.") { + cmd::bad(id, format!("id {value} is a layer, not an object; move layers with layer.move")) + } else { + cmd::bad(id, format!("id {value} is a layer, not an object")) + }); + } + } + Ok(()) + } + /// Execute a command by id. This is THE entry point for every frontend. pub fn execute(&mut self, id: &str, params: &Value) -> Result { let spec = find_command(id).ok_or_else(|| EngineError::UnknownCommand(id.to_string()))?; @@ -1771,6 +1789,9 @@ impl Session { if cmd::params::id_stands_for_ids(spec.params) && !effect_named && self.active().is_some() { cmd::given_objects(self, params, id)?; } + if SELECTS_GIVEN_IDS.contains(&id) { + self.check_given_ids(id, params)?; + } // Clear's menu needs a selection; an agent supplying explicit targets only needs a // document. The command validates those targets before making any edit. let given = given_ids(spec.params, params); diff --git a/crates/engine/src/tests_select_ids_first.rs b/crates/engine/src/tests_select_ids_first.rs index 03d4ebd0b..3df8d37e6 100644 --- a/crates/engine/src/tests_select_ids_first.rs +++ b/crates/engine/src/tests_select_ids_first.rs @@ -143,6 +143,78 @@ fn bad_ids_are_refused_and_change_nothing() { } } +/// A layer or sublayer is not an object these commands act on: its id is refused, alone or with an +/// object's, and the document, the selection and the undo history stay as they were. +#[test] +fn layer_ids_are_refused_and_change_nothing() { + let (mut s, ids) = doc(); + let layer = s.execute("layer.new", &json!({"name": "Top"})).unwrap()["id"].as_u64().unwrap(); + let sub = s.execute("layer.newSublayer", &json!({"parent": layer})).unwrap()["id"].as_u64().unwrap(); + s.execute("select.set", &json!({"ids": [ids[3]]})).unwrap(); + let st = s.doc().unwrap(); + let (before, undo) = (st.doc.clone(), st.history.undo.len()); + let params = |cmd: &str| match cmd { + "edit.duplicate" => json!({"dx": 5, "dy": 5}), + "object.move" => json!({"dx": 12, "dy": -4}), + "object.rotate" => json!({"angle": 30}), + "object.scale" => json!({"sx": 150}), + "object.reflect" => json!({"axis": "vertical"}), + "object.shear" => json!({"angle": 20}), + _ => json!({}), + }; + for cmd in SELECTS_GIVEN_IDS { + for given in [json!([layer]), json!([sub]), json!([ids[0], layer])] { + let mut p = params(cmd); + p["ids"] = given.clone(); + let r = s.execute(cmd, &p); + let Err(EngineError::BadParams { msg, .. }) = &r else { panic!("{cmd} {given}: {r:?}") }; + assert!(msg.contains("is a layer, not an object"), "{cmd} {given}: {msg}"); + assert_eq!(msg.contains("layer.move"), cmd.starts_with("object.arrange."), "{cmd} {given}: {msg}"); + let st = s.doc().unwrap(); + assert!(st.doc == before, "{cmd} {given}: the document changed"); + assert_eq!(st.selection.objects, vec![NodeId(ids[3])], "{cmd} {given}: the selection stays"); + assert_eq!(st.history.undo.len(), undo, "{cmd} {given}: an undo step was recorded"); + } + } + // An unknown id before the layer's is still reported as unknown. + let r = s.execute("object.arrange.sendToBack", &json!({"ids": [999, layer]})); + assert!(matches!(&r, Err(EngineError::BadParams { msg, .. }) if msg == "no such object id 999"), "{r:?}"); +} + +/// An id that names no object is reported by the command that was run, not by the `select.set` +/// that checks the ids. +#[test] +fn id_errors_name_the_command_run() { + let (mut s, ids) = doc(); + let layer = s.execute("layer.new", &json!({"name": "Top"})).unwrap()["id"].as_u64().unwrap(); + s.execute("select.set", &json!({"ids": [ids[3]]})).unwrap(); + let before = s.doc().unwrap().doc.clone(); + for cmd in SELECTS_GIVEN_IDS { + for (given, want) in [ + (json!([999]), "no such object id 999".to_string()), + (json!([999, layer]), "no such object id 999".to_string()), + (json!([ids[0], ids[1], -1]), "invalid object id -1: expected a non-negative integer".to_string()), + (json!(ids[0]), "ids must be an array of non-negative integer object ids".to_string()), + ] { + let mut p = match *cmd { + "edit.duplicate" => json!({"dx": 5, "dy": 5}), + "object.move" => json!({"dx": 12, "dy": -4}), + "object.rotate" => json!({"angle": 30}), + "object.scale" => json!({"sx": 150}), + "object.reflect" => json!({"axis": "vertical"}), + "object.shear" => json!({"angle": 20}), + _ => json!({}), + }; + p["ids"] = given.clone(); + let r = s.execute(cmd, &p); + let Err(EngineError::BadParams { cmd: named, msg }) = &r else { panic!("{cmd} {given}: {r:?}") }; + assert_eq!((named.as_str(), msg), (*cmd, &want), "{cmd} {given}"); + assert!(s.doc().unwrap().doc == before, "{cmd} {given}: the document changed"); + assert_eq!(s.doc().unwrap().selection.objects, vec![NodeId(ids[3])], "{cmd} {given}: the selection stays"); + } + } +} + #[test] fn a_command_that_fails_after_selecting_its_ids_puts_the_selection_back() { let (mut s, ids) = doc(); diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 35523a55b..1f2320313 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -4770,6 +4770,8 @@ imageTrace Outline Obrys @msg {key} must be an array of non-negative integer object ids {key} musí být pole ID objektů, která jsou nezáporná celá čísla @msg invalid object id {value}: expected a non-negative integer neplatné ID objektu {value}: očekává se nezáporné celé číslo @msg no such object id {value} objekt s ID {value} neexistuje +@msg id {value} is a layer, not an object ID {value} je vrstva, nikoli objekt +@msg id {value} is a layer, not an object; move layers with layer.move ID {value} je vrstva, nikoli objekt; vrstvy přesunete pomocí layer.move @msg automation filesystem access is not granted: read authority is absent: {path} přístup automatizace k systému souborů není udělen: chybí oprávnění ke čtení: {path} @msg automation filesystem access is not granted: write authority is absent: {path} přístup automatizace k systému souborů není udělen: chybí oprávnění k zápisu: {path} @msg automation path rejected: outside the read root {root}: {path} cesta automatizace odmítnuta: mimo kořen pro čtení {root}: {path} diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index 7af235054..6262eb08d 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -4429,6 +4429,8 @@ theme Appearance Erscheinungsbild @msg {key} must be an array of non-negative integer object ids {key} muss ein Array von Objekt-IDs sein, die nicht negative ganze Zahlen sind @msg invalid object id {value}: expected a non-negative integer ungültige Objekt-ID {value}: erwartet wird eine nicht negative ganze Zahl @msg no such object id {value} kein Objekt mit der ID {value} +@msg id {value} is a layer, not an object die ID {value} ist eine Ebene, kein Objekt +@msg id {value} is a layer, not an object; move layers with layer.move die ID {value} ist eine Ebene, kein Objekt; verschieben Sie Ebenen mit layer.move @msg automation filesystem access is not granted: read authority is absent: {path} Dateisystemzugriff für die Automatisierung ist nicht gewährt: Die Leseberechtigung fehlt: {path} @msg automation filesystem access is not granted: write authority is absent: {path} Dateisystemzugriff für die Automatisierung ist nicht gewährt: Die Schreibberechtigung fehlt: {path} @msg automation path rejected: outside the read root {root}: {path} Automatisierungspfad abgelehnt: außerhalb des Lesestammordners {root}: {path} diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 70b097d7c..b8d50b100 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -4470,6 +4470,8 @@ theme Appearance Εμφάνιση @msg {key} must be an array of non-negative integer object ids {key}: πρέπει να είναι πίνακας αναγνωριστικών αντικειμένων που είναι μη αρνητικοί ακέραιοι @msg invalid object id {value}: expected a non-negative integer μη έγκυρο αναγνωριστικό αντικειμένου {value}: αναμένεται μη αρνητικός ακέραιος @msg no such object id {value} δεν υπάρχει αντικείμενο με αναγνωριστικό {value} +@msg id {value} is a layer, not an object το αναγνωριστικό {value} είναι επίπεδο, όχι αντικείμενο +@msg id {value} is a layer, not an object; move layers with layer.move το αναγνωριστικό {value} είναι επίπεδο, όχι αντικείμενο· μετακινήστε τα επίπεδα με το layer.move @msg automation filesystem access is not granted: read authority is absent: {path} δεν έχει επιτραπεί πρόσβαση αυτοματισμού στο σύστημα αρχείων: δεν υπάρχει δικαίωμα ανάγνωσης: {path} @msg automation filesystem access is not granted: write authority is absent: {path} δεν έχει επιτραπεί πρόσβαση αυτοματισμού στο σύστημα αρχείων: δεν υπάρχει δικαίωμα εγγραφής: {path} @msg automation path rejected: outside the read root {root}: {path} απορρίφθηκε η διαδρομή αυτοματισμού: εκτός ρίζας ανάγνωσης {root}: {path} diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 36fba6c20..26e1e0712 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -4491,6 +4491,8 @@ axis Both Ambos @msg {key} must be an array of non-negative integer object ids {key} debe ser una lista de identificadores de objeto que sean enteros no negativos @msg invalid object id {value}: expected a non-negative integer identificador de objeto no válido {value}: se esperaba un entero no negativo @msg no such object id {value} no existe el objeto con el identificador {value} +@msg id {value} is a layer, not an object el identificador {value} es una capa, no un objeto +@msg id {value} is a layer, not an object; move layers with layer.move el identificador {value} es una capa, no un objeto; mueva las capas con layer.move @msg automation filesystem access is not granted: read authority is absent: {path} la automatización no tiene acceso al sistema de archivos: falta el permiso de lectura: {path} @msg automation filesystem access is not granted: write authority is absent: {path} la automatización no tiene acceso al sistema de archivos: falta el permiso de escritura: {path} @msg automation path rejected: outside the read root {root}: {path} ruta de automatización rechazada: fuera de la carpeta raíz de lectura {root}: {path} diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 462114e75..004f41bc0 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -4677,6 +4677,8 @@ imageTrace Outline Ääriviiva @msg {key} must be an array of non-negative integer object ids {key} on oltava taulukko objektitunnuksia, jotka ovat ei-negatiivisia kokonaislukuja @msg invalid object id {value}: expected a non-negative integer virheellinen objektitunnus {value}: odotettiin ei-negatiivista kokonaislukua @msg no such object id {value} objektia tunnuksella {value} ei ole +@msg id {value} is a layer, not an object tunnus {value} on taso, ei objekti +@msg id {value} is a layer, not an object; move layers with layer.move tunnus {value} on taso, ei objekti; siirrä tasoja komennolla layer.move @msg automation filesystem access is not granted: read authority is absent: {path} automaation tiedostojärjestelmäkäyttöä ei ole myönnetty: lukuoikeus puuttuu: {path} @msg automation filesystem access is not granted: write authority is absent: {path} automaation tiedostojärjestelmäkäyttöä ei ole myönnetty: kirjoitusoikeus puuttuu: {path} @msg automation path rejected: outside the read root {root}: {path} automaation polku hylättiin: lukujuuren {root} ulkopuolella: {path} diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 80f0a0699..54c2b9102 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -4502,6 +4502,8 @@ axis Both Les deux @msg {key} must be an array of non-negative integer object ids {key} doit être un tableau d’identifiants d’objet, entiers positifs ou nuls @msg invalid object id {value}: expected a non-negative integer identifiant d’objet {value} non valide (un entier positif ou nul est attendu) @msg no such object id {value} aucun objet ne porte l’identifiant {value} +@msg id {value} is a layer, not an object l’identifiant {value} désigne un calque, pas un objet +@msg id {value} is a layer, not an object; move layers with layer.move l’identifiant {value} désigne un calque, pas un objet ; déplacez les calques avec layer.move @msg automation filesystem access is not granted: read authority is absent: {path} l’automatisation n’a pas accès au système de fichiers : aucune autorisation de lecture : {path} @msg automation filesystem access is not granted: write authority is absent: {path} l’automatisation n’a pas accès au système de fichiers : aucune autorisation d’écriture : {path} @msg automation path rejected: outside the read root {root}: {path} chemin d’automatisation refusé : hors du dossier racine de lecture {root} : {path} diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index e7e45cf15..38ad9d2ab 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -4849,6 +4849,8 @@ imageTrace Outline Körvonal @msg {key} must be an array of non-negative integer object ids {key}: objektumazonosítók tömbje kell, mindegyik nemnegatív egész szám @msg invalid object id {value}: expected a non-negative integer érvénytelen objektumazonosító: {value} (nemnegatív egész szám kell) @msg no such object id {value} nincs ilyen objektumazonosító: {value} +@msg id {value} is a layer, not an object a(z) {value} azonosító egy réteg, nem objektum +@msg id {value} is a layer, not an object; move layers with layer.move a(z) {value} azonosító egy réteg, nem objektum; a rétegeket a layer.move paranccsal helyezheti át @msg object {0} cannot have children ennek az objektumnak nem lehetnek gyermekei: {0} @msg object {id} is not a path az objektum nem útvonal: {id} @msg object {id} is not a selected top-level object az objektum nem kijelölt legfelső szintű objektum: {id} diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 0a8678bdd..b80f2b0bd 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -4531,6 +4531,8 @@ axis Both Entrambi @msg {key} must be an array of non-negative integer object ids {key} deve essere un array di ID oggetto interi non negativi @msg invalid object id {value}: expected a non-negative integer ID oggetto {value} non valido: è richiesto un intero non negativo @msg no such object id {value} nessun oggetto con ID {value} +@msg id {value} is a layer, not an object l’ID {value} è un livello, non un oggetto +@msg id {value} is a layer, not an object; move layers with layer.move l’ID {value} è un livello, non un oggetto; sposta i livelli con layer.move @msg automation filesystem access is not granted: read authority is absent: {path} l'automazione non ha accesso al file system: manca l'autorizzazione di lettura: {path} @msg automation filesystem access is not granted: write authority is absent: {path} l'automazione non ha accesso al file system: manca l'autorizzazione di scrittura: {path} @msg automation path rejected: outside the read root {root}: {path} percorso di automazione rifiutato: fuori dalla cartella radice di lettura {root}: {path} diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index daf1e2587..4458d7a63 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -4569,6 +4569,8 @@ swatch Bright Violet ビビッドバイオレット @msg {key} must be an array of non-negative integer object ids {key} にはオブジェクト ID (0 以上の整数) の配列を指定してください @msg invalid object id {value}: expected a non-negative integer オブジェクト ID {value} は正しくありません: 0 以上の整数を指定してください @msg no such object id {value} ID が {value} のオブジェクトは見つかりません +@msg id {value} is a layer, not an object ID {value} はオブジェクトではなくレイヤーです +@msg id {value} is a layer, not an object; move layers with layer.move ID {value} はオブジェクトではなくレイヤーです。レイヤーは layer.move で移動してください @msg automation filesystem access is not granted: read authority is absent: {path} 自動化にはファイルシステムへのアクセスが許可されていません: 読み込み権限がありません: {path} @msg automation filesystem access is not granted: write authority is absent: {path} 自動化にはファイルシステムへのアクセスが許可されていません: 書き込み権限がありません: {path} @msg automation path rejected: outside the read root {root}: {path} 自動化のパスを拒否しました: 読み込みルート {root} の外です: {path} diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index c0f789a43..86b587900 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -4218,6 +4218,8 @@ font-technology Variable ცვლადი @msg {key} must be an array of non-negative integer object ids {key} უნდა იყოს ობიექტების id-ების მასივი, სადაც ყოველი id არაუარყოფითი მთელი რიცხვია @msg invalid object id {value}: expected a non-negative integer ობიექტის არასწორი id {value}: მოსალოდნელია არაუარყოფითი მთელი რიცხვი @msg no such object id {value} ობიექტი id-ით {value} არ არსებობს +@msg id {value} is a layer, not an object id {value} შრეა და არა ობიექტი +@msg id {value} is a layer, not an object; move layers with layer.move id {value} შრეა და არა ობიექტი; შრეების გადასატანად გამოიყენეთ layer.move @msg automation filesystem access is not granted: read authority is absent: {path} ავტომატიზაციას ფაილურ სისტემაზე წვდომა არ აქვს: წაკითხვის უფლება არ არის: {path} @msg automation filesystem access is not granted: write authority is absent: {path} ავტომატიზაციას ფაილურ სისტემაზე წვდომა არ აქვს: ჩაწერის უფლება არ არის: {path} @msg automation path rejected: outside the read root {root}: {path} ავტომატიზაციის გზა უარყოფილია: წაკითხვის ძირის {root} გარეთაა: {path} diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 23318f6ed..8a0f2e3fd 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -4501,6 +4501,8 @@ theme Appearance 외관 @msg {key} must be an array of non-negative integer object ids {key}은(는) 음이 아닌 정수인 개체 id의 배열이어야 합니다 @msg invalid object id {value}: expected a non-negative integer 개체 id {value}이(가) 올바르지 않습니다: 음이 아닌 정수여야 합니다 @msg no such object id {value} id가 {value}인 개체가 없습니다 +@msg id {value} is a layer, not an object id {value}은(는) 개체가 아닌 레이어입니다 +@msg id {value} is a layer, not an object; move layers with layer.move id {value}은(는) 개체가 아닌 레이어입니다. 레이어는 layer.move로 이동하세요 @msg automation filesystem access is not granted: read authority is absent: {path} 자동화 파일 시스템 접근이 허용되지 않았습니다: 읽기 권한이 없습니다: {path} @msg automation filesystem access is not granted: write authority is absent: {path} 자동화 파일 시스템 접근이 허용되지 않았습니다: 쓰기 권한이 없습니다: {path} @msg automation path rejected: outside the read root {root}: {path} 자동화 경로가 거부되었습니다: 읽기 루트 {root} 밖입니다: {path} diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 2b918e31f..593c4fc04 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -4595,6 +4595,8 @@ imageTrace Outline Kontur @msg {key} must be an array of non-negative integer object ids {key} musi być tablicą identyfikatorów obiektów, które są nieujemnymi liczbami całkowitymi @msg invalid object id {value}: expected a non-negative integer nieprawidłowy identyfikator obiektu {value}: oczekiwano nieujemnej liczby całkowitej @msg no such object id {value} brak obiektu o identyfikatorze {value} +@msg id {value} is a layer, not an object identyfikator {value} oznacza warstwę, a nie obiekt +@msg id {value} is a layer, not an object; move layers with layer.move identyfikator {value} oznacza warstwę, a nie obiekt; warstwy przenosi się za pomocą layer.move @msg automation filesystem access is not granted: read authority is absent: {path} nie przyznano dostępu automatyzacji do systemu plików: brak uprawnień do odczytu: {path} @msg automation filesystem access is not granted: write authority is absent: {path} nie przyznano dostępu automatyzacji do systemu plików: brak uprawnień do zapisu: {path} @msg automation path rejected: outside the read root {root}: {path} odrzucono ścieżkę automatyzacji: poza katalogiem głównym odczytu {root}: {path} diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 1157f6868..68666a175 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -4036,6 +4036,8 @@ axis Both Ambos @msg {key} must be an array of non-negative integer object ids {key} deve ser uma matriz de ids de objeto que sejam inteiros não negativos @msg invalid object id {value}: expected a non-negative integer id de objeto inválido {value}: era esperado um inteiro não negativo @msg no such object id {value} não existe objeto com o id {value} +@msg id {value} is a layer, not an object o id {value} é uma camada, não um objeto +@msg id {value} is a layer, not an object; move layers with layer.move o id {value} é uma camada, não um objeto; mova camadas com layer.move @msg automation filesystem access is not granted: read authority is absent: {path} o acesso da automação ao sistema de arquivos não foi concedido: falta autorização de leitura: {path} @msg automation filesystem access is not granted: write authority is absent: {path} o acesso da automação ao sistema de arquivos não foi concedido: falta autorização de gravação: {path} @msg automation path rejected: outside the read root {root}: {path} caminho da automação rejeitado: fora da raiz de leitura {root}: {path} diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 907f458c4..e97d50df9 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -4529,6 +4529,8 @@ axis Both Оба @msg {key} must be an array of non-negative integer object ids {key} должно быть массивом идентификаторов объектов, которые являются неотрицательными целыми числами @msg invalid object id {value}: expected a non-negative integer недопустимый идентификатор объекта {value}: ожидается неотрицательное целое число @msg no such object id {value} объект с идентификатором {value} не существует +@msg id {value} is a layer, not an object идентификатор {value} относится к слою, а не к объекту +@msg id {value} is a layer, not an object; move layers with layer.move идентификатор {value} относится к слою, а не к объекту; перемещайте слои с помощью layer.move @msg automation filesystem access is not granted: read authority is absent: {path} у автоматизации нет доступа к файловой системе: нет права на чтение: {path} @msg automation filesystem access is not granted: write authority is absent: {path} у автоматизации нет доступа к файловой системе: нет права на запись: {path} @msg automation path rejected: outside the read root {root}: {path} путь автоматизации отклонён: вне корневой папки для чтения {root}: {path} diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index c493195b5..5af11984a 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -4412,6 +4412,8 @@ axis Both Båda @msg {key} must be an array of non-negative integer object ids {key} måste vara en array med objekt-id:n som är icke-negativa heltal @msg invalid object id {value}: expected a non-negative integer ogiltigt objekt-id {value}: ett icke-negativt heltal förväntades @msg no such object id {value} det finns inget objekt med id {value} +@msg id {value} is a layer, not an object id {value} är ett lager, inte ett objekt +@msg id {value} is a layer, not an object; move layers with layer.move id {value} är ett lager, inte ett objekt; flytta lager med layer.move @msg automation filesystem access is not granted: read authority is absent: {path} automatiseringen har inte fått åtkomst till filsystemet: läsbehörighet saknas: {path} @msg automation filesystem access is not granted: write authority is absent: {path} automatiseringen har inte fått åtkomst till filsystemet: skrivbehörighet saknas: {path} @msg automation path rejected: outside the read root {root}: {path} automatiseringssökvägen avvisades: utanför läsroten {root}: {path} diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index 719fb0ca4..2b39485c9 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -5201,6 +5201,8 @@ theme Appearance Görünüm @msg {key} must be an array of non-negative integer object ids {key}, negatif olmayan tam sayı nesne kimlikleri dizisi olmalıdır @msg invalid object id {value}: expected a non-negative integer geçersiz nesne kimliği {value}: negatif olmayan bir tam sayı bekleniyordu @msg no such object id {value} böyle bir nesne kimliği yok: {value} +@msg id {value} is a layer, not an object {value} kimliği bir katmana ait, bir nesneye değil +@msg id {value} is a layer, not an object; move layers with layer.move {value} kimliği bir katmana ait, bir nesneye değil; katmanları layer.move ile taşıyın @msg {key} must be Unix seconds (an integer) or null {key}, Unix saniyesi (bir tam sayı) veya null olmalıdır @msg its zlib compression is damaged zlib sıkıştırması hasarlı @msg its Zstandard compression is damaged Zstandard sıkıştırması hasarlı diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 05bd282b1..f889d0984 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -4515,6 +4515,8 @@ axis Both Обидві @msg {key} must be an array of non-negative integer object ids {key} має бути масивом ідентифікаторів об’єктів, які є невід’ємними цілими числами @msg invalid object id {value}: expected a non-negative integer неприпустимий ідентифікатор об’єкта {value}: очікується невід’ємне ціле число @msg no such object id {value} об’єкт з ідентифікатором {value} не існує +@msg id {value} is a layer, not an object ідентифікатор {value} належить шару, а не об’єкту +@msg id {value} is a layer, not an object; move layers with layer.move ідентифікатор {value} належить шару, а не об’єкту; переміщуйте шари за допомогою layer.move @msg automation filesystem access is not granted: read authority is absent: {path} автоматизація не має доступу до файлової системи: немає права на читання: {path} @msg automation filesystem access is not granted: write authority is absent: {path} автоматизація не має доступу до файлової системи: немає права на запис: {path} @msg automation path rejected: outside the read root {root}: {path} шлях автоматизації відхилено: поза кореневою папкою для читання {root}: {path} diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index ad1c84997..9b6c1e8ba 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -4498,6 +4498,8 @@ theme Appearance Giao diện @msg {key} must be an array of non-negative integer object ids {key} phải là một mảng id đối tượng là số nguyên không âm @msg invalid object id {value}: expected a non-negative integer id đối tượng {value} không hợp lệ: cần một số nguyên không âm @msg no such object id {value} không có đối tượng nào có id {value} +@msg id {value} is a layer, not an object id {value} là một lớp, không phải đối tượng +@msg id {value} is a layer, not an object; move layers with layer.move id {value} là một lớp, không phải đối tượng; hãy di chuyển lớp bằng layer.move @msg object {0} cannot have children đối tượng {0} không thể có phần tử con @msg object {id} is not a path đối tượng {id} không phải là đường dẫn @msg object {id} is not a selected top-level object đối tượng {id} không phải là đối tượng cấp cao nhất đã chọn diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 1ab5c4669..e19751cd4 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -4288,6 +4288,8 @@ imageTrace Outline 轮廓 @msg {key} must be an array of non-negative integer object ids {key} 必须是由非负整数对象 id 组成的数组 @msg invalid object id {value}: expected a non-negative integer 无效的对象 id {value}:应为非负整数 @msg no such object id {value} 没有 id 为 {value} 的对象 +@msg id {value} is a layer, not an object id {value} 是图层,不是对象 +@msg id {value} is a layer, not an object; move layers with layer.move id {value} 是图层,不是对象;请使用 layer.move 移动图层 @msg automation filesystem access is not granted: read authority is absent: {path} 未授予自动化文件系统访问权限:缺少读取权限:{path} @msg automation filesystem access is not granted: write authority is absent: {path} 未授予自动化文件系统访问权限:缺少写入权限:{path} @msg automation path rejected: outside the read root {root}: {path} 已拒绝自动化路径:位于读取根目录 {root} 之外:{path} diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 95cab4a89..4a9057aa5 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -5052,6 +5052,8 @@ lighting Light 光源 @msg {key} must be an array of non-negative integer object ids {key} 必須是由非負整數物件 id 組成的陣列 @msg invalid object id {value}: expected a non-negative integer 無效的物件 id {value}:應為非負整數 @msg no such object id {value} 沒有 id 為 {value} 的物件 +@msg id {value} is a layer, not an object id {value} 是圖層,不是物件 +@msg id {value} is a layer, not an object; move layers with layer.move id {value} 是圖層,不是物件;請使用 layer.move 移動圖層 Move Anchor Point 移動錨點 @msg {label} keeps 1 of the document's {n} artboards: the file reopens with one. Turn on Preserve Editing Capabilities to keep them all. {label} 只保留文件 {n} 個工作區域中的 1 個:檔案重新開啟時只有一個。開啟「保留編輯功能」可全部保留。 Chalk & Charcoal… 粉筆和炭筆… diff --git a/docs/mcp.md b/docs/mcp.md index fccffb8db..3dba64fc9 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -347,6 +347,11 @@ currently describes them in prose, so MCP does not guess schemas or silently rem Coordinates are points in document space: y points down, the origin is the first artboard's top-left, and a new document is 612 × 792 (US Letter). New objects become the selection. Most commands act on the selection or on +explicit `ids`. A command that leaves out an object selected inside a selected group also leaves it out when `ids` +list it together with a group that holds it. The commands that select their `ids` first (`object.group`, the +`object.arrange.*` commands, `object.move`, the Pathfinder commands and the others like them) refuse an id that names a +layer or sublayer, names no object or is not a non-negative integer, with an error that names the command that was run, +and leave the document and the selection unchanged; `layer.move` reorders layers. explicit `ids`, which stand in for the selection, so they work with nothing selected. Where a command's params say `ids?|id?` (or `id?, ids?: … (instead of id)`), `id` is `ids` of one object: `{"id": 7}` does what `{"ids": [7]}` does, with or without a selection, and an `id` or `ids` that is malformed (not a non-negative integer) or names no