redbear-power: CPU% color grading + context-sensitive keybar

- Process rows: CPU% now color-graded (green <10%, yellow 10-50%, red 50-90%, bright red >90%)
  using styled spans instead of monolithic format string
- Keybar shows context-aware hints: process-specific keys (k/N/l/o/i/F/y) on Process tab,
  power-specific keys (p/P/m/M/t) on other tabs
- [EXPANDED] indicator added to keybar alongside [FROZEN]
This commit is contained in:
2026-07-07 01:30:47 +03:00
parent 2061609f62
commit f9ace4a956
@@ -20,7 +20,7 @@ use ratatui::backend::TestBackend;
use ratatui::layout::{Constraint, Layout};
#[allow(unused_imports)]
use ratatui::style::{Style, Styled, Stylize};
use ratatui::text::Line;
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Cell, Paragraph, Row, Table, Tabs, Wrap};
use ratatui::{Frame, Terminal};
@@ -1281,16 +1281,22 @@ pub fn render_process_panel<'a>(app: &'a App, focused: bool) -> Paragraph<'a> {
} else {
theme::VALUE
};
lines.push(Line::from(format!(
" {}{:<7} {} {:<5} {:<4} {:<3} {:<3} {:<6} {:<11} {:<11} {:<11} {:<11} {:<11} {:<12} {:<6} {:<5} {:<3} {}",
prefix,
p.pid,
p.state,
p.sched_policy,
p.priority,
p.nice,
p.num_threads,
format!("{:.1}", p.cpu_pct),
let cpu_str = format!("{:<6}", format!("{:.1}", p.cpu_pct));
let cpu_style = if p.cpu_pct >= 90.0 {
theme::VALUE_HOT_LIGHT
} else if p.cpu_pct >= 50.0 {
theme::VALUE_HOT
} else if p.cpu_pct >= 10.0 {
theme::VALUE_WARM
} else {
theme::VALUE
};
let pre = format!(
" {}{:<7} {} {:<5} {:<4} {:<3} {:<3} ",
prefix, p.pid, p.state, p.sched_policy, p.priority, p.nice, p.num_threads,
);
let post = format!(
" {:<11} {:<11} {:<11} {:<11} {:<11} {:<12} {:<6} {:<5} {:<3} {}",
io_str,
rate_str,
thread_io_total_str,
@@ -1301,7 +1307,15 @@ pub fn render_process_panel<'a>(app: &'a App, focused: bool) -> Paragraph<'a> {
rss_spark,
affinity_indicator,
comm_truncated,
).set_style(row_style)));
);
let mut spans = vec![Span::styled(pre, row_style)];
if is_cursor {
spans.push(Span::styled(cpu_str, app.theme.cursor_highlight));
} else {
spans.push(Span::styled(cpu_str, cpu_style));
}
spans.push(Span::styled(post, row_style));
lines.push(Line::from(spans));
}
Paragraph::new(lines)
.block(panel_border(focused, " Process ", &app.theme))
@@ -1925,14 +1939,23 @@ pub fn render_cpu_table<'a>(
}
pub fn render_keybar<'a>(app: &'a App) -> Paragraph<'a> {
let gov = format!(" g:{}", app.cpufreq.active.as_str());
let tab_hints: &str = if app.current_tab == crate::app::TabId::Process {
" ↑↓:sel k:kill N:nice l:files o:sort i:invert F:filter y:tree Enter:detail"
} else {
" ↑↓:cpu p/P:±pstate m/M:min/max t:throttle r:refresh"
};
let mut parts = vec![
format!(" g:{}", app.cpufreq.active.as_str()),
" ↑↓:cpu p/P:±pstate m/M:min/max t:throttle r:refresh".to_string(),
" T:tab ?:help e:expand f:freeze k:kill q:quit".to_string(),
gov,
tab_hints.to_string(),
" T:tab ?:help e:expand f:freeze q:quit".to_string(),
];
if app.frozen {
parts.push(" [FROZEN]".to_string());
}
if app.expanded {
parts.push(" [EXPANDED]".to_string());
}
let line = parts.join("");
Paragraph::new(line)
.style(theme::VALUE_OFF)