M4: fetch mode, cleanup and documentation
- --fetch with a Jinja-subset renderer and the shipped templates - clippy clean, cargo fmt, all tests green - README status and differential testing instructions
This commit is contained in:
+288
-117
@@ -3,7 +3,9 @@
|
||||
use anyhow::Result;
|
||||
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
|
||||
use crossterm::execute;
|
||||
use crossterm::terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode};
|
||||
use crossterm::terminal::{
|
||||
EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode,
|
||||
};
|
||||
use glances_core::plugin::{Align, Decoration, StatLine};
|
||||
use glances_core::processes::processes;
|
||||
use glances_core::{Args, RenderContext};
|
||||
@@ -18,17 +20,7 @@ use std::io::Stdout;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
const LEFT_SIDEBAR: [&str; 11] = [
|
||||
"network",
|
||||
"ports",
|
||||
"wifi",
|
||||
"diskio",
|
||||
"fs",
|
||||
"irq",
|
||||
"folders",
|
||||
"raid",
|
||||
"sensors",
|
||||
"ip",
|
||||
"now",
|
||||
"network", "ports", "wifi", "diskio", "fs", "irq", "folders", "raid", "sensors", "ip", "now",
|
||||
];
|
||||
const TOP_PLUGINS: [&str; 6] = ["cpu", "percpu", "mem", "memswap", "load", "gpu"];
|
||||
|
||||
@@ -54,7 +46,11 @@ pub fn run(engine: &mut Engine) -> Result<()> {
|
||||
let backend = CrosstermBackend::new(stdout);
|
||||
let mut terminal = ratatui::Terminal::new(backend)?;
|
||||
|
||||
let mut tui = Tui { popup: Popup::None, input: String::new(), quit: false };
|
||||
let mut tui = Tui {
|
||||
popup: Popup::None,
|
||||
input: String::new(),
|
||||
quit: false,
|
||||
};
|
||||
let result = run_loop(&mut terminal, engine, &mut tui);
|
||||
|
||||
disable_raw_mode()?;
|
||||
@@ -76,10 +72,10 @@ fn run_loop(
|
||||
tui.draw(terminal, engine)?;
|
||||
|
||||
count += 1;
|
||||
if let Some(max) = engine.args.stop_after {
|
||||
if count >= max {
|
||||
break;
|
||||
}
|
||||
if let Some(max) = engine.args.stop_after
|
||||
&& count >= max
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
let elapsed = start.elapsed().as_secs_f64();
|
||||
@@ -101,7 +97,11 @@ fn run_loop(
|
||||
}
|
||||
|
||||
impl Tui {
|
||||
fn draw(&self, terminal: &mut ratatui::Terminal<CrosstermBackend<Stdout>>, engine: &mut Engine) -> Result<()> {
|
||||
fn draw(
|
||||
&self,
|
||||
terminal: &mut ratatui::Terminal<CrosstermBackend<Stdout>>,
|
||||
engine: &mut Engine,
|
||||
) -> Result<()> {
|
||||
terminal.draw(|frame| draw_frame(frame, engine, self))?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -122,14 +122,39 @@ fn draw_frame(frame: &mut Frame, engine: &mut Engine, tui: &Tui) {
|
||||
// Header.
|
||||
let header_height = 1u16;
|
||||
let top_height = tui.top_height(engine, args, area.width);
|
||||
let footer_height = if tui.popup == Popup::Filter || tui.popup == Popup::Kill { 3 } else { 0 };
|
||||
let main_height = area.height.saturating_sub(header_height + top_height + footer_height);
|
||||
let footer_height = if tui.popup == Popup::Filter || tui.popup == Popup::Kill {
|
||||
3
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let main_height = area
|
||||
.height
|
||||
.saturating_sub(header_height + top_height + footer_height);
|
||||
|
||||
let header_area = Rect { x: 0, y: 0, width: area.width, height: header_height };
|
||||
let top_area = Rect { x: 0, y: header_height, width: area.width, height: top_height };
|
||||
let main_area = Rect { x: 0, y: header_height + top_height, width: area.width, height: main_height };
|
||||
let footer_area =
|
||||
Rect { x: 0, y: area.height.saturating_sub(footer_height), width: area.width, height: footer_height };
|
||||
let header_area = Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: area.width,
|
||||
height: header_height,
|
||||
};
|
||||
let top_area = Rect {
|
||||
x: 0,
|
||||
y: header_height,
|
||||
width: area.width,
|
||||
height: top_height,
|
||||
};
|
||||
let main_area = Rect {
|
||||
x: 0,
|
||||
y: header_height + top_height,
|
||||
width: area.width,
|
||||
height: main_height,
|
||||
};
|
||||
let footer_area = Rect {
|
||||
x: 0,
|
||||
y: area.height.saturating_sub(footer_height),
|
||||
width: area.width,
|
||||
height: footer_height,
|
||||
};
|
||||
|
||||
tui.draw_header(frame, header_area, engine, args);
|
||||
tui.draw_top(frame, top_area, engine, args);
|
||||
@@ -140,7 +165,6 @@ fn draw_frame(frame: &mut Frame, engine: &mut Engine, tui: &Tui) {
|
||||
}
|
||||
|
||||
impl Tui {
|
||||
|
||||
fn top_height(&self, engine: &mut Engine, args: &Args, width: u16) -> u16 {
|
||||
if args.disable_top {
|
||||
return 1;
|
||||
@@ -157,53 +181,67 @@ impl Tui {
|
||||
}
|
||||
}
|
||||
// Quicklook.
|
||||
if let Some(plugin) = engine.plugins.get_mut("quicklook") {
|
||||
if plugin.is_enabled() && !args.disable_quicklook {
|
||||
let ql_width = quicklook_width(width);
|
||||
let ctx = render_ctx(args, &engine.runtime, ql_width as usize);
|
||||
let lines = split_lines(plugin.render(&ctx));
|
||||
height = height.max(lines.len());
|
||||
}
|
||||
if let Some(plugin) = engine.plugins.get_mut("quicklook")
|
||||
&& plugin.is_enabled()
|
||||
&& !args.disable_quicklook
|
||||
{
|
||||
let ql_width = quicklook_width(width);
|
||||
let ctx = render_ctx(args, &engine.runtime, ql_width as usize);
|
||||
let lines = split_lines(plugin.render(&ctx));
|
||||
height = height.max(lines.len());
|
||||
}
|
||||
(height.min(20) as u16).max(1)
|
||||
}
|
||||
|
||||
fn draw_header(
|
||||
&self,
|
||||
frame: &mut Frame,
|
||||
area: Rect,
|
||||
engine: &mut Engine,
|
||||
args: &Args,
|
||||
) {
|
||||
fn draw_header(&self, frame: &mut Frame, area: Rect, engine: &mut Engine, args: &Args) {
|
||||
let x = area.x;
|
||||
// System information.
|
||||
if let Some(plugin) = engine.plugins.get_mut("system") {
|
||||
if plugin.is_enabled() {
|
||||
let ctx = render_ctx(args, &engine.runtime, area.width as usize);
|
||||
let lines = split_lines(plugin.render(&ctx));
|
||||
let text: String = lines.first().map(|l| l.iter().map(|s| s.msg.clone()).collect()).unwrap_or_default();
|
||||
let style = lines
|
||||
.first()
|
||||
.and_then(|l| l.first())
|
||||
.map(|s| style_for(s.decoration, args))
|
||||
.unwrap_or_default();
|
||||
let width = text.chars().count() as u16;
|
||||
frame.render_widget(Paragraph::new(text).style(style), Rect { x, y: area.y, width: width.min(area.width), height: 1 });
|
||||
}
|
||||
if let Some(plugin) = engine.plugins.get_mut("system")
|
||||
&& plugin.is_enabled()
|
||||
{
|
||||
let ctx = render_ctx(args, &engine.runtime, area.width as usize);
|
||||
let lines = split_lines(plugin.render(&ctx));
|
||||
let text: String = lines
|
||||
.first()
|
||||
.map(|l| l.iter().map(|s| s.msg.clone()).collect())
|
||||
.unwrap_or_default();
|
||||
let style = lines
|
||||
.first()
|
||||
.and_then(|l| l.first())
|
||||
.map(|s| style_for(s.decoration, args))
|
||||
.unwrap_or_default();
|
||||
let width = text.chars().count() as u16;
|
||||
frame.render_widget(
|
||||
Paragraph::new(text).style(style),
|
||||
Rect {
|
||||
x,
|
||||
y: area.y,
|
||||
width: width.min(area.width),
|
||||
height: 1,
|
||||
},
|
||||
);
|
||||
}
|
||||
// Uptime on the right.
|
||||
if let Some(plugin) = engine.plugins.get_mut("uptime") {
|
||||
if plugin.is_enabled() {
|
||||
let ctx = render_ctx(args, &engine.runtime, area.width as usize);
|
||||
let lines = split_lines(plugin.render(&ctx));
|
||||
let text: String = lines.first().map(|l| l.iter().map(|s| s.msg.clone()).collect()).unwrap_or_default();
|
||||
let width = text.chars().count() as u16;
|
||||
if width + 2 < area.width {
|
||||
frame.render_widget(
|
||||
Paragraph::new(text),
|
||||
Rect { x: area.width.saturating_sub(width), y: area.y, width, height: 1 },
|
||||
);
|
||||
}
|
||||
if let Some(plugin) = engine.plugins.get_mut("uptime")
|
||||
&& plugin.is_enabled()
|
||||
{
|
||||
let ctx = render_ctx(args, &engine.runtime, area.width as usize);
|
||||
let lines = split_lines(plugin.render(&ctx));
|
||||
let text: String = lines
|
||||
.first()
|
||||
.map(|l| l.iter().map(|s| s.msg.clone()).collect())
|
||||
.unwrap_or_default();
|
||||
let width = text.chars().count() as u16;
|
||||
if width + 2 < area.width {
|
||||
frame.render_widget(
|
||||
Paragraph::new(text),
|
||||
Rect {
|
||||
x: area.width.saturating_sub(width),
|
||||
y: area.y,
|
||||
width,
|
||||
height: 1,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,22 +250,27 @@ impl Tui {
|
||||
let mut x = area.x;
|
||||
// Collect the rendered blocks with their natural widths.
|
||||
struct Block {
|
||||
name: String,
|
||||
lines: Vec<Vec<StatLine>>,
|
||||
natural_width: usize,
|
||||
}
|
||||
let mut blocks: Vec<Block> = Vec::new();
|
||||
|
||||
if !args.disable_quicklook {
|
||||
if let Some(plugin) = engine.plugins.get_mut("quicklook") {
|
||||
if plugin.is_enabled() {
|
||||
let width = quicklook_width(area.width) as usize;
|
||||
let ctx = render_ctx(args, &engine.runtime, width);
|
||||
let lines = split_lines(plugin.render(&ctx));
|
||||
let natural = lines.iter().map(|l| l.iter().map(|s| s.msg.chars().count()).sum::<usize>()).max().unwrap_or(10);
|
||||
blocks.push(Block { name: "quicklook".to_string(), lines, natural_width: natural.max(10) });
|
||||
}
|
||||
}
|
||||
if !args.disable_quicklook
|
||||
&& let Some(plugin) = engine.plugins.get_mut("quicklook")
|
||||
&& plugin.is_enabled()
|
||||
{
|
||||
let width = quicklook_width(area.width) as usize;
|
||||
let ctx = render_ctx(args, &engine.runtime, width);
|
||||
let lines = split_lines(plugin.render(&ctx));
|
||||
let natural = lines
|
||||
.iter()
|
||||
.map(|l| l.iter().map(|s| s.msg.chars().count()).sum::<usize>())
|
||||
.max()
|
||||
.unwrap_or(10);
|
||||
blocks.push(Block {
|
||||
lines,
|
||||
natural_width: natural.max(10),
|
||||
});
|
||||
}
|
||||
for name in TOP_PLUGINS {
|
||||
if let Some(plugin) = engine.plugins.get_mut(name) {
|
||||
@@ -236,8 +279,15 @@ impl Tui {
|
||||
}
|
||||
let ctx = render_ctx(args, &engine.runtime, area.width as usize);
|
||||
let lines = split_lines(plugin.render(&ctx));
|
||||
let natural = lines.iter().map(|l| l.iter().map(|s| s.msg.chars().count()).sum::<usize>()).max().unwrap_or(10);
|
||||
blocks.push(Block { name: name.to_string(), lines, natural_width: natural.max(10) });
|
||||
let natural = lines
|
||||
.iter()
|
||||
.map(|l| l.iter().map(|s| s.msg.chars().count()).sum::<usize>())
|
||||
.max()
|
||||
.unwrap_or(10);
|
||||
blocks.push(Block {
|
||||
lines,
|
||||
natural_width: natural.max(10),
|
||||
});
|
||||
}
|
||||
}
|
||||
if blocks.is_empty() {
|
||||
@@ -247,7 +297,9 @@ impl Tui {
|
||||
// Allocate the available width proportionally to the natural widths.
|
||||
let total_natural: usize = blocks.iter().map(|b| b.natural_width).sum();
|
||||
let spacing = 2usize * blocks.len().saturating_sub(1);
|
||||
let available = (area.width as usize).saturating_sub(spacing).max(blocks.len() * 8);
|
||||
let available = (area.width as usize)
|
||||
.saturating_sub(spacing)
|
||||
.max(blocks.len() * 8);
|
||||
let mut widths: Vec<u16> = Vec::new();
|
||||
for block in &blocks {
|
||||
let mut width = (available * block.natural_width / total_natural).max(8);
|
||||
@@ -267,7 +319,17 @@ impl Tui {
|
||||
if x + width > area.x + area.width {
|
||||
break;
|
||||
}
|
||||
draw_lines(frame, Rect { x, y: area.y, width, height: area.height }, &block.lines, args);
|
||||
draw_lines(
|
||||
frame,
|
||||
Rect {
|
||||
x,
|
||||
y: area.y,
|
||||
width,
|
||||
height: area.height,
|
||||
},
|
||||
&block.lines,
|
||||
args,
|
||||
);
|
||||
x += width + 2;
|
||||
}
|
||||
}
|
||||
@@ -304,7 +366,17 @@ impl Tui {
|
||||
break;
|
||||
}
|
||||
let height = height.min(area.y + area.height - y);
|
||||
draw_lines(frame, Rect { x: area.x, y, width: left_width, height }, &lines, args);
|
||||
draw_lines(
|
||||
frame,
|
||||
Rect {
|
||||
x: area.x,
|
||||
y,
|
||||
width: left_width,
|
||||
height,
|
||||
},
|
||||
&lines,
|
||||
args,
|
||||
);
|
||||
y += height;
|
||||
}
|
||||
}
|
||||
@@ -318,14 +390,24 @@ impl Tui {
|
||||
let mut y = area.y;
|
||||
|
||||
// Process count.
|
||||
if let Some(plugin) = engine.plugins.get_mut("processcount") {
|
||||
if plugin.is_enabled() {
|
||||
let ctx = render_ctx(args, &engine.runtime, right_width as usize);
|
||||
let lines = split_lines(plugin.render(&ctx));
|
||||
let height = (lines.len() as u16).min(2);
|
||||
draw_lines(frame, Rect { x: right_x, y, width: right_width, height }, &lines, args);
|
||||
y += height;
|
||||
}
|
||||
if let Some(plugin) = engine.plugins.get_mut("processcount")
|
||||
&& plugin.is_enabled()
|
||||
{
|
||||
let ctx = render_ctx(args, &engine.runtime, right_width as usize);
|
||||
let lines = split_lines(plugin.render(&ctx));
|
||||
let height = (lines.len() as u16).min(2);
|
||||
draw_lines(
|
||||
frame,
|
||||
Rect {
|
||||
x: right_x,
|
||||
y,
|
||||
width: right_width,
|
||||
height,
|
||||
},
|
||||
&lines,
|
||||
args,
|
||||
);
|
||||
y += height;
|
||||
}
|
||||
|
||||
// Alerts footer (up to 4 lines).
|
||||
@@ -334,20 +416,40 @@ impl Tui {
|
||||
let list_height = area.y + area.height - y;
|
||||
let process_height = list_height.saturating_sub(alert_height);
|
||||
|
||||
let list_name = if args.programs { "programlist" } else { "processlist" };
|
||||
if let Some(plugin) = engine.plugins.get_mut(list_name) {
|
||||
if plugin.is_enabled() && process_height > 1 {
|
||||
let ctx = render_ctx(args, &engine.runtime, right_width as usize);
|
||||
let mut lines = split_lines(plugin.render(&ctx));
|
||||
lines.truncate(process_height as usize);
|
||||
draw_lines(frame, Rect { x: right_x, y, width: right_width, height: process_height }, &lines, args);
|
||||
}
|
||||
let list_name = if args.programs {
|
||||
"programlist"
|
||||
} else {
|
||||
"processlist"
|
||||
};
|
||||
if let Some(plugin) = engine.plugins.get_mut(list_name)
|
||||
&& plugin.is_enabled()
|
||||
&& process_height > 1
|
||||
{
|
||||
let ctx = render_ctx(args, &engine.runtime, right_width as usize);
|
||||
let mut lines = split_lines(plugin.render(&ctx));
|
||||
lines.truncate(process_height as usize);
|
||||
draw_lines(
|
||||
frame,
|
||||
Rect {
|
||||
x: right_x,
|
||||
y,
|
||||
width: right_width,
|
||||
height: process_height,
|
||||
},
|
||||
&lines,
|
||||
args,
|
||||
);
|
||||
}
|
||||
y += process_height;
|
||||
if alert_height > 0 {
|
||||
draw_lines(
|
||||
frame,
|
||||
Rect { x: right_x, y, width: right_width, height: alert_height },
|
||||
Rect {
|
||||
x: right_x,
|
||||
y,
|
||||
width: right_width,
|
||||
height: alert_height,
|
||||
},
|
||||
&event_lines,
|
||||
args,
|
||||
);
|
||||
@@ -360,14 +462,20 @@ impl Tui {
|
||||
if events.is_empty() {
|
||||
return lines;
|
||||
}
|
||||
lines.push(vec![StatLine::new("EVENTS HISTORY").decoration(Decoration::Title)]);
|
||||
lines.push(vec![
|
||||
StatLine::new("EVENTS HISTORY").decoration(Decoration::Title),
|
||||
]);
|
||||
for event in events.events.iter().rev().take(4) {
|
||||
let state = match event.state.as_str() {
|
||||
"CRITICAL" => Decoration::CriticalLog,
|
||||
"WARNING" => Decoration::WarningLog,
|
||||
_ => Decoration::Default,
|
||||
};
|
||||
let end = if event.is_ongoing() { String::new() } else { " (ended)".to_string() };
|
||||
let end = if event.is_ongoing() {
|
||||
String::new()
|
||||
} else {
|
||||
" (ended)".to_string()
|
||||
};
|
||||
lines.push(vec![
|
||||
StatLine::new(format!("{} ", event.state)).decoration(state),
|
||||
StatLine::new(format!("{} (avg {:.1}){}", event.r#type, event.avg, end)),
|
||||
@@ -401,7 +509,9 @@ impl Tui {
|
||||
Line::from("4 Full quicklook"),
|
||||
Line::from("5 Disable top menu"),
|
||||
Line::from("6 Mean GPU mode"),
|
||||
Line::from("a c m i o p t u Sort processes (auto/cpu/mem/io/cpu_time/name/time/user)"),
|
||||
Line::from(
|
||||
"a c m i o p t u Sort processes (auto/cpu/mem/io/cpu_time/name/time/user)",
|
||||
),
|
||||
Line::from("</> Cycle sort key"),
|
||||
Line::from("UP/DOWN Select process"),
|
||||
Line::from("+ / - Increase/decrease nice level"),
|
||||
@@ -420,7 +530,12 @@ impl Tui {
|
||||
];
|
||||
let block = Block::default().borders(Borders::ALL).title("Help");
|
||||
frame.render_widget(Clear, area);
|
||||
frame.render_widget(Paragraph::new(lines).block(block).wrap(Wrap { trim: false }), area);
|
||||
frame.render_widget(
|
||||
Paragraph::new(lines)
|
||||
.block(block)
|
||||
.wrap(Wrap { trim: false }),
|
||||
area,
|
||||
);
|
||||
}
|
||||
|
||||
fn handle_key(&mut self, engine: &mut Engine, key: KeyEvent) {
|
||||
@@ -435,7 +550,11 @@ impl Tui {
|
||||
KeyCode::Enter => {
|
||||
let filter = self.input.clone();
|
||||
let mut procs = processes().lock().unwrap();
|
||||
procs.filter.set_filter(if filter.is_empty() { None } else { Some(&filter) });
|
||||
procs.filter.set_filter(if filter.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(&filter)
|
||||
});
|
||||
self.popup = Popup::None;
|
||||
}
|
||||
KeyCode::Esc => self.popup = Popup::None,
|
||||
@@ -485,7 +604,9 @@ impl Tui {
|
||||
args.meangpu = !args.meangpu;
|
||||
engine.runtime.meangpu = args.meangpu;
|
||||
}
|
||||
KeyCode::Char('/') => engine.runtime.process_short_name = !engine.runtime.process_short_name,
|
||||
KeyCode::Char('/') => {
|
||||
engine.runtime.process_short_name = !engine.runtime.process_short_name
|
||||
}
|
||||
KeyCode::Char('a') => set_sort(engine, "auto"),
|
||||
KeyCode::Char('c') => set_sort(engine, "cpu_percent"),
|
||||
KeyCode::Char('m') => set_sort(engine, "memory_percent"),
|
||||
@@ -502,7 +623,13 @@ impl Tui {
|
||||
KeyCode::Char('-') => nice_change(engine, false),
|
||||
KeyCode::Char('k') => self.popup = Popup::Kill,
|
||||
KeyCode::Char('f') => {
|
||||
self.input = processes().lock().unwrap().filter.filter_input().unwrap_or("").to_string();
|
||||
self.input = processes()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.filter
|
||||
.filter_input()
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
self.popup = Popup::Filter;
|
||||
}
|
||||
KeyCode::Char('E') => processes().lock().unwrap().filter.set_filter(None),
|
||||
@@ -521,12 +648,16 @@ impl Tui {
|
||||
KeyCode::Char('L') => args.diskio_latency = !args.diskio_latency,
|
||||
KeyCode::Char('F') => engine.runtime.fs_free_space = !engine.runtime.fs_free_space,
|
||||
KeyCode::Char('S') => engine.runtime.sparkline = !engine.runtime.sparkline,
|
||||
KeyCode::Char('M') => engine.runtime.reset_minmax_tag = !engine.runtime.reset_minmax_tag,
|
||||
KeyCode::Char('M') => {
|
||||
engine.runtime.reset_minmax_tag = !engine.runtime.reset_minmax_tag
|
||||
}
|
||||
KeyCode::Char('j') => {
|
||||
args.programs = !args.programs;
|
||||
engine.runtime.programs = args.programs;
|
||||
}
|
||||
KeyCode::Char(c @ ('d' | 'n' | 's' | 'l' | 'D' | 'C' | 'I' | 'V' | 'W' | 'P' | 'K' | 'R')) => {
|
||||
KeyCode::Char(
|
||||
c @ ('d' | 'n' | 's' | 'l' | 'D' | 'C' | 'I' | 'V' | 'W' | 'P' | 'K' | 'R'),
|
||||
) => {
|
||||
toggle_plugin_by_key(engine, c);
|
||||
}
|
||||
_ => {}
|
||||
@@ -534,8 +665,16 @@ impl Tui {
|
||||
}
|
||||
}
|
||||
|
||||
fn render_ctx<'a>(args: &'a Args, runtime: &'a glances_core::Runtime, max_width: usize) -> RenderContext<'a> {
|
||||
RenderContext { args, runtime, max_width }
|
||||
fn render_ctx<'a>(
|
||||
args: &'a Args,
|
||||
runtime: &'a glances_core::Runtime,
|
||||
max_width: usize,
|
||||
) -> RenderContext<'a> {
|
||||
RenderContext {
|
||||
args,
|
||||
runtime,
|
||||
max_width,
|
||||
}
|
||||
}
|
||||
|
||||
fn quicklook_width(width: u16) -> u16 {
|
||||
@@ -587,7 +726,11 @@ fn draw_lines(frame: &mut Frame, area: Rect, lines: &[Vec<StatLine>], args: &Arg
|
||||
}
|
||||
|
||||
fn style_for(decoration: Decoration, args: &Args) -> Style {
|
||||
let bold = if args.disable_bold { Modifier::empty() } else { Modifier::BOLD };
|
||||
let bold = if args.disable_bold {
|
||||
Modifier::empty()
|
||||
} else {
|
||||
Modifier::BOLD
|
||||
};
|
||||
let bg = args.disable_bg;
|
||||
match decoration {
|
||||
Decoration::Default | Decoration::Password => Style::default(),
|
||||
@@ -596,7 +739,9 @@ fn style_for(decoration: Decoration, args: &Args) -> Style {
|
||||
Style::default().add_modifier(bold | Modifier::UNDERLINED)
|
||||
}
|
||||
Decoration::Title => Style::default().add_modifier(bold),
|
||||
Decoration::Ok | Decoration::Process | Decoration::Status => Style::default().fg(Color::Green),
|
||||
Decoration::Ok | Decoration::Process | Decoration::Status => {
|
||||
Style::default().fg(Color::Green)
|
||||
}
|
||||
Decoration::Max => Style::default().fg(Color::Green).add_modifier(bold),
|
||||
Decoration::Careful | Decoration::Info => Style::default().fg(Color::Blue),
|
||||
Decoration::CarefulLog => {
|
||||
@@ -630,7 +775,9 @@ fn style_for(decoration: Decoration, args: &Args) -> Style {
|
||||
}
|
||||
}
|
||||
Decoration::CpuTime => Style::default().fg(Color::Magenta),
|
||||
Decoration::ProcessSelected => Style::default().fg(Color::Green).add_modifier(bold | Modifier::UNDERLINED),
|
||||
Decoration::ProcessSelected => Style::default()
|
||||
.fg(Color::Green)
|
||||
.add_modifier(bold | Modifier::UNDERLINED),
|
||||
Decoration::Error => Style::default().fg(Color::Red),
|
||||
Decoration::Separator => Style::default().fg(Color::DarkGray),
|
||||
}
|
||||
@@ -643,7 +790,15 @@ fn set_sort(_engine: &mut Engine, key: &str) {
|
||||
}
|
||||
|
||||
fn cycle_sort(engine: &mut Engine, forward: bool) {
|
||||
const KEYS: [&str; 7] = ["cpu_percent", "memory_percent", "username", "cpu_times", "io_counters", "name", "cpu_num"];
|
||||
const KEYS: [&str; 7] = [
|
||||
"cpu_percent",
|
||||
"memory_percent",
|
||||
"username",
|
||||
"cpu_times",
|
||||
"io_counters",
|
||||
"name",
|
||||
"cpu_num",
|
||||
];
|
||||
let current = processes().lock().unwrap().sort_key.clone();
|
||||
let index = KEYS.iter().position(|k| *k == current).unwrap_or(0);
|
||||
let next = if forward {
|
||||
@@ -680,7 +835,11 @@ fn nice_change(engine: &mut Engine, increase: bool) {
|
||||
}
|
||||
|
||||
fn toggle_processes(engine: &mut Engine) {
|
||||
let enabled = engine.plugins.get("processlist").map(|p| p.is_enabled()).unwrap_or(false);
|
||||
let enabled = engine
|
||||
.plugins
|
||||
.get("processlist")
|
||||
.map(|p| p.is_enabled())
|
||||
.unwrap_or(false);
|
||||
for name in ["processcount", "processlist", "programlist"] {
|
||||
if let Some(plugin) = engine.plugins.get_mut(name) {
|
||||
plugin.set_enabled(!enabled);
|
||||
@@ -752,7 +911,13 @@ mod tests {
|
||||
fn test_tui_layout_renders() {
|
||||
use clap::Parser;
|
||||
use glances_core::Config;
|
||||
let mut args = Args::parse_from(["glances", "--disable-plugin", "all", "--enable-plugin", "cpu,mem,load,processlist,processcount,network,fs,diskio,now,system,uptime,quicklook"]);
|
||||
let mut args = Args::parse_from([
|
||||
"glances",
|
||||
"--disable-plugin",
|
||||
"all",
|
||||
"--enable-plugin",
|
||||
"cpu,mem,load,processlist,processcount,network,fs,diskio,now,system,uptime,quicklook",
|
||||
]);
|
||||
args.time = Some(1.0);
|
||||
let config = Config::empty(false);
|
||||
let mut engine = Engine::new(args.clone(), config);
|
||||
@@ -760,8 +925,14 @@ mod tests {
|
||||
engine.update();
|
||||
let backend = TestBackend::new(140, 40);
|
||||
let mut terminal = ratatui::Terminal::new(backend).unwrap();
|
||||
let tui = Tui { popup: Popup::None, input: String::new(), quit: false };
|
||||
terminal.draw(|frame| draw_frame(frame, &mut engine, &tui)).unwrap();
|
||||
let tui = Tui {
|
||||
popup: Popup::None,
|
||||
input: String::new(),
|
||||
quit: false,
|
||||
};
|
||||
terminal
|
||||
.draw(|frame| draw_frame(frame, &mut engine, &tui))
|
||||
.unwrap();
|
||||
let text = buffer_to_string(terminal.backend().buffer());
|
||||
println!("{text}");
|
||||
assert!(text.contains("CPU"));
|
||||
|
||||
Reference in New Issue
Block a user