From 2d3e4991eb54709670749b8faeb26c76ca9b6432 Mon Sep 17 00:00:00 2001 From: ManOfGoldForever Date: Sun, 8 Feb 2026 13:32:46 -0500 Subject: [PATCH] Complete tracker TUI --- src/app.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++------- src/main.rs | 18 +++++++++++++---- 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/app.rs b/src/app.rs index 11571a0..2e9b7b9 100644 --- a/src/app.rs +++ b/src/app.rs @@ -4,21 +4,36 @@ use ratatui::{ style::{Color, Style}, widgets::{Block, Borders, Row, Table, TableState}, }; +use std::ffi::OsStr; use sysinfo::System; +use sysinfo::UpdateKind; +use sysinfo::Users; pub struct SystemStats { pub sys: System, pub cpu_count: f32, + pub users: Users, } pub fn init_system() -> SystemStats { let mut sys = System::new_all(); - sys.refresh_cpu_usage(); + sys.refresh_all(); + let users = Users::new_with_refreshed_list(); let cpu_count = sys.cpus().len() as f32; - SystemStats { sys, cpu_count } + SystemStats { + sys, + cpu_count, + users, + } } -pub fn draw_ui(f: &mut Frame, sys: &mut System, cpu_count: f32, state: &mut TableState) { +pub fn draw_ui( + f: &mut Frame, + sys: &mut System, + users: &mut Users, + cpu_count: f32, + state: &mut TableState, +) { let mut processes: Vec<_> = sys.processes().values().collect(); processes.sort_by(|a, b| { b.cpu_usage() @@ -30,9 +45,21 @@ pub fn draw_ui(f: &mut Frame, sys: &mut System, cpu_count: f32, state: &mut Tabl .iter() .map(|p| { let cpu_usage = p.cpu_usage(); + let owner_name = if let Some(user_id) = p.user_id() { + if let Some(user) = users.get_user_by_id(user_id) { + user.name().to_string() + } else { + format!("UID: {}", user_id.to_string()) + } + } else { + "Unknown".to_string() + }; Row::new(vec![ p.pid().to_string(), p.name().to_string_lossy().to_string(), + p.cmd().join(OsStr::new(" ")).to_string_lossy().to_string(), + owner_name, + format!("{:.1} bytes", p.memory()), format!("{:.1}%", cpu_usage / cpu_count), format!("{:.1}%", cpu_usage), ]) @@ -42,19 +69,31 @@ pub fn draw_ui(f: &mut Frame, sys: &mut System, cpu_count: f32, state: &mut Tabl let widths = [ Constraint::Length(10), Constraint::Fill(1), + Constraint::Fill(1), + Constraint::Length(10), + Constraint::Length(20), + Constraint::Length(10), Constraint::Length(10), - Constraint::Length(15), ]; let table = Table::new(rows, widths) .header( - Row::new(vec!["PID", "Name", "CPU %", "CPU Core %"]).style(Style::new().blue().bold()), + Row::new(vec![ + "PID", + "Name", + "Command", + "Owner", + "Memory", + "CPU %", + "CPU Core %", + ]) + .style(Style::new().blue().bold()), ) .block( Block::default() .borders(Borders::ALL) .title(" Process Manager ") - .title_bottom(" Use ↑/↓ to Scroll, 'q' to Quit "), + .title_bottom(" Use ↑/↓ to Scroll, 'q' to Quit, 'p' to Pause Refresh "), ) .row_highlight_style(Style::new().bg(Color::Cyan).fg(Color::Black).bold()) .highlight_symbol(">> "); @@ -66,6 +105,9 @@ pub fn refresh_system_data(sys: &mut System) { sys.refresh_processes_specifics( sysinfo::ProcessesToUpdate::All, true, - sysinfo::ProcessRefreshKind::nothing().with_cpu(), + sysinfo::ProcessRefreshKind::nothing() + .with_cpu() + .with_user(UpdateKind::Always) + .with_memory(), ); } diff --git a/src/main.rs b/src/main.rs index b071078..0e4a9e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ fn main() -> Result<(), Box> { crossterm::terminal::enable_raw_mode()?; let mut stdout = io::stdout(); crossterm::execute!(stdout, crossterm::terminal::EnterAlternateScreen)?; + let mut paused: bool = false; let backend = CrosstermBackend::new(stdout); let mut terminal = Terminal::new(backend)?; @@ -24,18 +25,27 @@ fn main() -> Result<(), Box> { loop { terminal.draw(|f| { - draw_ui(f, &mut stats.sys, stats.cpu_count, &mut table_state); + draw_ui( + f, + &mut stats.sys, + &mut stats.users, + stats.cpu_count, + &mut table_state, + ); })?; - if last_tick.elapsed() >= tick_rate { - refresh_system_data(&mut stats.sys); - last_tick = Instant::now(); + if !paused { + if last_tick.elapsed() >= tick_rate { + refresh_system_data(&mut stats.sys); + last_tick = Instant::now(); + } } if event::poll(Duration::from_millis(50))? { if let Event::Key(key) = event::read()? { match key.code { KeyCode::Char('q') => break, + KeyCode::Char('p') => paused = !paused, KeyCode::Down => { let i = match table_state.selected() { Some(i) => (i + 1).min(stats.sys.processes().len() - 1),