From 9b2410d5f9cf5c906d53372483e27cba484428d8 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Wed, 11 Nov 2026 01:37:40 -0800 Subject: [PATCH] Script Console: report lines match script.console, counts of one are singular, every run ends - The panel's report line gives a run without a clock as "time unavailable", as script.console does, instead of "? ms", and shows the slowest commands after "slowest:" as script.console does. - "1 host call", "1 earlier line dropped" and "1 line cut" take the singular in the panel and in script.console, and each catalog gives its language's plural forms. The dropped and cut counts choose their forms independently. - A run whose state is gone still gets an end line: "stopped" when it is abandoned, "internal" when the next slice finds it missing. Neither adds a report line. The missing-run path in script_pump now also puts the session's state back, as script_abandon does, so the next run can start. --- crates/engine/src/script/console.rs | 3 +- crates/engine/src/script/mod.rs | 50 ++++++++++++++----- crates/engine/src/tests/script_console.rs | 49 ++++++++++++++++++ crates/ui-egui/src/i18n/bg.tsv | 10 +++- crates/ui-egui/src/i18n/bs.tsv | 10 +++- crates/ui-egui/src/i18n/ca.tsv | 10 +++- crates/ui-egui/src/i18n/cs.tsv | 10 +++- crates/ui-egui/src/i18n/da.tsv | 10 +++- crates/ui-egui/src/i18n/de.tsv | 10 +++- crates/ui-egui/src/i18n/el.tsv | 10 +++- crates/ui-egui/src/i18n/es.tsv | 10 +++- crates/ui-egui/src/i18n/fi.tsv | 10 +++- crates/ui-egui/src/i18n/fr.tsv | 10 +++- crates/ui-egui/src/i18n/hi.tsv | 10 +++- crates/ui-egui/src/i18n/hu.tsv | 10 +++- crates/ui-egui/src/i18n/id.tsv | 10 +++- crates/ui-egui/src/i18n/it.tsv | 10 +++- crates/ui-egui/src/i18n/ja.tsv | 10 +++- crates/ui-egui/src/i18n/ka.tsv | 10 +++- crates/ui-egui/src/i18n/ko.tsv | 10 +++- crates/ui-egui/src/i18n/nl.tsv | 10 +++- crates/ui-egui/src/i18n/pl.tsv | 10 +++- crates/ui-egui/src/i18n/pt-br.tsv | 10 +++- crates/ui-egui/src/i18n/ru.tsv | 10 +++- crates/ui-egui/src/i18n/sv.tsv | 10 +++- crates/ui-egui/src/i18n/tests.rs | 18 +++++++ crates/ui-egui/src/i18n/tr.tsv | 10 +++- crates/ui-egui/src/i18n/uk.tsv | 10 +++- crates/ui-egui/src/i18n/vi.tsv | 10 +++- crates/ui-egui/src/i18n/zh-hans.tsv | 10 +++- crates/ui-egui/src/i18n/zh-hant.tsv | 10 +++- crates/ui-egui/src/panels/script_console.rs | 23 ++++++--- .../src/panels/tests_script_console.rs | 47 ++++++++++++++++- docs/mcp.md | 7 ++- docs/target-app-parity.md | 1 + 35 files changed, 390 insertions(+), 78 deletions(-) diff --git a/crates/engine/src/script/console.rs b/crates/engine/src/script/console.rs index eda6feeb4..f93356619 100644 --- a/crates/engine/src/script/console.rs +++ b/crates/engine/src/script/console.rs @@ -106,7 +106,8 @@ impl Entry { Entry::End(e) => format!("ended: {}", e.id()), Entry::Report { ms, host_calls, slowest } => { let time = ms.map_or_else(|| "time unavailable".to_string(), |ms| format!("{ms} ms")); - let mut s = format!("{time}, {host_calls} host calls"); + let calls = if *host_calls == 1 { "host call" } else { "host calls" }; + let mut s = format!("{time}, {host_calls} {calls}"); if !slowest.is_empty() { let list: Vec = slowest.iter().map(|c| format!("{} ×{} {} ms", c.id, c.calls, c.total_ms)).collect(); s.push_str("; slowest: "); diff --git a/crates/engine/src/script/mod.rs b/crates/engine/src/script/mod.rs index f2e4cc5ba..d06c2699d 100644 --- a/crates/engine/src/script/mod.rs +++ b/crates/engine/src/script/mod.rs @@ -158,21 +158,27 @@ thread_local! { static NEXT_JOB: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1); /// A session's hold on its running job: while one exists the lease is held. Dropping it ends the job. +/// It keeps the run's number and its name as console lines give it, so the run's console entry can +/// end when the job is gone. #[derive(Debug)] -pub struct JobKey(u64); +pub struct JobKey { + id: u64, + run: u64, + name: Arc, +} impl Drop for JobKey { fn drop(&mut self) { let _ = JOBS.try_with(|jobs| { if let Ok(mut jobs) = jobs.try_borrow_mut() { - jobs.remove(&self.0); + jobs.remove(&self.id); } }); } } fn with_job(key: &JobKey, f: impl FnOnce(&mut Job) -> T) -> Option { - JOBS.with(|jobs| jobs.borrow_mut().get_mut(&key.0).map(f)) + JOBS.with(|jobs| jobs.borrow_mut().get_mut(&key.id).map(f)) } /// The state a script changes that a rollback puts back. @@ -1195,12 +1201,8 @@ impl Session { /// ([`Self::script_report`]). False with none running. pub fn script_abandon(&mut self) -> bool { let Some(key) = self.script_key.take() else { return false }; - let Some(job) = JOBS.with(|jobs| jobs.borrow_mut().remove(&key.0)) else { - drop(key); - raise_ids(self); - self.script_stop.clear(); - self.reset_tool(); - cmd::compositefonts::sync(self); + let Some(job) = JOBS.with(|jobs| jobs.borrow_mut().remove(&key.id)) else { + self.script_gone(key, console::Ending::Stopped); return true; }; drop(key); @@ -1210,6 +1212,19 @@ impl Session { true } + /// Ends the run whose job is no longer held: its console entry ends with `ending`, with no + /// report line, since its time and host calls went with the job, and the session's state is + /// put back as at the end of any run. + fn script_gone(&mut self, key: JobKey, ending: console::Ending) { + let line = console::ConsoleLine { run: key.run, name: key.name.clone(), entry: console::Entry::End(ending) }; + self.script_console.push(line, false); + drop(key); + raise_ids(self); + self.script_stop.clear(); + self.reset_tool(); + cmd::compositefonts::sync(self); + } + /// A script can't start while a document holds a drag in progress or an undo group, which its /// one undo step could not take in. fn settle_for_script(&mut self) -> Result<()> { @@ -1298,10 +1313,11 @@ impl Session { return Err(EngineError::Other(message)); } let scope = crate::file_access::ScopeHandle::capture(); + let (run, line_name) = (host.run, host.name.clone()); let job = Job { realm, host, world: World::working(self), start_uids: open, name: name.clone(), scope }; let id = NEXT_JOB.fetch_add(1, std::sync::atomic::Ordering::Relaxed); JOBS.with(|jobs| jobs.borrow_mut().insert(id, job)); - self.script_key = Some(JobKey(id)); + self.script_key = Some(JobKey { id, run, name: line_name }); Ok(name) } @@ -1309,11 +1325,12 @@ impl Session { /// run has ended: its report, or the error that ended it, with the documents put back. pub fn script_pump(&mut self) -> Option> { let key = self.script_key.take()?; - let Some(mut job) = JOBS.with(|jobs| jobs.borrow_mut().remove(&key.0)) else { + let Some(mut job) = JOBS.with(|jobs| jobs.borrow_mut().remove(&key.id)) else { + self.script_gone(key, console::Ending::Internal); return Some(Err(EngineError::Other(JOB_GONE.to_string()))); }; if job.host.waiting.get() && !self.script_stop.is_set() { - JOBS.with(|jobs| jobs.borrow_mut().insert(key.0, job)); + JOBS.with(|jobs| jobs.borrow_mut().insert(key.id, job)); self.script_key = Some(key); return None; } @@ -1329,7 +1346,7 @@ impl Session { } Ok(Err(e)) => Some(self.script_failed(job, &e)), Ok(Ok(Progress::Paused)) => { - JOBS.with(|jobs| jobs.borrow_mut().insert(key.0, job)); + JOBS.with(|jobs| jobs.borrow_mut().insert(key.id, job)); self.script_key = Some(key); None } @@ -1592,6 +1609,13 @@ fn run_slice(s: &mut Session, job: &mut Job) -> std::result::Result bool { + s.script_key.as_ref().is_some_and(|k| JOBS.with(|jobs| jobs.borrow_mut().remove(&k.id)).is_some()) +} + /// The objects a run may add before it is asked to continue or stop. fn growth_objects() -> u64 { #[cfg(test)] diff --git a/crates/engine/src/tests/script_console.rs b/crates/engine/src/tests/script_console.rs index ba57d96bd..985e5b810 100644 --- a/crates/engine/src/tests/script_console.rs +++ b/crates/engine/src/tests/script_console.rs @@ -170,6 +170,55 @@ fn a_stopped_run_reports_its_diagnostics_and_its_unended_line() { assert_eq!(texts(&mut s, "end"), ["ended: stopped"]); } +/// A report line counts one host call in the singular, and gives a run without a clock as "time +/// unavailable". +#[test] +fn a_report_line_counts_one_host_call_in_the_singular_and_says_when_time_is_unavailable() { + use crate::script::console::{Entry, Slow}; + let report = |ms: Option, host_calls: u64| Entry::Report { ms, host_calls, slowest: vec![] }.text(); + assert_eq!(report(Some(3), 0), "3 ms, 0 host calls"); + assert_eq!(report(Some(3), 1), "3 ms, 1 host call"); + assert_eq!(report(Some(0), 2), "0 ms, 2 host calls"); + assert_eq!(report(None, 0), "time unavailable, 0 host calls"); + assert_eq!(report(None, 1), "time unavailable, 1 host call"); + assert_eq!(report(None, 2), "time unavailable, 2 host calls"); + let slowest = vec![Slow { id: "a.b".into(), calls: 1, total_ms: 4, max_ms: 4 }]; + assert_eq!(Entry::Report { ms: None, host_calls: 1, slowest }.text(), "time unavailable, 1 host call; slowest: a.b ×1 4 ms"); +} + +/// A run whose job is gone still ends its console entry, once, with its own number and name and no +/// report line: as stopped when it is abandoned, as an internal fault when a slice finds it gone. +/// The session can start the next run. +#[test] +fn a_run_whose_job_is_gone_still_ends_its_console_entry() { + for abandon in [true, false] { + let mut s = Session::new(); + s.script_frames = true; + run(&mut s, "$.writeln('one'); while (true) {}").unwrap(); + assert!(s.script_pump().is_none()); + assert!(script::forget_job(&s)); + if abandon { + assert!(s.script_abandon()); + } else { + let e = s.script_pump().unwrap().unwrap_err(); + assert_eq!(e.to_string(), "the script's run is no longer available"); + } + assert!(!s.script_running()); + let all = lines(&mut s); + let kinds: Vec<&str> = all.iter().map(|(_, k, _)| k.as_str()).collect(); + assert_eq!(kinds, ["start", "output", "end"], "{all:?}"); + assert_eq!(all[2].2, if abandon { "ended: stopped" } else { "ended: internal" }); + let c = s.execute("script.console", &json!({})).unwrap(); + assert_eq!((c["lines"][2]["run"].as_u64(), c["lines"][2]["name"].as_str()), (Some(1), Some("t.js"))); + assert!(!s.script_abandon() && s.script_pump().is_none(), "nothing is left to end"); + assert_eq!(lines(&mut s).len(), 3, "the entry ends once"); + s.script_frames = false; + run(&mut s, "$.writeln('two')").unwrap(); + assert_eq!(texts(&mut s, "end").last().map(String::as_str), Some("ended: finished"), "the next run starts"); + assert_eq!(lines(&mut s).last().map(|l| l.0), Some(2)); + } +} + #[test] fn runs_are_numbered_a_busy_run_adds_nothing_and_clear_keeps_the_report() { let mut s = Session::new(); diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index 2d4949879..53589c698 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -6513,5 +6513,11 @@ breakText Glyphs Глифи Ended at a limit Прекратен при лимит Stopped Спрян Ended by an internal fault Прекратен поради вътрешна грешка - {ms} ms, {calls} host calls {ms} ms, {calls} извиквания към хоста - {dropped} earlier lines dropped, {cut} lines cut {dropped} по-ранни реда премахнати, {cut} реда съкратени + time unavailable времето не е налично + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} най-бавни: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} извикване към хоста|{n} извиквания към хоста +@plural {n} earlier line dropped|{n} earlier lines dropped {n} по-ранен ред премахнат|{n} по-ранни реда премахнати +@plural {n} line cut|{n} lines cut {n} ред съкратен|{n} реда съкратени diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index 912eec6a6..17805d5b9 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -6564,5 +6564,11 @@ shape Open Otvoren Ended at a limit Završeno na ograničenju Stopped Zaustavljeno Ended by an internal fault Završeno zbog interne greške - {ms} ms, {calls} host calls {ms} ms, {calls} poziva hosta - {dropped} earlier lines dropped, {cut} lines cut {dropped} ranijih redova uklonjeno, {cut} redova skraćeno + time unavailable vrijeme nije dostupno + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} najsporije: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} poziv hosta|{n} poziva hosta|{n} poziva hosta +@plural {n} earlier line dropped|{n} earlier lines dropped {n} raniji red uklonjen|{n} ranija reda uklonjena|{n} ranijih redova uklonjeno +@plural {n} line cut|{n} lines cut {n} red skraćen|{n} reda skraćena|{n} redova skraćeno diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index f12bb4a6a..8abd9f09f 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -6768,6 +6768,12 @@ breakText Glyphs Glifs Ended at a limit Acabat en un límit Stopped Aturat Ended by an internal fault Acabat per un error intern - {ms} ms, {calls} host calls {ms} ms, {calls} crides a l’amfitrió - {dropped} earlier lines dropped, {cut} lines cut {dropped} línies anteriors descartades, {cut} línies tallades + time unavailable temps no disponible + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} més lentes: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} crida a l’amfitrió|{n} crides a l’amfitrió +@plural {n} earlier line dropped|{n} earlier lines dropped {n} línia anterior descartada|{n} línies anteriors descartades +@plural {n} line cut|{n} lines cut {n} línia tallada|{n} línies tallades @msg `first` and `last` must be numbers of lines the console holds, first before last `first` i `last` han de ser números de línies que la consola conserva, `first` abans de `last` diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 6d7965acd..aca421c4a 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -6787,6 +6787,12 @@ breakText Glyphs Glyfy Ended at a limit Ukončeno na limitu Stopped Zastaveno Ended by an internal fault Ukončeno vnitřní chybou - {ms} ms, {calls} host calls {ms} ms, {calls} volání hostitele - {dropped} earlier lines dropped, {cut} lines cut {dropped} starších řádků zahozeno, {cut} řádků zkráceno + time unavailable čas není k dispozici + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} nejpomalejší: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} volání hostitele|{n} volání hostitele|{n} volání hostitele +@plural {n} earlier line dropped|{n} earlier lines dropped {n} starší řádek zahozen|{n} starší řádky zahozeny|{n} starších řádků zahozeno +@plural {n} line cut|{n} lines cut {n} řádek zkrácen|{n} řádky zkráceny|{n} řádků zkráceno @msg `first` and `last` must be numbers of lines the console holds, first before last `first` a `last` musí být čísla řádků, které konzole uchovává, `first` před `last` diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index 53036e9dd..f0f93c868 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -6527,5 +6527,11 @@ breakText Glyphs Glyffer Ended at a limit Afsluttet ved en grænse Stopped Stoppet Ended by an internal fault Afsluttet af en intern fejl - {ms} ms, {calls} host calls {ms} ms, {calls} værtskald - {dropped} earlier lines dropped, {cut} lines cut {dropped} tidligere linjer fjernet, {cut} linjer afkortet + time unavailable tid ikke tilgængelig + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} langsomste: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} værtskald|{n} værtskald +@plural {n} earlier line dropped|{n} earlier lines dropped {n} tidligere linje fjernet|{n} tidligere linjer fjernet +@plural {n} line cut|{n} lines cut {n} linje afkortet|{n} linjer afkortet diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index e46a1b6ea..a86fa9133 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -6374,6 +6374,12 @@ breakText Glyphs Glyphen Ended at a limit An einem Limit beendet Stopped Gestoppt Ended by an internal fault Durch einen internen Fehler beendet - {ms} ms, {calls} host calls {ms} ms, {calls} Host-Aufrufe - {dropped} earlier lines dropped, {cut} lines cut {dropped} ältere Zeilen verworfen, {cut} Zeilen gekürzt + time unavailable Zeit nicht verfügbar + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} langsamste: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} Host-Aufruf|{n} Host-Aufrufe +@plural {n} earlier line dropped|{n} earlier lines dropped {n} ältere Zeile verworfen|{n} ältere Zeilen verworfen +@plural {n} line cut|{n} lines cut {n} Zeile gekürzt|{n} Zeilen gekürzt @msg `first` and `last` must be numbers of lines the console holds, first before last `first` und `last` müssen Nummern von Zeilen sein, die die Konsole enthält, `first` vor `last` diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 98015264e..10dc1c2ec 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -6739,6 +6739,12 @@ breakText Glyphs Γλύφοι Ended at a limit Τερματίστηκε σε όριο Stopped Διακόπηκε Ended by an internal fault Τερματίστηκε λόγω εσωτερικού σφάλματος - {ms} ms, {calls} host calls {ms} ms, {calls} κλήσεις προς το κεντρικό σύστημα - {dropped} earlier lines dropped, {cut} lines cut {dropped} παλαιότερες γραμμές απορρίφθηκαν, {cut} γραμμές περικόπηκαν + time unavailable ο χρόνος δεν είναι διαθέσιμος + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} πιο αργές: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} κλήση προς το κεντρικό σύστημα|{n} κλήσεις προς το κεντρικό σύστημα +@plural {n} earlier line dropped|{n} earlier lines dropped {n} παλαιότερη γραμμή απορρίφθηκε|{n} παλαιότερες γραμμές απορρίφθηκαν +@plural {n} line cut|{n} lines cut {n} γραμμή περικόπηκε|{n} γραμμές περικόπηκαν @msg `first` and `last` must be numbers of lines the console holds, first before last Τα `first` και `last` πρέπει να είναι αριθμοί γραμμών που κρατά η κονσόλα, το `first` πριν από το `last` diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index d5d844b23..8e2f06fd7 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -6730,6 +6730,12 @@ breakText Glyphs Glifos Ended at a limit Terminado en un límite Stopped Detenido Ended by an internal fault Terminado por un error interno - {ms} ms, {calls} host calls {ms} ms, {calls} llamadas al host - {dropped} earlier lines dropped, {cut} lines cut {dropped} líneas anteriores descartadas, {cut} líneas recortadas + time unavailable tiempo no disponible + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} más lentos: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} llamada al host|{n} llamadas al host +@plural {n} earlier line dropped|{n} earlier lines dropped {n} línea anterior descartada|{n} líneas anteriores descartadas +@plural {n} line cut|{n} lines cut {n} línea recortada|{n} líneas recortadas @msg `first` and `last` must be numbers of lines the console holds, first before last `first` y `last` deben ser números de líneas que la consola conserva, `first` antes que `last` diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 85b49e77e..00103d50f 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -6822,6 +6822,12 @@ breakText Glyphs Merkit Ended at a limit Päättyi rajaan Stopped Pysäytetty Ended by an internal fault Päättyi sisäiseen virheeseen - {ms} ms, {calls} host calls {ms} ms, {calls} isäntäkutsua - {dropped} earlier lines dropped, {cut} lines cut {dropped} aiempaa riviä poistettu, {cut} riviä katkaistu + time unavailable aika ei käytettävissä + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} hitaimmat: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} isäntäkutsu|{n} isäntäkutsua +@plural {n} earlier line dropped|{n} earlier lines dropped {n} aiempi rivi poistettu|{n} aiempaa riviä poistettu +@plural {n} line cut|{n} lines cut {n} rivi katkaistu|{n} riviä katkaistu @msg `first` and `last` must be numbers of lines the console holds, first before last `first` ja `last` on oltava konsolin säilyttämien rivien numeroita, `first` ennen arvoa `last` diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 43eb6d757..28c466d86 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -6782,6 +6782,12 @@ breakText Glyphs Glyphes Ended at a limit Terminé à une limite Stopped Arrêté Ended by an internal fault Terminé par une erreur interne - {ms} ms, {calls} host calls {ms} ms, {calls} appels à l’hôte - {dropped} earlier lines dropped, {cut} lines cut {dropped} lignes antérieures supprimées, {cut} lignes coupées + time unavailable temps indisponible + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} plus lentes : {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} appel à l’hôte|{n} appels à l’hôte +@plural {n} earlier line dropped|{n} earlier lines dropped {n} ligne antérieure supprimée|{n} lignes antérieures supprimées +@plural {n} line cut|{n} lines cut {n} ligne coupée|{n} lignes coupées @msg `first` and `last` must be numbers of lines the console holds, first before last `first` et `last` doivent être des numéros de lignes que la console contient, `first` avant `last` diff --git a/crates/ui-egui/src/i18n/hi.tsv b/crates/ui-egui/src/i18n/hi.tsv index 796939065..4bd3244fb 100644 --- a/crates/ui-egui/src/i18n/hi.tsv +++ b/crates/ui-egui/src/i18n/hi.tsv @@ -8228,6 +8228,12 @@ theme Appearance अपीयरेंस Ended at a limit सीमा पर समाप्त Stopped रोका गया Ended by an internal fault आंतरिक त्रुटि से समाप्त - {ms} ms, {calls} host calls {ms} ms, {calls} होस्ट कॉल - {dropped} earlier lines dropped, {cut} lines cut {dropped} पुरानी पंक्तियाँ हटाई गईं, {cut} पंक्तियाँ काटी गईं + time unavailable समय उपलब्ध नहीं + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} सबसे धीमे: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} होस्ट कॉल|{n} होस्ट कॉल +@plural {n} earlier line dropped|{n} earlier lines dropped {n} पुरानी पंक्ति हटाई गई|{n} पुरानी पंक्तियाँ हटाई गईं +@plural {n} line cut|{n} lines cut {n} पंक्ति काटी गई|{n} पंक्तियाँ काटी गईं @msg `first` and `last` must be numbers of lines the console holds, first before last `first` और `last` कंसोल में रखी पंक्तियों की संख्याएँ होनी चाहिए, `first` पहले और `last` बाद में diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index ec7d13a8c..1eb77bdba 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -6771,6 +6771,12 @@ breakText Glyphs Glifák Ended at a limit Korlátnál ért véget Stopped Leállítva Ended by an internal fault Belső hiba miatt ért véget - {ms} ms, {calls} host calls {ms} ms, {calls} gazdahívás - {dropped} earlier lines dropped, {cut} lines cut {dropped} korábbi sor elvetve, {cut} sor levágva + time unavailable az idő nem érhető el + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} leglassabbak: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} gazdahívás +@plural {n} earlier line dropped|{n} earlier lines dropped {n} korábbi sor elvetve +@plural {n} line cut|{n} lines cut {n} sor levágva @msg `first` and `last` must be numbers of lines the console holds, first before last A `first` és a `last` a konzolban tárolt sorok számai legyenek, a `first` a `last` előtt diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 45d30eb0f..d0ef44033 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -6527,5 +6527,11 @@ breakText Glyphs Glif Ended at a limit Berakhir pada batas Stopped Dihentikan Ended by an internal fault Berakhir karena galat internal - {ms} ms, {calls} host calls {ms} ms, {calls} panggilan host - {dropped} earlier lines dropped, {cut} lines cut {dropped} baris lama dibuang, {cut} baris dipotong + time unavailable waktu tidak tersedia + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} paling lambat: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} panggilan host +@plural {n} earlier line dropped|{n} earlier lines dropped {n} baris lama dibuang +@plural {n} line cut|{n} lines cut {n} baris dipotong diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 419cf0582..ae8f8f5b1 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -6408,6 +6408,12 @@ breakText Glyphs Glifi Ended at a limit Terminato a un limite Stopped Interrotto Ended by an internal fault Terminato per un errore interno - {ms} ms, {calls} host calls {ms} ms, {calls} chiamate all'host - {dropped} earlier lines dropped, {cut} lines cut {dropped} righe precedenti scartate, {cut} righe tagliate + time unavailable tempo non disponibile + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} più lenti: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} chiamata all'host|{n} chiamate all'host +@plural {n} earlier line dropped|{n} earlier lines dropped {n} riga precedente scartata|{n} righe precedenti scartate +@plural {n} line cut|{n} lines cut {n} riga tagliata|{n} righe tagliate @msg `first` and `last` must be numbers of lines the console holds, first before last `first` e `last` devono essere numeri di righe presenti nella console, `first` prima di `last` diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index effd2a900..b2bb89ff1 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -6473,6 +6473,12 @@ breakText Glyphs 字形 Ended at a limit 上限で終了 Stopped 停止 Ended by an internal fault 内部エラーで終了 - {ms} ms, {calls} host calls {ms} ms、ホスト呼び出し {calls} 回 - {dropped} earlier lines dropped, {cut} lines cut 古い行 {dropped} 行を破棄、{cut} 行を切り詰め + time unavailable 時間を取得できません + {ms} ms {ms} ms + {time}, {calls} {time}、{calls} + slowest: {commands} 最も遅いコマンド:{commands} + {dropped}, {cut} {dropped}、{cut} +@plural {n} host call|{n} host calls ホスト呼び出し {n} 回 +@plural {n} earlier line dropped|{n} earlier lines dropped 古い行 {n} 行を破棄 +@plural {n} line cut|{n} lines cut {n} 行を切り詰め @msg `first` and `last` must be numbers of lines the console holds, first before last `first` と `last` には、コンソールが保持している行の番号を、`first` が `last` より前になるよう指定してください diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index e1b2fceef..ac822eebc 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -6848,6 +6848,12 @@ font-script Japanese იაპონური Ended at a limit დასრულდა ლიმიტზე Stopped შეჩერდა Ended by an internal fault დასრულდა შიდა შეცდომის გამო - {ms} ms, {calls} host calls {ms} ms, ჰოსტის {calls} გამოძახება - {dropped} earlier lines dropped, {cut} lines cut {dropped} ძველი სტრიქონი წაიშალა, {cut} სტრიქონი შემოკლდა + time unavailable დრო მიუწვდომელია + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} ყველაზე ნელი: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls ჰოსტის {n} გამოძახება +@plural {n} earlier line dropped|{n} earlier lines dropped {n} ძველი სტრიქონი წაიშალა +@plural {n} line cut|{n} lines cut {n} სტრიქონი შემოკლდა @msg `first` and `last` must be numbers of lines the console holds, first before last `first` და `last` უნდა იყოს კონსოლში შენახული სტრიქონების ნომრები და `first` უნდა იყოს `last`-ზე წინ diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 2fa677459..031fb82ed 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -6369,6 +6369,12 @@ breakText Glyphs 글리프 Ended at a limit 한도에서 종료됨 Stopped 중지됨 Ended by an internal fault 내부 오류로 종료됨 - {ms} ms, {calls} host calls {ms} ms, 호스트 호출 {calls}회 - {dropped} earlier lines dropped, {cut} lines cut 이전 줄 {dropped}개 삭제됨, 줄 {cut}개 잘림 + time unavailable 시간 정보 없음 + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} 가장 느린 명령: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls 호스트 호출 {n}회 +@plural {n} earlier line dropped|{n} earlier lines dropped 이전 줄 {n}개 삭제됨 +@plural {n} line cut|{n} lines cut 줄 {n}개 잘림 @msg `first` and `last` must be numbers of lines the console holds, first before last `first`와 `last`는 콘솔에 있는 줄 번호여야 하며 `first`가 `last`보다 앞서야 합니다 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 10c923cd6..72c704dea 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -6578,5 +6578,11 @@ breakText Glyphs Glyphs Ended at a limit Beëindigd bij een limiet Stopped Gestopt Ended by an internal fault Beëindigd door een interne fout - {ms} ms, {calls} host calls {ms} ms, {calls} host-aanroepen - {dropped} earlier lines dropped, {cut} lines cut {dropped} eerdere regels verwijderd, {cut} regels ingekort + time unavailable tijd niet beschikbaar + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} traagste: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} host-aanroep|{n} host-aanroepen +@plural {n} earlier line dropped|{n} earlier lines dropped {n} eerdere regel verwijderd|{n} eerdere regels verwijderd +@plural {n} line cut|{n} lines cut {n} regel ingekort|{n} regels ingekort diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index a4f8580ff..8b974e25f 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -6643,6 +6643,12 @@ breakText Glyphs Glify Ended at a limit Zakończono na limicie Stopped Zatrzymano Ended by an internal fault Zakończono z powodu błędu wewnętrznego - {ms} ms, {calls} host calls {ms} ms, wywołania hosta: {calls} - {dropped} earlier lines dropped, {cut} lines cut Odrzucone wcześniejsze wiersze: {dropped}, skrócone wiersze: {cut} + time unavailable czas niedostępny + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} najwolniejsze: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} wywołanie hosta|{n} wywołania hosta|{n} wywołań hosta +@plural {n} earlier line dropped|{n} earlier lines dropped {n} odrzucony wcześniejszy wiersz|{n} odrzucone wcześniejsze wiersze|{n} odrzuconych wcześniejszych wierszy +@plural {n} line cut|{n} lines cut {n} skrócony wiersz|{n} skrócone wiersze|{n} skróconych wierszy @msg `first` and `last` must be numbers of lines the console holds, first before last `first` i `last` muszą być numerami wierszy przechowywanych w konsoli, `first` przed `last` diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 2496b775e..ba46fd1db 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -6860,6 +6860,12 @@ swatch Yellow Green Verde-amarelado Ended at a limit Encerrado em um limite Stopped Interrompido Ended by an internal fault Encerrado por um erro interno - {ms} ms, {calls} host calls {ms} ms, {calls} chamadas ao host - {dropped} earlier lines dropped, {cut} lines cut {dropped} linhas anteriores descartadas, {cut} linhas cortadas + time unavailable tempo indisponível + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} mais lentos: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} chamada ao host|{n} chamadas ao host +@plural {n} earlier line dropped|{n} earlier lines dropped {n} linha anterior descartada|{n} linhas anteriores descartadas +@plural {n} line cut|{n} lines cut {n} linha cortada|{n} linhas cortadas @msg `first` and `last` must be numbers of lines the console holds, first before last `first` e `last` devem ser números de linhas que o console mantém, `first` antes de `last` diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 5f34c30ec..ff910d692 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -6876,6 +6876,12 @@ shape Open Открытый Ended at a limit Завершено на лимите Stopped Остановлено Ended by an internal fault Завершено из-за внутренней ошибки - {ms} ms, {calls} host calls {ms} мс, вызовов хоста: {calls} - {dropped} earlier lines dropped, {cut} lines cut Отброшено прежних строк: {dropped}, обрезано строк: {cut} + time unavailable время недоступно + {ms} ms {ms} мс + {time}, {calls} {time}, {calls} + slowest: {commands} самые медленные: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} вызов хоста|{n} вызова хоста|{n} вызовов хоста +@plural {n} earlier line dropped|{n} earlier lines dropped {n} прежняя строка отброшена|{n} прежние строки отброшены|{n} прежних строк отброшено +@plural {n} line cut|{n} lines cut {n} строка обрезана|{n} строки обрезаны|{n} строк обрезано @msg `first` and `last` must be numbers of lines the console holds, first before last `first` и `last` должны быть номерами строк, которые хранит консоль, причём `first` не позже `last` diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index aab245107..5e4c239d3 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -8272,6 +8272,12 @@ digits Hindi Hindi Ended at a limit Avslutades vid en gräns Stopped Stoppad Ended by an internal fault Avslutades av ett internt fel - {ms} ms, {calls} host calls {ms} ms, {calls} värdanrop - {dropped} earlier lines dropped, {cut} lines cut {dropped} tidigare rader borttagna, {cut} rader avkortade + time unavailable tid ej tillgänglig + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} långsammast: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} värdanrop|{n} värdanrop +@plural {n} earlier line dropped|{n} earlier lines dropped {n} tidigare rad borttagen|{n} tidigare rader borttagna +@plural {n} line cut|{n} lines cut {n} rad avkortad|{n} rader avkortade @msg `first` and `last` must be numbers of lines the console holds, first before last `first` och `last` måste vara nummer på rader som konsolen har kvar, `first` före `last` diff --git a/crates/ui-egui/src/i18n/tests.rs b/crates/ui-egui/src/i18n/tests.rs index fd842dd34..79cbd7a64 100644 --- a/crates/ui-egui/src/i18n/tests.rs +++ b/crates/ui-egui/src/i18n/tests.rs @@ -227,6 +227,24 @@ fn each_language_counts_with_its_plural_rule() { } } +/// The Script Console's counted phrases have a row in every complete catalog, and a count picks +/// the language's own form. +#[test] +fn script_console_counts_take_each_language_s_form() { + const COUNTED: [(&str, &str); 3] = + [("{n} host call", "{n} host calls"), ("{n} earlier line dropped", "{n} earlier lines dropped"), ("{n} line cut", "{n} lines cut")]; + for l in LANGUAGES.iter().filter(|l| l.complete_menus) { + for (one, other) in COUNTED { + assert!(l.catalog().plural(one, other, 0).is_some(), "{} is missing the row for {other}", l.code); + } + } + assert_eq!([1, 2].map(|n| trn(de(), n, COUNTED[0].0, COUNTED[0].1)), ["1 Host-Aufruf", "2 Host-Aufrufe"]); + let ru = Lang::from_code("ru").expect("registered"); + assert_eq!([1, 3, 5].map(|n| trn(ru, n, COUNTED[2].0, COUNTED[2].1)), ["1 строка обрезана", "3 строки обрезаны", "5 строк обрезано"]); + let fr = Lang::from_code("fr").expect("registered"); + assert_eq!([0, 1].map(|n| trn(fr, n, COUNTED[1].0, COUNTED[1].1)), ["0 ligne antérieure supprimée", "1 ligne antérieure supprimée"]); +} + #[test] fn candidates_walk_from_specific_to_general() { assert_eq!(candidates("pt_BR.UTF-8"), ["pt-br", "pt"]); diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index 12e5a14e3..6b40ef0c2 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -6743,6 +6743,12 @@ breakText Glyphs Glifler Ended at a limit Bir sınırda sona erdi Stopped Durduruldu Ended by an internal fault Bir iç hata nedeniyle sona erdi - {ms} ms, {calls} host calls {ms} ms, {calls} ana bilgisayar çağrısı - {dropped} earlier lines dropped, {cut} lines cut {dropped} eski satır atıldı, {cut} satır kesildi + time unavailable süre kullanılamıyor + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} en yavaşlar: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} ana bilgisayar çağrısı +@plural {n} earlier line dropped|{n} earlier lines dropped {n} eski satır atıldı +@plural {n} line cut|{n} lines cut {n} satır kesildi @msg `first` and `last` must be numbers of lines the console holds, first before last `first` ve `last`, konsolun tuttuğu satırların numaraları olmalı ve `first`, `last` değerinden önce gelmeli diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index a7854dc66..6cb54c683 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -6388,6 +6388,12 @@ breakText Glyphs Гліфи Ended at a limit Завершено на ліміті Stopped Зупинено Ended by an internal fault Завершено через внутрішню помилку - {ms} ms, {calls} host calls {ms} мс, викликів хоста: {calls} - {dropped} earlier lines dropped, {cut} lines cut Відкинуто попередніх рядків: {dropped}, обрізано рядків: {cut} + time unavailable час недоступний + {ms} ms {ms} мс + {time}, {calls} {time}, {calls} + slowest: {commands} найповільніші: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} виклик хоста|{n} виклики хоста|{n} викликів хоста +@plural {n} earlier line dropped|{n} earlier lines dropped {n} попередній рядок відкинуто|{n} попередні рядки відкинуто|{n} попередніх рядків відкинуто +@plural {n} line cut|{n} lines cut {n} рядок обрізано|{n} рядки обрізано|{n} рядків обрізано @msg `first` and `last` must be numbers of lines the console holds, first before last `first` і `last` мають бути номерами рядків, які зберігає консоль, причому `first` не пізніше `last` diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index ce683ff03..3cf264daf 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -6389,6 +6389,12 @@ breakText Glyphs Glyph Ended at a limit Kết thúc ở giới hạn Stopped Đã dừng Ended by an internal fault Kết thúc do lỗi nội bộ - {ms} ms, {calls} host calls {ms} ms, {calls} lệnh gọi máy chủ - {dropped} earlier lines dropped, {cut} lines cut Đã bỏ {dropped} dòng cũ, đã cắt {cut} dòng + time unavailable không có thời gian + {ms} ms {ms} ms + {time}, {calls} {time}, {calls} + slowest: {commands} chậm nhất: {commands} + {dropped}, {cut} {dropped}, {cut} +@plural {n} host call|{n} host calls {n} lệnh gọi máy chủ +@plural {n} earlier line dropped|{n} earlier lines dropped đã bỏ {n} dòng cũ +@plural {n} line cut|{n} lines cut đã cắt {n} dòng @msg `first` and `last` must be numbers of lines the console holds, first before last `first` và `last` phải là số thứ tự của các dòng mà bảng điều khiển đang giữ, `first` đứng trước `last` diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 91d0e4e74..8da248f40 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -6625,6 +6625,12 @@ breakText Glyphs 字形 Ended at a limit 在限制处结束 Stopped 已停止 Ended by an internal fault 因内部错误结束 - {ms} ms, {calls} host calls {ms} 毫秒,宿主调用 {calls} 次 - {dropped} earlier lines dropped, {cut} lines cut 已丢弃 {dropped} 行较早内容,已截断 {cut} 行 + time unavailable 时间不可用 + {ms} ms {ms} 毫秒 + {time}, {calls} {time},{calls} + slowest: {commands} 最慢的命令:{commands} + {dropped}, {cut} {dropped},{cut} +@plural {n} host call|{n} host calls 宿主调用 {n} 次 +@plural {n} earlier line dropped|{n} earlier lines dropped 已丢弃 {n} 行较早内容 +@plural {n} line cut|{n} lines cut 已截断 {n} 行 @msg `first` and `last` must be numbers of lines the console holds, first before last `first` 和 `last` 必须是控制台保留的行号,且 `first` 不能在 `last` 之后 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 399377101..5187faac6 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -6423,6 +6423,12 @@ breakText Glyphs 字符 Ended at a limit 在限制處結束 Stopped 已停止 Ended by an internal fault 因內部錯誤結束 - {ms} ms, {calls} host calls {ms} 毫秒,主機呼叫 {calls} 次 - {dropped} earlier lines dropped, {cut} lines cut 已捨棄 {dropped} 行較早內容,已截斷 {cut} 行 + time unavailable 時間無法取得 + {ms} ms {ms} 毫秒 + {time}, {calls} {time},{calls} + slowest: {commands} 最慢的命令:{commands} + {dropped}, {cut} {dropped},{cut} +@plural {n} host call|{n} host calls 主機呼叫 {n} 次 +@plural {n} earlier line dropped|{n} earlier lines dropped 已捨棄 {n} 行較早內容 +@plural {n} line cut|{n} lines cut 已截斷 {n} 行 @msg `first` and `last` must be numbers of lines the console holds, first before last `first` 和 `last` 必須是主控台保留的行號,且 `first` 不能在 `last` 之後 diff --git a/crates/ui-egui/src/panels/script_console.rs b/crates/ui-egui/src/panels/script_console.rs index 3a3a32500..78540b211 100644 --- a/crates/ui-egui/src/panels/script_console.rs +++ b/crates/ui-egui/src/panels/script_console.rs @@ -39,10 +39,13 @@ pub(crate) fn shown(line: &ConsoleLine) -> String { Entry::Output(t) | Entry::Log(t) | Entry::Error(t) => t.clone(), Entry::End(e) => format!("■ {}", ending_label(*e)), Entry::Report { ms, host_calls, slowest } => { - let ms = ms.map_or_else(|| "?".to_string(), |ms| ms.to_string()); - let mut s = crate::i18n::fmt(tl!("{ms} ms, {calls} host calls"), &[("ms", &ms), ("calls", &host_calls.to_string())]); - for c in slowest { - s.push_str(&format!("; {} ×{} {} ms", c.id, c.calls, c.total_ms)); + let time = ms.map_or_else(|| tl!("time unavailable").to_string(), millis); + let calls = crate::i18n::tn(*host_calls, "{n} host call", "{n} host calls"); + let mut s = crate::i18n::fmt(tl!("{time}, {calls}"), &[("time", &time), ("calls", &calls)]); + if !slowest.is_empty() { + let list: Vec = slowest.iter().map(|c| format!("{} ×{} {}", c.id, c.calls, millis(c.total_ms))).collect(); + s.push_str("; "); + s.push_str(&crate::i18n::fmt(tl!("slowest: {commands}"), &[("commands", &list.join(", "))])); } s } @@ -50,13 +53,17 @@ pub(crate) fn shown(line: &ConsoleLine) -> String { format!("#{} {}: {}", line.run, line.name, text) } +/// A time in milliseconds, in the UI language. +fn millis(ms: u64) -> String { + crate::i18n::fmt(tl!("{ms} ms"), &[("ms", &ms.to_string())]) +} + /// The notice of the lines the console dropped and cut, or `None` when it has done neither. fn notice(c: &Console) -> Option { (c.dropped_lines() > 0 || c.truncated_lines() > 0).then(|| { - crate::i18n::fmt( - tl!("{dropped} earlier lines dropped, {cut} lines cut"), - &[("dropped", &c.dropped_lines().to_string()), ("cut", &c.truncated_lines().to_string())], - ) + let dropped = crate::i18n::tn(c.dropped_lines(), "{n} earlier line dropped", "{n} earlier lines dropped"); + let cut = crate::i18n::tn(c.truncated_lines(), "{n} line cut", "{n} lines cut"); + crate::i18n::fmt(tl!("{dropped}, {cut}"), &[("dropped", &dropped), ("cut", &cut)]) }) } diff --git a/crates/ui-egui/src/panels/tests_script_console.rs b/crates/ui-egui/src/panels/tests_script_console.rs index 414e1bb36..c1fbcc4da 100644 --- a/crates/ui-egui/src/panels/tests_script_console.rs +++ b/crates/ui-egui/src/panels/tests_script_console.rs @@ -6,7 +6,7 @@ use serde_json::json; use vectorcraft_engine::Session; use super::pstate; -use super::script_console::{DRAWN, ID, show}; +use super::script_console::{DRAWN, ID, show, shown}; use crate::tests_labels::painted_text; use crate::{Services, VectorcraftApp, script_runs}; @@ -96,3 +96,48 @@ fn copy_all_and_copy_selected_put_the_lines_on_the_clipboard() { let all = app.clipboard_out.take().unwrap(); assert!(all.lines().next().is_some_and(|l| l.contains("lines dropped")), "Copy All starts with the notice: {}", &all[..80]); } + +/// A report line reads in English as `script.console` gives it: "time unavailable" for a run +/// without a clock, one host call in the singular, and the slowest commands. +#[test] +fn a_report_line_reads_as_script_console_gives_it() { + use vectorcraft_engine::script::console::{ConsoleLine, Entry, Slow}; + let slow = vec![Slow { id: "a.b".into(), calls: 2, total_ms: 7, max_ms: 4 }, Slow { id: "c".into(), calls: 1, total_ms: 1, max_ms: 1 }]; + for ms in [None, Some(0), Some(12)] { + for host_calls in [0, 1, 2] { + for slowest in [vec![], slow.clone()] { + let entry = Entry::Report { ms, host_calls, slowest }; + let want = format!("#3 c.js: {}", entry.text()); + assert_eq!(shown(&ConsoleLine { run: 3, name: "c.js".into(), entry }), want); + } + } + } + let line = |ms, host_calls| shown(&ConsoleLine { run: 1, name: "c.js".into(), entry: Entry::Report { ms, host_calls, slowest: vec![] } }); + assert_eq!(line(None, 1), "#1 c.js: time unavailable, 1 host call"); + assert_eq!(line(Some(0), 2), "#1 c.js: 0 ms, 2 host calls"); +} + +/// The notice counts the lines dropped and the lines cut each in its own form, a count of one in +/// the singular; Copy All starts with it. +#[test] +fn the_notice_counts_one_line_in_the_singular() { + for (dropped, cut, want) in [ + (1, 0, "1 earlier line dropped, 0 lines cut"), + (0, 1, "0 earlier lines dropped, 1 line cut"), + (1, 2, "1 earlier line dropped, 2 lines cut"), + (2, 1, "2 earlier lines dropped, 1 line cut"), + (2, 2, "2 earlier lines dropped, 2 lines cut"), + ] { + let mut app = app(); + // A run adds a start, an end and a report line to its output lines. + let lines = if dropped > 0 { vectorcraft_engine::script::console::MAX_CONSOLE_LINES - 3 + dropped } else { cut + 1 }; + let source = format!("var big = 'x'; while (big.length < 5000) big += big; for (var i = 0; i < {lines}; i++) $.writeln(i < {cut} ? big : i)"); + run(&mut app, &source); + let c = app.session.script_console(); + assert_eq!((c.dropped_lines(), c.truncated_lines()), (dropped as u64, cut as u64)); + app.run("ui.copyScriptConsole", json!({})).unwrap(); + let all = app.clipboard_out.take().unwrap(); + assert_eq!(all.lines().next(), Some(want)); + assert!(painted_text(&mut app, show).contains(want)); + } +} diff --git a/docs/mcp.md b/docs/mcp.md index 9c28fbe5b..989e39444 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -1672,7 +1672,12 @@ at the bottom of the panel and in its menu. Output goes on while the panel is cl - `script.console {}` returns `{lines: [{run, name, kind, text}], droppedLines, truncatedLines}`. `run` is the run's number in the session, and `kind` is `start`, `output`, `log`, `error`, `end` or `report`. An end line's text - is `ended:`, a space, and then `finished`, `error`, `fuel`, `hostLimit`, `limit`, `stopped` or `internal`. + is `ended:`, a space, and then `finished`, `error`, `fuel`, `hostLimit`, `limit`, `stopped` or `internal`. A report + line's text is the run's time (`12 ms`, or `time unavailable` on a platform without a clock), a comma and its host + calls (`1 host call`, `2 host calls`), then `; slowest:` and the slowest commands when any were timed. The panel + shows the same text in the interface language. Every run that starts gets an end line. When a run is no longer + available, its end line is `stopped` if the run was abandoned and `internal` if the next slice found it missing, and + no report line follows. - `script.console.clear {}` empties the console, sets its counts to zero and returns `{cleared}`. A running script goes on writing, and `scriptReport` keeps the last run's console. - `ui.copyScriptConsole {first?, last?}` copies lines `first` to `last` to the clipboard as the panel shows them, or diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index cdcda0f6e..312da9a1b 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -729,6 +729,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - The control server writes each reply through a 64 KiB buffer. On Windows 11 it sends the 17 MB `document.inspect` reply of a document with 50,000 objects on one layer to a client over loopback in 0.09 s instead of 34 s. - Scripts: File › Scripts › Other Script… and `script.run` run a JavaScript file against the open documents as one transaction with one undo step for each changed document. A failed or stopped run puts every document back. `crates/engine/src/tests/script_run.rs`. - Scripts: Window › Script Console shows each run's `$.write` and `$.writeln` output, `vc.log` entries, uncaught error with the script's name, line and column, and a report of its time, host calls and slowest commands, keeping at most 2,048 lines and counting the lines it dropped. `script.run`'s report carries the same data, and `script.console`, `script.console.clear` and `ui.copyScriptConsole` read, clear and copy it. `crates/engine/src/tests/script_console.rs`. + - Scripts: the Script Console panel's report line reads as `script.console` gives it, `time unavailable` included on a platform without a clock; counts of host calls, dropped lines and cut lines take the singular for one, in each language's own plural forms; and a run that is no longer available still gets its end line (`crates/engine/src/tests/script_console.rs`, `crates/ui-egui/src/panels/tests_script_console.rs`). - Scripts: a run reads its preprocessor lines before any of it runs: `#include` and `//@include` put another file in place of the line, looked for beside the including file, in the `#includepath` folders and in `JSINCLUDE`; `#script` names the run; `#target` and `#strict off` are taken, and `#strict on`, `#targetengine` and `#engine` are refused. `$.evalFile` runs a file with the same globals and returns its last value, and `$.fileName` and `$.includePath` give the file being run and the include folders. A script run from a file reads these files only in its folder and below, without `..` names or links that lead out, and an error in one is reported at its own file, line and column ([preprocessor directives](https://extendscript.docsforadobe.dev/extendscript-tools-features/preprocessor-directives/), [the `$` object](https://extendscript.docsforadobe.dev/extendscript-tools-features/dollar-object/); `crates/engine/src/tests/script_include.rs`). - Scripts folder: File › Scripts lists the `.js` and `.jsx` files of the `Scripts` folder next to the preferences, each named after its file without the extension, with each subfolder as a submenu, above Check Script… and Other Script… (https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/install-and-run-scripts.html). VectorCraft's own rules: the folder is read again when the window becomes active and when the File menu opens, links are not followed, and one read stops at 2,048 entries, 512 scripts, 128 subfolders, 4 levels or 250 ms. `script.listInstalled` returns the listing. `crates/engine/src/tests/script_folder.rs`, `crates/ui-egui/src/tests/scripts_menu.rs`. - Parameter keys: the engine refuses a key that a command's params description doesn't name before the command runs, in every build and for every caller, including the app's own calls, the commands a command runs and the steps of `command.batch` and `action.batch`. An action recorded by an older version still plays from the Actions panel and the Batch dialog (`Session::replay`). `crates/engine/tests/it/param_keys.rs`.