diff --git a/crates/engine/src/cmd/fileio/action_batch.rs b/crates/engine/src/cmd/fileio/action_batch.rs index 7e757eb19..90856aaa4 100644 --- a/crates/engine/src/cmd/fileio/action_batch.rs +++ b/crates/engine/src/cmd/fileio/action_batch.rs @@ -56,7 +56,13 @@ pub(super) fn action_batch(s: &mut Session, p: &Value) -> Result { return Err(bad(C, "batches cannot nest")); } if find_command(id).is_none() { - return Err(bad(C, format!("commands[{i}]: unknown command `{id}`"))); + return Err(bad( + C, + match super::super::params::nearest_command(id) { + Some(near) => format!("commands[{i}]: unknown command `{id}`; did you mean `{near}`?"), + None => format!("commands[{i}]: unknown command `{id}`"), + }, + )); } } let source = str_param(p, "source").unwrap_or("folder"); diff --git a/crates/engine/src/cmd/params.rs b/crates/engine/src/cmd/params.rs index 1c8ba5ffc..875721b92 100644 --- a/crates/engine/src/cmd/params.rs +++ b/crates/engine/src/cmd/params.rs @@ -20,7 +20,7 @@ use serde_json::Value; -use super::{bad, find_command}; +use super::{bad, command_specs, find_command}; use crate::Result; /// What a params description says about the keys of the params object. @@ -208,8 +208,12 @@ fn distance(a: &str, b: &str) -> usize { /// The key of `keys` a misspelt `key` most likely meant: the nearest one, when it is near. fn nearest<'a>(key: &str, keys: &[&'a str]) -> Option<&'a str> { - let near = keys.iter().map(|k| (distance(key, k), *k)).min()?; - (near.0 <= (key.chars().count() / 3).max(1)).then_some(near.1) + let len = key.chars().count(); + let most = (len / 3).max(1); + // A key whose length differs by more than `most` is more than `most` edits away and isn't + // measured. + let near = keys.iter().filter(|k| k.chars().count().abs_diff(len) <= most).map(|k| (distance(key, k), *k)).min()?; + (near.0 <= most).then_some(near.1) } /// `params` has only keys the description `doc` of command `id` names, or the parameter error @@ -480,6 +484,21 @@ pub fn check_params(id: &str, params: &Value) -> Result<()> { Ok(()) } +/// The command id a misspelled `id`, which names no command, most likely meant: the nearest one, +/// when it is near (as [`check_keys`] matches a misspelled key). +pub(crate) fn nearest_command(id: &str) -> Option<&'static str> { + let ids: Vec<&'static str> = command_specs().iter().map(|c| c.id).collect(); + nearest(id, &ids) +} + +/// The error for `id`, which names no command: with the nearest command id, when one is near. +pub(crate) fn unknown_command(id: &str) -> crate::EngineError { + match nearest_command(id) { + Some(near) => crate::EngineError::UnknownCommandNear(id.to_string(), near.to_string()), + None => crate::EngineError::UnknownCommand(id.to_string()), + } +} + impl crate::Session { /// [`check_params`], and [`check_effect_params`] for the effects `effect.setParams` edits in /// this session's document (not as a step of a `command.batch`: what it edits is only there diff --git a/crates/engine/src/lib.rs b/crates/engine/src/lib.rs index 0854dcaab..1971d74a4 100644 --- a/crates/engine/src/lib.rs +++ b/crates/engine/src/lib.rs @@ -45,6 +45,9 @@ pub use vectorcraft_tools as tools; pub enum EngineError { #[error("unknown command `{0}`")] UnknownCommand(String), + /// An unknown command id, with the command id it most likely misspells. + #[error("unknown command `{0}`; did you mean `{1}`?")] + UnknownCommandNear(String, String), #[error("command `{0}` is not available right now: {1}")] Disabled(String, String), #[error("invalid parameters for `{cmd}`: {msg}")] @@ -1785,7 +1788,7 @@ impl Session { /// 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()))?; + let spec = find_command(id).ok_or_else(|| cmd::params::unknown_command(id))?; // The crate's own tests are the audit of the params descriptions (#1442): a key a test // passes that its command's description doesn't name fails the test. #[cfg(test)] diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index a96733cb4..5985eae96 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -90,6 +90,42 @@ fn unknown_and_disabled() { assert!(matches!(s.execute("object.group", &json!({})), Err(EngineError::Disabled(..)))); } +#[test] +fn unknown_command_names_the_nearest_id() { + let mut s = session(); + for typo in ["select.al", "Select.All", "selcet.all"] { + let e = s.execute(typo, &json!({})).unwrap_err(); + assert!(matches!(&e, EngineError::UnknownCommandNear(id, near) if id == typo && near == "select.all"), "{typo}: {e:?}"); + assert_eq!(e.to_string(), format!("unknown command `{typo}`; did you mean `select.all`?")); + } + let e = s.execute("nope", &json!({})).unwrap_err(); + assert!(matches!(&e, EngineError::UnknownCommand(id) if id == "nope"), "{e:?}"); + assert_eq!(e.to_string(), "unknown command `nope`"); + let e = s.execute("command.batch", &json!({"commands": [{"command": "select.al", "params": {}}]})).unwrap_err(); + assert!(e.to_string().contains("did you mean `select.all`?"), "{e}"); +} + +#[test] +fn a_long_unknown_command_id_is_answered_at_once() { + let mut s = session(); + let long = "x".repeat(200_000); + let start = std::time::Instant::now(); + assert!(matches!(s.execute(&long, &json!({})), Err(EngineError::UnknownCommand(_)))); + let e = crate::check_params("file.new", &json!({ long.as_str(): 1 })).unwrap_err(); + assert!(e.to_string().contains("the command takes:"), "{e}"); + assert!(start.elapsed() < std::time::Duration::from_secs(2), "{:?}", start.elapsed()); +} + +#[cfg(not(target_arch = "wasm32"))] +#[test] +fn action_batch_names_the_nearest_command_id() { + let mut s = session(); + let e = s.execute("action.batch", &json!({"source": "dataSets", "commands": [{"command": "select.al"}]})).unwrap_err(); + assert_eq!(e.to_string(), "invalid parameters for `action.batch`: commands[0]: unknown command `select.al`; did you mean `select.all`?"); + let e = s.execute("action.batch", &json!({"source": "dataSets", "commands": [{"command": "nope"}]})).unwrap_err(); + assert_eq!(e.to_string(), "invalid parameters for `action.batch`: commands[0]: unknown command `nope`"); +} + #[test] fn group_ungroup() { let mut s = session(); diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index b61613e80..edf2305a8 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -4224,6 +4224,7 @@ axis Both И двете @msg tool shortcuts must be a single key (optionally with Shift) клавишните комбинации за инструменти трябва да са един клавиш (по избор със Shift) @msg truncated съкратено @msg unknown command `{0}` непозната команда `{0}` +@msg unknown command `{0}`; did you mean `{1}`? непозната команда `{0}`; имахте ли предвид `{1}`? @msg unknown effect `{id}` непознат ефект `{id}` @msg unknown format непознат формат @msg unknown format `{f}` (Save writes {_1}) непознат формат `{f}` (Запазването записва {_1}) diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index f64f49519..36551d01e 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -4629,6 +4629,7 @@ imageTrace Outline Obrys @msg tool shortcuts must be a single key (optionally with Shift) zkratky nástrojů musí být jediná klávesa (volitelně se Shift) @msg truncated zkráceno @msg unknown command `{0}` neznámý příkaz `{0}` +@msg unknown command `{0}`; did you mean `{1}`? neznámý příkaz `{0}`; mysleli jste `{1}`? @msg unknown effect `{id}` neznámý efekt `{id}` @msg unknown format neznámý formát @msg unknown format `{f}` (Save writes {_1}) neznámý formát `{f}` (Uložit zapisuje {_1}) diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index e33f3735e..c52993ccc 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -4324,6 +4324,7 @@ imageTrace Outline Kontur @msg tool shortcuts must be a single key (optionally with Shift) værktøjsgenveje skal være en enkelt tast (eventuelt med Skift) @msg truncated afkortet @msg unknown command `{0}` ukendt kommando `{0}` +@msg unknown command `{0}`; did you mean `{1}`? ukendt kommando `{0}`; mente du `{1}`? @msg unknown effect `{id}` ukendt effekt `{id}` @msg unknown format ukendt format @msg unknown format `{f}` (Save writes {_1}) ukendt format `{f}` (Gem skriver {_1}) diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index 4ff3f922f..c6c453727 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -4252,6 +4252,7 @@ theme Appearance Erscheinungsbild @msg tool shortcuts must be a single key (optionally with Shift) Tastaturbefehle für Werkzeuge müssen aus einer einzelnen Taste bestehen (optional mit Shift) @msg truncated abgeschnitten @msg unknown command `{0}` unbekannter Befehl `{0}` +@msg unknown command `{0}`; did you mean `{1}`? unbekannter Befehl `{0}`; meinten Sie `{1}`? @msg unknown effect `{id}` unbekannter Effekt `{id}` @msg unknown format unbekanntes Format @msg unknown format `{f}` (Save writes {_1}) unbekanntes Format `{f}` („Speichern“ schreibt {_1}) diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 566078a29..54ba403fa 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -4300,6 +4300,7 @@ theme Appearance Εμφάνιση @msg tool shortcuts must be a single key (optionally with Shift) οι συντομεύσεις εργαλείων πρέπει να περιλαμβάνουν ένα πλήκτρο (προαιρετικά με Shift) @msg truncated περικομμένο @msg unknown command `{0}` άγνωστη εντολή `{0}` +@msg unknown command `{0}`; did you mean `{1}`? άγνωστη εντολή `{0}`· μήπως εννοείτε `{1}`; @msg unknown effect `{id}` άγνωστο εφέ `{id}` @msg unknown format άγνωστη μορφή @msg unknown format `{f}` (Save writes {_1}) άγνωστη μορφή `{f}` (η Αποθήκευση υποστηρίζει {_1}) diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 6f9649671..6a00b860b 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -4327,6 +4327,7 @@ axis Both Ambos @msg tool shortcuts must be a single key (optionally with Shift) los atajos de herramientas deben ser una sola tecla (opcionalmente con Shift) @msg truncated truncado @msg unknown command `{0}` comando desconocido `{0}` +@msg unknown command `{0}`; did you mean `{1}`? comando desconocido `{0}`; ¿quiso decir `{1}`? @msg unknown effect `{id}` efecto desconocido `{id}` @msg unknown format formato desconocido @msg unknown format `{f}` (Save writes {_1}) formato desconocido `{f}` (Guardar escribe {_1}) diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 0e277db8e..d43c31186 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -4536,6 +4536,7 @@ imageTrace Outline Ääriviiva @msg tool shortcuts must be a single key (optionally with Shift) työkalujen pikanäppäinten on oltava yksittäinen näppäin (valinnaisesti Vaihto-näppäimen kanssa) @msg truncated katkaistu @msg unknown command `{0}` tuntematon komento `{0}` +@msg unknown command `{0}`; did you mean `{1}`? tuntematon komento `{0}`; tarkoititko `{1}`? @msg unknown effect `{id}` tuntematon tehoste `{id}` @msg unknown format tuntematon muoto @msg unknown format `{f}` (Save writes {_1}) tuntematon muoto `{f}` (Tallenna kirjoittaa muotoja {_1}) diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 76e7626f6..d343f4721 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -4324,6 +4324,7 @@ axis Both Les deux @msg tool shortcuts must be a single key (optionally with Shift) les raccourcis d’outils doivent être une seule touche (éventuellement avec Maj) @msg truncated tronqué @msg unknown command `{0}` commande inconnue `{0}` +@msg unknown command `{0}`; did you mean `{1}`? commande inconnue `{0}` ; vouliez-vous dire `{1}` ? @msg unknown effect `{id}` effet inconnu `{id}` @msg unknown format format inconnu @msg unknown format `{f}` (Save writes {_1}) format inconnu `{f}` (Enregistrer écrit {_1}) diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index eb7dfa404..d1ae6c603 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -5075,6 +5075,7 @@ imageTrace Outline Körvonal @msg truncated csonka @msg Unembedded to {_1} Beágyazás megszüntetve, ide: {_1} @msg unknown command `{0}` ismeretlen parancs: `{0}` +@msg unknown command `{0}`; did you mean `{1}`? ismeretlen parancs: `{0}`; erre gondolt: `{1}`? @msg unknown effect `{id}` ismeretlen effektus: `{id}` @msg unknown format ismeretlen formátum @msg unknown format `{f}` (Save writes {_1}) ismeretlen formátum: `{f}` (a Mentés ezeket írja: {_1}) diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index a6bfdb0d5..27694d65d 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -4324,6 +4324,7 @@ imageTrace Outline Kontur @msg tool shortcuts must be a single key (optionally with Shift) pintasan alat harus satu tombol (opsional dengan Shift) @msg truncated terpotong @msg unknown command `{0}` perintah `{0}` tidak dikenal +@msg unknown command `{0}`; did you mean `{1}`? perintah `{0}` tidak dikenal; apakah maksud Anda `{1}`? @msg unknown effect `{id}` efek `{id}` tidak dikenal @msg unknown format format tidak dikenal @msg unknown format `{f}` (Save writes {_1}) format `{f}` tidak dikenal (Simpan menulis {_1}) diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 9c4ddf9e2..adf401328 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -4367,6 +4367,7 @@ axis Both Entrambi @msg tool shortcuts must be a single key (optionally with Shift) le scelte rapide degli strumenti devono essere un singolo tasto (eventualmente con Shift) @msg truncated troncato @msg unknown command `{0}` comando sconosciuto `{0}` +@msg unknown command `{0}`; did you mean `{1}`? comando sconosciuto `{0}`; forse intendevate `{1}`? @msg unknown effect `{id}` effetto sconosciuto `{id}` @msg unknown format formato sconosciuto @msg unknown format `{f}` (Save writes {_1}) formato sconosciuto `{f}` (Salva scrive {_1}) diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index d1f9fc62e..cda3dc030 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -4190,6 +4190,7 @@ swatch Bright Violet ビビッドバイオレット @msg objects can't be nested more than 32 deep オブジェクトは 32 階層より深く入れ子にできません @msg the SVG's elements are nested more than {0} deep SVG の要素が {0} 階層より深く入れ子になっています @msg unknown command `{0}` `{0}` は不明なコマンドです +@msg unknown command `{0}`; did you mean `{1}`? `{0}` は不明なコマンドです。`{1}` のことですか? @msg `{what}` closes nothing `{what}` に対応する開始部分がありません @msg `{what}` closes something it didn't open `{what}` が対応しない開始部分を閉じています @msg a path has too many points ポイントが多すぎるパスがあります diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 62ab638f3..1a5a9f2bb 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -4089,6 +4089,7 @@ font-technology Variable ცვლადი @msg tool shortcuts must be a single key (optionally with Shift) ხელსაწყოს მალსახმობი ერთი კლავიში უნდა იყოს (სურვილისამებრ Shift-ით) @msg truncated შეკვეცილია @msg unknown command `{0}` უცნობი ბრძანება `{0}` +@msg unknown command `{0}`; did you mean `{1}`? უცნობი ბრძანება `{0}`; იქნებ `{1}` იგულისხმეთ? @msg unknown effect `{id}` უცნობი ეფექტი `{id}` @msg unknown format უცნობი ფორმატი @msg unknown format `{f}` (Save writes {_1}) უცნობი ფორმატი `{f}` (შენახვა წერს: {_1}) diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 1e3bf00e7..571a658f6 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -4122,6 +4122,7 @@ theme Appearance 외관 @msg objects can't be nested more than 32 deep 개체는 32단계보다 깊게 중첩할 수 없습니다 @msg the SVG's elements are nested more than {0} deep SVG 요소가 {0}단계보다 깊게 중첩되어 있습니다 @msg unknown command `{0}` 알 수 없는 명령 `{0}` +@msg unknown command `{0}`; did you mean `{1}`? 알 수 없는 명령 `{0}`: `{1}`을(를) 의미하셨습니까? @msg `{what}` closes nothing `{what}`이(가) 닫는 항목이 없습니다 @msg `{what}` closes something it didn't open `{what}`이(가) 열지 않은 항목을 닫습니다 @msg a path has too many points 패스의 점이 너무 많습니다 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 9eb141055..204123ee6 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -4336,6 +4336,7 @@ imageTrace Outline Contour @msg tool shortcuts must be a single key (optionally with Shift) gereedschapsneltoetsen moeten uit één toets bestaan (eventueel met Shift) @msg truncated afgekapt @msg unknown command `{0}` onbekende opdracht `{0}` +@msg unknown command `{0}`; did you mean `{1}`? onbekende opdracht `{0}`; bedoelde je `{1}`? @msg unknown effect `{id}` onbekend effect `{id}` @msg unknown format onbekende indeling @msg unknown format `{f}` (Save writes {_1}) onbekende indeling `{f}` (Opslaan schrijft {_1}) diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 1941bc050..5a6e7a0f4 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -4454,6 +4454,7 @@ imageTrace Outline Kontur @msg tool shortcuts must be a single key (optionally with Shift) skróty narzędzi muszą być pojedynczym klawiszem (opcjonalnie z Shift) @msg truncated obcięty @msg unknown command `{0}` nieznane polecenie `{0}` +@msg unknown command `{0}`; did you mean `{1}`? nieznane polecenie `{0}`; czy chodziło o `{1}`? @msg unknown effect `{id}` nieznany efekt `{id}` @msg unknown format nieznany format @msg unknown format `{f}` (Save writes {_1}) nieznany format `{f}` (zapis tworzy {_1}) diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 19f0f442d..99cec1c41 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -3900,6 +3900,7 @@ axis Both Ambos @msg tool shortcuts must be a single key (optionally with Shift) os atalhos de ferramenta devem ser uma única tecla (opcionalmente com Shift) @msg truncated truncado @msg unknown command `{0}` comando desconhecido `{0}` +@msg unknown command `{0}`; did you mean `{1}`? comando desconhecido `{0}`; você quis dizer `{1}`? @msg unknown effect `{id}` efeito desconhecido `{id}` @msg unknown format formato desconhecido @msg unknown format `{f}` (Save writes {_1}) formato desconhecido `{f}` (Salvar grava {_1}) diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index e465f2a32..2d9f320cd 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -4363,6 +4363,7 @@ axis Both Оба @msg tool shortcuts must be a single key (optionally with Shift) сочетания инструментов должны быть одной клавишей (необязательно с Shift) @msg truncated усечено @msg unknown command `{0}` неизвестная команда `{0}` +@msg unknown command `{0}`; did you mean `{1}`? неизвестная команда `{0}`; возможно, имелась в виду `{1}`? @msg unknown effect `{id}` неизвестный эффект `{id}` @msg unknown format неизвестный формат @msg unknown format `{f}` (Save writes {_1}) неизвестный формат `{f}` (сохранение записывает {_1}) diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 03ad0ddd7..b2a92188a 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -4236,6 +4236,7 @@ axis Both Båda @msg tool shortcuts must be a single key (optionally with Shift) kortkommandon för verktyg måste vara en enda tangent (eventuellt med Shift) @msg truncated avkortad @msg unknown command `{0}` okänt kommando `{0}` +@msg unknown command `{0}`; did you mean `{1}`? okänt kommando `{0}`; menade du `{1}`? @msg unknown effect `{id}` okänd effekt `{id}` @msg unknown format okänt format @msg unknown format `{f}` (Save writes {_1}) okänt format `{f}` (Spara skriver {_1}) diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index ed0514462..415a35fa6 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -4088,6 +4088,7 @@ axis Both Her İkisi @msg tool shortcuts must be a single key (optionally with Shift) araç kısayolları tek tuş olmalıdır (isteğe bağlı olarak Shift ile) @msg truncated kesik @msg unknown command `{0}` bilinmeyen komut `{0}` +@msg unknown command `{0}`; did you mean `{1}`? bilinmeyen komut `{0}`; `{1}` mi demek istediniz? @msg unknown effect `{id}` bilinmeyen etki `{id}` @msg unknown format bilinmeyen format @msg unknown format `{f}` (Save writes {_1}) bilinmeyen format `{f}` (Kaydet, {_1} yazar) diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 40ea0ac69..fec966049 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -4351,6 +4351,7 @@ axis Both Обидві @msg tool shortcuts must be a single key (optionally with Shift) поєднання інструментів має бути однією клавішею (необов’язково з Shift) @msg truncated усічено @msg unknown command `{0}` невідома команда `{0}` +@msg unknown command `{0}`; did you mean `{1}`? невідома команда `{0}`; можливо, ви мали на увазі `{1}`? @msg unknown effect `{id}` невідомий ефект `{id}` @msg unknown format невідомий формат @msg unknown format `{f}` (Save writes {_1}) невідомий формат `{f}` (збереження записує {_1}) diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 858d3f049..80cf166e6 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -4730,6 +4730,7 @@ theme Appearance Giao diện @msg truncated bị cắt ngắn @msg Unembedded to {_1} Đã bỏ nhúng vào {_1} @msg unknown command `{0}` lệnh không xác định `{0}` +@msg unknown command `{0}`; did you mean `{1}`? lệnh không xác định `{0}`; ý bạn là `{1}`? @msg unknown effect `{id}` hiệu ứng không xác định `{id}` @msg unknown format định dạng không xác định @msg unknown format `{f}` (Save writes {_1}) định dạng không xác định `{f}` (Lưu ghi {_1}) diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index f2175fd33..b7f279d9d 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -3921,6 +3921,7 @@ imageTrace Outline 轮廓 @msg objects can't be nested more than 32 deep 对象的嵌套不能超过 32 层 @msg the SVG's elements are nested more than {0} deep SVG 的元素嵌套超过 {0} 层 @msg unknown command `{0}` 未知命令 `{0}` +@msg unknown command `{0}`; did you mean `{1}`? 未知命令 `{0}`;您是否想输入 `{1}`? @msg `{what}` closes nothing `{what}` 没有可结束的内容 @msg `{what}` closes something it didn't open `{what}` 结束了并非由它开始的内容 @msg a path has too many points 某条路径的点过多 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index d5b3857e6..62b7cdb91 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -1901,6 +1901,7 @@ file-filter Templates 範本 @msg objects can't be nested more than 32 deep 物件的巢狀層級不能超過 32 層 @msg the SVG's elements are nested more than {0} deep SVG 的元素巢狀超過 {0} 層 @msg unknown command `{0}` 未知的指令 `{0}` +@msg unknown command `{0}`; did you mean `{1}`? 未知的指令 `{0}`;您是指 `{1}` 嗎? @msg `{what}` closes nothing `{what}` 沒有可結束的內容 @msg `{what}` closes something it didn't open `{what}` 結束了並非由它開始的內容 @msg a path has too many points 有一條路徑的點過多 diff --git a/docs/mcp.md b/docs/mcp.md index b8a56499f..b737cd98f 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -1030,6 +1030,14 @@ of the format they write (one object can carry several formats' options). A comm (`document.setup`, `text.areaOptions`) says so the same way. The app's own journal isn't checked: an action or journal recorded by an older version replays as it did, except for an effect `color` that the effect can't read. +An unknown command id is matched the same way as an unknown parameter key: the error names the nearest command id when +one is near, ignoring case. A step of `command.batch` or `action.batch` gets the same suggestion in its step error: + +```json +{"id": "select.al"} +→ unknown command `select.al`; did you mean `select.all`? +``` + These Object menu commands refuse a string or another value that is not a number with `` `scaleH` must be a number, not "50" ``, naming the key, and change nothing: `scaleH`, `scaleV`, `moveH`, `moveV` and `rotate` in `object.transformEach`; `ppi` in `object.rasterize`; `width`, `height`, `spacingX` and `spacingY` in