diff --git a/crates/engine/src/script/console.rs b/crates/engine/src/script/console.rs index 5a3b40ffe..a0e3ee6d0 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 78002422d..7c082739c 100644 --- a/crates/engine/src/script/mod.rs +++ b/crates/engine/src/script/mod.rs @@ -166,21 +166,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. @@ -1235,12 +1241,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); @@ -1250,6 +1252,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<()> { @@ -1342,10 +1357,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) } @@ -1353,14 +1369,15 @@ 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 let Some(e) = job.host.dialogs.take_failure() { return Some(self.script_failed(job, &e)); } if (job.host.waiting.get() || job.host.dialogs.is_waiting()) && !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; } @@ -1382,7 +1399,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 } @@ -1653,6 +1670,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 1f930dfc4..e69dc7b97 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -6521,8 +6521,14 @@ 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} реда съкратени # Deferred plug-in effects Refresh Deferred Effects Обновяване на отложените ефекти diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index 123f2e7cf..fc4610e0d 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -6572,8 +6572,14 @@ 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 # Deferred plug-in effects Refresh Deferred Effects Osvježi odgođene efekte diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index a7c1d07c1..44562ac0f 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -6776,8 +6776,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 3319dc953..e42f9bd21 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -6795,8 +6795,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index dd7af644b..cf7aa67b3 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -6535,8 +6535,14 @@ 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 # Deferred plug-in effects Refresh Deferred Effects Opdatér udskudte effekter diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index f2ec5b4d3..b339033e6 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -6382,8 +6382,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index d60272a1f..114ed5a52 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -6747,8 +6747,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 552037a49..c0e50d82e 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -6738,8 +6738,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index f62120339..cdbd87576 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -6830,8 +6830,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 09b27035b..cb81c4902 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -6790,8 +6790,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/hi.tsv b/crates/ui-egui/src/i18n/hi.tsv index a2b4ff921..296f18e80 100644 --- a/crates/ui-egui/src/i18n/hi.tsv +++ b/crates/ui-egui/src/i18n/hi.tsv @@ -8236,8 +8236,14 @@ 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` बाद में # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 46654e8bb..34b6be0ab 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -6779,8 +6779,14 @@ 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 # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index a48c194da..16854b5bb 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -6535,8 +6535,14 @@ 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 # Deferred plug-in effects Refresh Deferred Effects Segarkan efek yang ditunda diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 3dcc9cec5..6a8f3d725 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -6416,8 +6416,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index e6cd92d6e..aabe534b6 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -6481,8 +6481,14 @@ 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` より前になるよう指定してください # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 60bbfb87a..bb6a5da7d 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -6856,8 +6856,14 @@ 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`-ზე წინ # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 4e847e091..b7f582463 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -6377,8 +6377,14 @@ 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`보다 앞서야 합니다 # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index e31380968..32db6785b 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -6586,8 +6586,14 @@ 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 # Deferred plug-in effects Refresh Deferred Effects Uitgestelde effecten vernieuwen diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index fd3e2d74b..398adf5f5 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -6651,8 +6651,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index ca72406e1..9ede5521a 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -6868,8 +6868,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 4ce19715b..50eb9e969 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -6884,8 +6884,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 07c4fc48b..60324bb91 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -8280,8 +8280,14 @@ 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` # Deferred plug-in effects 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 21cdd3733..496dba8cf 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -6751,8 +6751,14 @@ 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 # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 255c72c05..c1b1c3bda 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -6396,8 +6396,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 6cd971623..d458c348e 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -6397,8 +6397,14 @@ 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` # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index bbd5ab233..028bd6057 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -6633,8 +6633,14 @@ 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` 之后 # Deferred plug-in effects diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index dbc2cf248..7cb218f99 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -6431,8 +6431,14 @@ 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` 之後 # Deferred plug-in effects 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 959201254..9c2a286b7 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -1744,7 +1744,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 8e78caf8e..c22048308 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -732,6 +732,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: an error `$.evalFile` throws for a file it cannot run is reported at that file's line and column only while no `catch` has taken it. Caught and thrown again later, in the script or in another file, it is reported where it was thrown again, and a new error whose message holds its text is reported where that error was thrown. VectorCraft's own rule. `crates/engine/src/tests/script_include.rs`, `crates/js/src/host_tests.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, `#strict on` turns on strict write checks (below), and `#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: `#strict on` (and `//@strict on`) runs the script with the checks the [`$` object](https://extendscript.docsforadobe.dev/extendscript-tools-features/dollar-object/) help page gives for `$.strict`: an assignment to a read-only property throws a `TypeError`, and so does a new property on an object that takes none. VectorCraft's own rules: a getter-only property counts as read-only, the objects that take no new properties are the non-extensible ones (`Object.preventExtensions`, `seal`, `freeze`, and the frozen `vc` and `$` objects), the last `#strict` line of the script and its includes sets the whole run, a file `$.evalFile` runs keeps its own line's checks for its code, and the rest of ES5 strict mode stays with `'use strict'`. Without the line, runs are unchanged. `crates/engine/src/tests/script_include.rs` (`strict_on_*`, `strict_mode_in_eval_file_is_scoped`), `crates/js/src/interp_tests.rs` (`strict_writes_are_separate_from_es5_strict`).