Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/uu/top/src/top.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
uucore::error::set_exit_code(0);
break;
}
event::Event::Key(KeyEvent {
code: KeyCode::Char('l'),
..
}) => {
let mut stat = tui_stat.write().unwrap();
stat.show_load_avg = !stat.show_load_avg;
should_update.store(true, Ordering::Relaxed);
}
event::Event::Key(KeyEvent {
code: KeyCode::Char('t'),
..
Expand All @@ -175,6 +183,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
should_update.store(true, Ordering::Relaxed);
data.write().unwrap().0.update_cpu(&stat);
}
event::Event::Key(KeyEvent {
code: KeyCode::Char('4'),
..
}) => {
let mut stat = tui_stat.write().unwrap();
stat.cpu_column = stat.cpu_column % 8 + 1;
should_update.store(true, Ordering::Relaxed);
}
event::Event::Key(KeyEvent {
code: KeyCode::Char('m'),
..
Expand Down
124 changes: 88 additions & 36 deletions src/uu/top/src/tui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,50 +34,88 @@ impl<'a> Tui<'a> {
}

fn calc_header_height(&self) -> u16 {
let mut height = 1;
let mut height = u16::from(self.stat.show_load_avg);

let mut columns = 0;
if self.stat.cpu_graph_mode != CpuGraphMode::Hide {
height += 1;
height += self.header.cpu.len() as u16;
height += 1; // task line
if self.stat.cpu_graph_mode == CpuGraphMode::Sum {
height += self.header.cpu.len() as u16;
} else {
columns += self.header.cpu.len() as u16;
}
}
if self.stat.memory_graph_mode != MemoryGraphMode::Hide {
height += 2;
if self.stat.memory_graph_mode == MemoryGraphMode::Sum {
height += 2;
} else {
columns += 2;
}
}
height += columns / self.stat.cpu_column;
if columns % self.stat.cpu_column != 0 {
height += 1;
}

height
}

fn render_header(&self, area: Rect, buf: &mut Buffer) {
let mut constraints = vec![Constraint::Length(1)];
let constraints = vec![Constraint::Length(1); self.calc_header_height() as usize];

let cpu = &self.header.cpu;

if self.stat.cpu_graph_mode != CpuGraphMode::Hide {
constraints.extend(vec![Constraint::Length(1); cpu.len() + 1]);
}
if self.stat.memory_graph_mode != MemoryGraphMode::Hide {
constraints.extend(vec![Constraint::Length(1); 2]);
}
let header_layout = Layout::new(Direction::Vertical, constraints).split(area);
let mut i = 0;

let render_bars = |bars_to_render: Vec<(String, f64, f64, f64, f64, char, bool)>,
buf: &mut Buffer,
i: usize| {
let mut i_columns = 0;
let mut cpu_column = None;
let mut render_bars = |bars_to_render: Vec<(String, f64, f64, f64, f64, char, bool)>,
buf: &mut Buffer,
i: usize| {
let mut i = i;
for (tag, l, r, red, yellow, content, print_percentage) in bars_to_render {
if cpu_column.is_none() || i_columns >= self.stat.cpu_column as usize {
let mut constraints = vec![Constraint::Min(25)];
let mut width_left = header_layout[i].width - 25;
for _ in 0..self.stat.cpu_column {
if width_left > 28 {
constraints.extend(vec![Constraint::Length(3), Constraint::Min(25)]);
width_left -= 28;
} else {
constraints.extend(vec![Constraint::Length(0), Constraint::Length(0)]);
}
}
let line =
Layout::new(Direction::Horizontal, constraints).split(header_layout[i]);
i += 1;
i_columns = 0;
cpu_column = Some(line);
}

let column_offset = i_columns * 2;
let area = cpu_column.as_ref().unwrap()[column_offset];
if i_columns > 0 {
Line::from(vec![
Span::raw(" "),
Span::styled(" ", Style::default().bg(Color::Yellow)),
Span::raw(" "),
])
.render(cpu_column.as_ref().unwrap()[column_offset - 1], buf);
}
let line_layout = Layout::new(
Direction::Horizontal,
[
Constraint::Length(10),
Constraint::Length(16),
Constraint::Length(if self.stat.cpu_column < 3 { 16 } else { 0 }),
Constraint::Length(1),
Constraint::Min(0),
Constraint::Length(1),
],
)
.split(header_layout[i]);
i += 1;
.split(area);
i_columns += 1;

Span::styled(format!("%{tag:<6}:",), Style::default().red())
.render(line_layout[0], buf);
let percentage = if print_percentage {
Expand Down Expand Up @@ -120,15 +158,17 @@ impl<'a> Tui<'a> {
i
};

let uptime = format!(
"top - {time} {uptime}, {user}, {load_average}",
time = self.header.uptime.time,
uptime = self.header.uptime.uptime,
user = self.header.uptime.user,
load_average = self.header.uptime.load_average,
);
Paragraph::new(uptime).render(header_layout[0], buf);
i += 1;
if self.stat.show_load_avg {
let load_avg = format!(
"top - {time} {uptime}, {user}, {load_average}",
time = self.header.uptime.time,
uptime = self.header.uptime.uptime,
user = self.header.uptime.user,
load_average = self.header.uptime.load_average,
);
Paragraph::new(load_avg).render(header_layout[i], buf);
i += 1;
}

if self.stat.cpu_graph_mode != CpuGraphMode::Hide {
let task = &self.header.task;
Expand All @@ -145,7 +185,7 @@ impl<'a> Tui<'a> {
Span::raw(task.zombie.to_string()),
Span::styled(" zombie", Style::default().red()),
];
Line::from(task_line).render(header_layout[1], buf);
Line::from(task_line).render(header_layout[i], buf);
i += 1;

let mut cpu_bars = Vec::new();
Expand Down Expand Up @@ -253,15 +293,27 @@ impl<'a> Tui<'a> {
bar_content,
false,
));
mem_bars.push((
format!("{unit_name} Swap"),
mem.used_swap as f64 / mem.total_swap as f64 * 100.0,
format_memory(mem.total_swap, unit),
0.0,
mem.used_swap as f64 / mem.total_swap as f64,
bar_content,
false,
));
if mem.total_swap > 0 {
mem_bars.push((
format!("{unit_name} Swap"),
mem.used_swap as f64 / mem.total_swap as f64 * 100.0,
format_memory(mem.total_swap, unit),
0.0,
mem.used_swap as f64 / mem.total_swap as f64,
bar_content,
false,
));
} else {
mem_bars.push((
format!("{unit_name} Swap"),
0.0,
0.0,
0.0,
0.0,
bar_content,
false,
));
}
render_bars(mem_bars, &mut *buf, i);
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/uu/top/src/tui/stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,23 @@
use std::time::Duration;

pub(crate) struct TuiStat {
pub show_load_avg: bool,
pub cpu_graph_mode: CpuGraphMode,
pub cpu_value_mode: CpuValueMode,
pub memory_graph_mode: MemoryGraphMode,
pub cpu_column: u16,
pub list_offset: usize,
pub delay: Duration,
}

impl TuiStat {
pub fn new() -> Self {
Self {
show_load_avg: true,
cpu_graph_mode: CpuGraphMode::default(),
cpu_value_mode: CpuValueMode::default(),
memory_graph_mode: MemoryGraphMode::default(),
cpu_column: 2,
list_offset: 0,
delay: Duration::from_millis(1500), // 1.5s
}
Expand Down
Loading