Skip to content

Commit 1b94527

Browse files
authored
Merge pull request #530 from Bluemangoo/feature/top-tui-u
top: tui impl `u` `U` (filter by user)
2 parents 102dae1 + c883cb5 commit 1b94527

File tree

4 files changed

+94
-32
lines changed

4 files changed

+94
-32
lines changed

src/uu/top/src/top.rs

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,12 @@ pub enum Filter {
4141
#[derive(Debug)]
4242
pub(crate) struct Settings {
4343
// batch:bool
44-
filter: Option<Filter>,
4544
scale_summary_mem: Option<String>,
4645
}
4746

4847
impl Settings {
4948
fn new(matches: &ArgMatches) -> Self {
5049
Self {
51-
filter: None,
5250
scale_summary_mem: matches.get_one::<String>("scale-summary-mem").cloned(),
5351
}
5452
}
@@ -79,34 +77,32 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
7977
picker::sysinfo().write().unwrap().refresh_all();
8078

8179
let settings = Settings::new(&matches);
80+
let mut tui_stat = TuiStat::new();
81+
82+
let filter = matches
83+
.get_many::<u32>("pid")
84+
.map(|pidlist| Filter::Pid(pidlist.cloned().collect()))
85+
.or_else(|| {
86+
matches
87+
.get_one::<String>("filter-any-user")
88+
.map(|user| Filter::User(user.clone()))
89+
})
90+
.or_else(|| {
91+
matches
92+
.get_one::<String>("filter-only-euser")
93+
.map(|euser| Filter::EUser(euser.clone()))
94+
});
8295

83-
let settings = {
84-
let filter = matches
85-
.get_many::<u32>("pid")
86-
.map(|pidlist| Filter::Pid(pidlist.cloned().collect()))
87-
.or_else(|| {
88-
matches
89-
.get_one::<String>("filter-any-user")
90-
.map(|user| Filter::User(user.clone()))
91-
})
92-
.or_else(|| {
93-
matches
94-
.get_one::<String>("filter-only-euser")
95-
.map(|euser| Filter::EUser(euser.clone()))
96-
});
97-
98-
let filter = match filter {
99-
Some(Filter::User(data)) => Some(Filter::User(try_into_uid(data)?)),
100-
// TODO: Make sure this working
101-
Some(Filter::EUser(data)) => Some(Filter::EUser(try_into_uid(data)?)),
102-
_ => filter,
103-
};
104-
105-
Settings { filter, ..settings }
96+
let filter = match filter {
97+
Some(Filter::User(data)) => Some(Filter::User(try_into_uid(data)?)),
98+
// TODO: Make sure this working
99+
Some(Filter::EUser(data)) => Some(Filter::EUser(try_into_uid(data)?)),
100+
_ => filter,
106101
};
102+
tui_stat.filter = filter;
107103

108104
let settings = Arc::new(settings);
109-
let tui_stat = Arc::new(RwLock::new(TuiStat::new()));
105+
let tui_stat = Arc::new(RwLock::new(tui_stat));
110106
let should_update = Arc::new(AtomicBool::new(true));
111107
let data = Arc::new(RwLock::new((
112108
Header::new(&tui_stat.read().unwrap()),
@@ -209,7 +205,7 @@ fn collect(settings: &Settings, fields: &[String], tui_stat: &TuiStat) -> Vec<Ve
209205
.map(|it| it.as_u32())
210206
.collect::<Vec<_>>();
211207

212-
let filter = construct_filter(settings);
208+
let filter = construct_filter(tui_stat);
213209

214210
let mut collected = pids
215211
.into_iter()
@@ -244,8 +240,8 @@ fn collect(settings: &Settings, fields: &[String], tui_stat: &TuiStat) -> Vec<Ve
244240
}
245241

246242
/// Constructing filter from `Settings`
247-
fn construct_filter(settings: &Settings) -> Box<dyn Fn(u32) -> bool> {
248-
let Some(ref filter) = settings.filter else {
243+
fn construct_filter(tui_stat: &TuiStat) -> Box<dyn Fn(u32) -> bool> {
244+
let Some(ref filter) = tui_stat.filter else {
249245
return Box::new(|_: u32| true);
250246
};
251247

src/uu/top/src/tui/input.rs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
use crate::header::Header;
77
use crate::platform::get_numa_nodes;
88
use crate::tui::stat::{CpuValueMode, TuiStat};
9-
use crate::{selected_fields, ProcList, Settings};
9+
use crate::Filter::{EUser, User};
10+
use crate::{selected_fields, try_into_uid, ProcList, Settings};
1011
use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
1112
use std::sync::atomic::{AtomicBool, Ordering};
1213
use std::sync::RwLock;
@@ -20,6 +21,8 @@ pub(crate) enum InputMode {
2021
pub(crate) enum InputEvent {
2122
MaxListDisplay,
2223
NumaNode,
24+
FilterUser,
25+
FilterEUser,
2326
}
2427

2528
macro_rules! char {
@@ -106,6 +109,22 @@ pub fn handle_input(
106109
stat.cpu_graph_mode = stat.cpu_graph_mode.next();
107110
should_update.store(true, Ordering::Relaxed);
108111
}
112+
char!('U') => {
113+
let mut stat = tui_stat.write().unwrap();
114+
stat.input_label = "Which user (blank for all) ".into();
115+
stat.input_value.clear();
116+
stat.input_mode = InputMode::Input(InputEvent::FilterUser);
117+
118+
should_update.store(true, Ordering::Relaxed);
119+
}
120+
char!('u') => {
121+
let mut stat = tui_stat.write().unwrap();
122+
stat.input_label = "Which user (blank for all) ".into();
123+
stat.input_value.clear();
124+
stat.input_mode = InputMode::Input(InputEvent::FilterEUser);
125+
126+
should_update.store(true, Ordering::Relaxed);
127+
}
109128
char!('x') => {
110129
let mut stat = tui_stat.write().unwrap();
111130
stat.highlight_sorted = !stat.highlight_sorted;
@@ -246,7 +265,7 @@ pub fn handle_input(
246265
if let Event::Key(key) = e {
247266
match key.code {
248267
KeyCode::Enter => {
249-
handle_input_value(input_event, tui_stat, data, should_update);
268+
handle_input_value(input_event, settings, tui_stat, data, should_update);
250269
}
251270
KeyCode::Esc => {
252271
let mut stat = tui_stat.write().unwrap();
@@ -273,6 +292,7 @@ pub fn handle_input(
273292

274293
fn handle_input_value(
275294
input_event: InputEvent,
295+
settings: &Settings,
276296
tui_stat: &RwLock<TuiStat>,
277297
data: &RwLock<(Header, ProcList)>,
278298
should_update: &AtomicBool,
@@ -315,5 +335,40 @@ fn handle_input_value(
315335
data.write().unwrap().0.update_cpu(&stat);
316336
should_update.store(true, Ordering::Relaxed);
317337
}
338+
InputEvent::FilterUser | InputEvent::FilterEUser => {
339+
let input_value = { tui_stat.read().unwrap().input_value.clone() };
340+
if input_value.is_empty() {
341+
let mut stat = tui_stat.write().unwrap();
342+
stat.filter = None;
343+
data.write().unwrap().1 = ProcList::new(settings, &stat);
344+
stat.reset_input();
345+
should_update.store(true, Ordering::Relaxed);
346+
return;
347+
}
348+
let user = match try_into_uid(&input_value) {
349+
Ok(user) => user,
350+
Err(_) => {
351+
let mut stat = tui_stat.write().unwrap();
352+
stat.reset_input();
353+
stat.input_error = Some(" invalid user ".into());
354+
should_update.store(true, Ordering::Relaxed);
355+
return;
356+
}
357+
};
358+
359+
let mut stat = tui_stat.write().unwrap();
360+
match input_event {
361+
InputEvent::FilterUser => {
362+
stat.filter = Some(User(user));
363+
}
364+
InputEvent::FilterEUser => {
365+
stat.filter = Some(EUser(user));
366+
}
367+
_ => {}
368+
}
369+
data.write().unwrap().1 = ProcList::new(settings, &stat);
370+
stat.reset_input();
371+
should_update.store(true, Ordering::Relaxed);
372+
}
318373
}
319374
}

src/uu/top/src/tui/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,14 @@ impl<'a> Tui<'a> {
484484

485485
impl Widget for Tui<'_> {
486486
fn render(mut self, area: Rect, buf: &mut Buffer) {
487-
self.stat.list_offset = min(self.stat.list_offset, self.proc_list.collected.len() - 1);
487+
self.stat.list_offset = min(
488+
self.stat.list_offset,
489+
self.proc_list
490+
.collected
491+
.len()
492+
.checked_sub(1)
493+
.unwrap_or_default(),
494+
);
488495
let layout = Layout::new(
489496
Direction::Vertical,
490497
[

src/uu/top/src/tui/stat.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub(crate) struct TuiStat {
3030
pub highlight_bold: bool,
3131
pub show_coordinates: bool,
3232
pub show_zeros: bool,
33+
34+
pub filter: Option<crate::Filter>,
3335
}
3436

3537
impl TuiStat {
@@ -64,6 +66,8 @@ impl TuiStat {
6466
highlight_bold: false,
6567
show_coordinates: false,
6668
show_zeros: true,
69+
70+
filter: None,
6771
}
6872
}
6973

0 commit comments

Comments
 (0)