M2: terminal UI (ratatui)

- layout: header, top menu (quicklook, cpu, mem, swap, load), left sidebar,
  process list and alert footer
- decorations/colors, bars, per-plugin render implementations
- hotkeys: quit, help, modes, sorting, cursor, nice, kill, filters, toggles
- TestBackend layout test
This commit is contained in:
glances-rs
2026-10-09 23:35:23 +00:00
parent 975385da5d
commit 8385900ac1
27 changed files with 2053 additions and 31 deletions
+74
View File
@@ -138,4 +138,78 @@ impl Plugin for CpuPlugin {
fn display_curse(&self) -> bool {
true
}
fn render(&mut self, ctx: &glances_core::RenderContext) -> Vec<glances_core::StatLine> {
let mut ret = Vec::new();
let s = &self.model.stats;
if !s.is_object() || ctx.runtime.percpu {
return ret;
}
let idle_tag = s.get("user").is_none();
// Line 1: total + idle + ctx_switches.
ret.push(self.model.curse_add_line(format!("{:8}", "CPU"), glances_core::Decoration::Title, false, false, false));
if let Some(total) = s.get("total").and_then(Value::as_f64) {
ret.push(self.model.curse_add_line(
format!("{total:>4.1}%"),
self.model.view_decoration(None, "total"),
false,
false,
false,
));
}
if s.get("idle").is_some() && !idle_tag {
let optional = self.model.view_bool(None, "idle", "optional");
ret.push(self.model.curse_add_line(" idle ", glances_core::Decoration::Default, optional, false, false));
if let Some(idle) = s.get("idle").and_then(Value::as_f64) {
ret.push(self.model.curse_add_line(
format!("{idle:>4.1}%"),
self.model.view_decoration(None, "idle"),
optional,
false,
false,
));
}
}
ret.extend(self.model.curse_add_stat("ctx_switches", Some(15), " ", "", ""));
// Line 2.
ret.push(self.model.curse_new_line());
if !idle_tag {
ret.extend(self.model.curse_add_stat("user", Some(15), "", "", ""));
} else {
ret.extend(self.model.curse_add_stat("idle", Some(15), "", "", ""));
}
ret.extend(self.model.curse_add_stat("irq", Some(14), " ", "", ""));
ret.extend(self.model.curse_add_stat("interrupts", Some(15), " ", "", ""));
// Line 3.
ret.push(self.model.curse_new_line());
if !idle_tag {
ret.extend(self.model.curse_add_stat("system", Some(15), "", "", ""));
} else {
ret.extend(self.model.curse_add_stat("core", Some(15), "", "", ""));
}
ret.extend(self.model.curse_add_stat("nice", Some(14), " ", "", ""));
if s.get("soft_interrupts").is_some() {
ret.extend(self.model.curse_add_stat("soft_interrupts", Some(15), " ", "", ""));
} else {
ret.extend(self.model.curse_add_stat("ctx_switches", Some(15), " ", "", ""));
}
// Line 4.
ret.push(self.model.curse_new_line());
if s.get("iowait").is_some() {
ret.extend(self.model.curse_add_stat("iowait", Some(15), "", "", ""));
} else {
ret.extend(self.model.curse_add_stat("dpc", Some(15), "", "", ""));
}
ret.extend(self.model.curse_add_stat("steal", Some(14), " ", "", ""));
if s.get("guest").is_some() {
ret.extend(self.model.curse_add_stat("guest", Some(14), " ", "", ""));
} else {
ret.extend(self.model.curse_add_stat("syscalls", Some(15), " ", "", ""));
}
ret
}
}