Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change: change how disk, temp, and net filters in config are set #1481

Merged
merged 3 commits into from
Jun 16, 2024
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `mem_as_value` is now `process_memory_as_value`.
- [#1472](https://github.com/ClementTsang/bottom/pull/1472): The following config fields have changed names:
- `mem_as_value` is now `process_memory_as_value`.
- [#1481](https://github.com/ClementTsang/bottom/pull/1481): The following config fields have changed names:
- `disk_filter` is now `disk.name_filter`.
- `mount_filter` is now `disk.mount_filter`.
- `temp_filter` is now `temperature.sensor_filter`
- `net_filter` is now `network.interface_filter`

### Bug Fixes

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ clap_complete_nushell = "4.5.1"
clap_complete_fig = "4.5.0"
clap_mangen = "0.2.20"
indoc = "2.0.5"
# schemars = "0.8.21"

[package.metadata.deb]
section = "utility"
Expand Down
73 changes: 39 additions & 34 deletions sample_configs/default_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,53 @@
# How much data is stored at once in terms of time.
#retention = "10m"

# These are flags around the process widget.

# Processes widget configuration
#[processes]
# The columns shown by the process widget. The following columns are supported:
# PID, Name, CPU%, Mem%, R/s, W/s, T.Read, T.Write, User, State, Time, GMem%, GPU%
#columns = ["PID", "Name", "CPU%", "Mem%", "R/s", "W/s", "T.Read", "T.Write", "User", "State", "GMEM%", "GPU%"]

# [cpu]
# CPU widget configuration
#[cpu]
# One of "all" (default), "average"/"avg"
# default = "average"

# Disk widget configuration
#[disk]
#[disk.name_filter]
#is_list_ignored = true
#list = ["/dev/sda\\d+", "/dev/nvme0n1p2"]
#regex = true
#case_sensitive = false
#whole_word = false

#[disk.mount_filter]
#is_list_ignored = true
#list = ["/mnt/.*", "/boot"]
#regex = true
#case_sensitive = false
#whole_word = false

# Temperature widget configuration
#[temperature]
#[temperature.sensor_filter]
#is_list_ignored = true
#list = ["cpu", "wifi"]
#regex = false
#case_sensitive = false
#whole_word = false

# Network widget configuration
#[network]
#[network.interface_filter]
#is_list_ignored = true
#list = ["virbr0.*"]
#regex = true
#case_sensitive = false
#whole_word = false

# These are all the components that support custom theming. Note that colour support
# will depend on terminal support.

#[colors] # Uncomment if you want to use custom colors
# Represents the colour of table headers (processes, CPU, disks, temperature).
#table_header_color="LightBlue"
Expand Down Expand Up @@ -160,33 +195,3 @@
# [[row.child]]
# type="proc"
# default=true

# Filters - you can hide specific temperature sensors, network interfaces, and disks using filters. This is admittedly
# a bit hard to use as of now, and there is a planned in-app interface for managing this in the future:
#[disk_filter]
#is_list_ignored = true
#list = ["/dev/sda\\d+", "/dev/nvme0n1p2"]
#regex = true
#case_sensitive = false
#whole_word = false

#[mount_filter]
#is_list_ignored = true
#list = ["/mnt/.*", "/boot"]
#regex = true
#case_sensitive = false
#whole_word = false

#[temp_filter]
#is_list_ignored = true
#list = ["cpu", "wifi"]
#regex = false
#case_sensitive = false
#whole_word = false

#[net_filter]
#is_list_ignored = true
#list = ["virbr0.*"]
#regex = true
#case_sensitive = false
#whole_word = false
57 changes: 34 additions & 23 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,8 @@ impl App {
pws.is_sort_open = !pws.is_sort_open;
pws.force_rerender = true;

// If the sort is now open, move left. Otherwise, if the proc sort was selected, force move right.
// If the sort is now open, move left. Otherwise, if the proc sort was selected,
// force move right.
if pws.is_sort_open {
pws.sort_table.set_position(pws.table.sort_index());
self.move_widget_selection(&WidgetDirection::Left);
Expand Down Expand Up @@ -1054,13 +1055,15 @@ impl App {
.widget_states
.get_mut(&(self.current_widget.widget_id - 1))
{
// Traverse backwards from the current cursor location until you hit non-whitespace characters,
// then continue to traverse (and delete) backwards until you hit a whitespace character. Halt.
// Traverse backwards from the current cursor location until you hit
// non-whitespace characters, then continue to traverse (and
// delete) backwards until you hit a whitespace character. Halt.

// So... first, let's get our current cursor position in terms of char indices.
let end_index = proc_widget_state.cursor_char_index();

// Then, let's crawl backwards until we hit our location, and store the "head"...
// Then, let's crawl backwards until we hit our location, and store the
// "head"...
let query = proc_widget_state.current_search_query();
let mut start_index = 0;
let mut saw_non_whitespace = false;
Expand Down Expand Up @@ -1617,7 +1620,8 @@ impl App {
if let Some(basic_table_widget_state) =
&mut self.states.basic_table_widget_state
{
// We also want to move towards Proc if we had set it to ProcSort.
// We also want to move towards Proc if we had set it to
// ProcSort.
if let BottomWidgetType::ProcSort =
basic_table_widget_state.currently_displayed_widget_type
{
Expand Down Expand Up @@ -2505,20 +2509,22 @@ impl App {
}
}

/// Moves the mouse to the widget that was clicked on, then propagates the click down to be
/// handled by the widget specifically.
/// Moves the mouse to the widget that was clicked on, then propagates the
/// click down to be handled by the widget specifically.
pub fn on_left_mouse_up(&mut self, x: u16, y: u16) {
// Pretty dead simple - iterate through the widget map and go to the widget where the click
// is within.
// Pretty dead simple - iterate through the widget map and go to the widget
// where the click is within.

// TODO: [REFACTOR] might want to refactor this, it's really ugly.
// TODO: [REFACTOR] Might wanna refactor ALL state things in general, currently everything
// is grouped up as an app state. We should separate stuff like event state and gui state and etc.
// TODO: [REFACTOR] Might wanna refactor ALL state things in general, currently
// everything is grouped up as an app state. We should separate stuff
// like event state and gui state and etc.

// TODO: [MOUSE] double click functionality...? We would do this above all other actions and SC if needed.
// TODO: [MOUSE] double click functionality...? We would do this above all
// other actions and SC if needed.

// Short circuit if we're in basic table... we might have to handle the basic table arrow
// case here...
// Short circuit if we're in basic table... we might have to handle the basic
// table arrow case here...

if let Some(bt) = &mut self.states.basic_table_widget_state {
if let (
Expand Down Expand Up @@ -2582,8 +2588,8 @@ impl App {
}
}

// Second short circuit --- are we in the dd dialog state? If so, only check yes/no/signals
// and bail after.
// Second short circuit --- are we in the dd dialog state? If so, only check
// yes/no/signals and bail after.
if self.is_in_dialog() {
match self.delete_dialog_state.button_positions.iter().find(
|(tl_x, tl_y, br_x, br_y, _idx)| {
Expand Down Expand Up @@ -2649,7 +2655,8 @@ impl App {
) {
let border_offset = u16::from(self.is_drawing_border());

// This check ensures the click isn't actually just clicking on the bottom border.
// This check ensures the click isn't actually just clicking on the bottom
// border.
if y < (brc_y - border_offset) {
match &self.current_widget.widget_type {
BottomWidgetType::Proc
Expand Down Expand Up @@ -2682,8 +2689,10 @@ impl App {

self.change_process_position(change);

// If in tree mode, also check to see if this click is on
// the same entry as the already selected one - if it is,
// If in tree mode, also check to see if this click is
// on
// the same entry as the already selected one - if it
// is,
// then we minimize.
if is_tree_mode && change == 0 {
self.toggle_collapsing_process_branch();
Expand Down Expand Up @@ -2755,8 +2764,9 @@ impl App {
_ => {}
}
} else {
// We might have clicked on a header! Check if we only exceeded the table + border offset, and
// it's implied we exceeded the gap offset.
// We might have clicked on a header! Check if we only exceeded the
// table + border offset, and it's implied
// we exceeded the gap offset.
if clicked_entry == border_offset {
match &self.current_widget.widget_type {
BottomWidgetType::Proc => {
Expand Down Expand Up @@ -2851,8 +2861,9 @@ impl App {

/// A quick and dirty way to handle paste events.
pub fn handle_paste(&mut self, paste: String) {
// Partially copy-pasted from the single-char variant; should probably clean up this process in the future.
// In particular, encapsulate this entire logic and add some tests to make it less potentially error-prone.
// Partially copy-pasted from the single-char variant; should probably clean up
// this process in the future. In particular, encapsulate this entire
// logic and add some tests to make it less potentially error-prone.
let is_in_search_widget = self.is_in_search_widget();
if let Some(proc_widget_state) = self
.states
Expand Down
15 changes: 8 additions & 7 deletions src/app/data_farmer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
//! a better name for the file. Since I called data collection "harvesting",
//! then this is the farmer I guess.
//!
//! Essentially the main goal is to shift the initial calculation and distribution
//! of joiner points and data to one central location that will only do it
//! *once* upon receiving the data --- as opposed to doing it on canvas draw,
//! which will be a costly process.
//! Essentially the main goal is to shift the initial calculation and
//! distribution of joiner points and data to one central location that will
//! only do it *once* upon receiving the data --- as opposed to doing it on
//! canvas draw, which will be a costly process.
//!
//! This will also handle the *cleaning* of stale data. That should be done
//! in some manner (timer on another thread, some loop) that will occasionally
Expand Down Expand Up @@ -102,8 +102,8 @@ impl ProcessData {
/// collected, and what is needed to convert into a displayable form.
///
/// If the app is *frozen* - that is, we do not want to *display* any changing
/// data, keep updating this. As of 2021-09-08, we just clone the current collection
/// when it freezes to have a snapshot floating around.
/// data, keep updating this. As of 2021-09-08, we just clone the current
/// collection when it freezes to have a snapshot floating around.
///
/// Note that with this method, the *app* thread is responsible for cleaning -
/// not the data collector.
Expand Down Expand Up @@ -355,7 +355,8 @@ impl DataCollection {
#[cfg(feature = "zfs")]
{
if !device.name.starts_with('/') {
Some(device.name.as_str()) // use the whole zfs dataset name
Some(device.name.as_str()) // use the whole zfs
// dataset name
} else {
device.name.split('/').last()
}
Expand Down
5 changes: 3 additions & 2 deletions src/app/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ impl Filter {
#[inline]
pub(crate) fn keep_entry(&self, value: &str) -> bool {
if self.has_match(value) {
// If a match is found, then if we wanted to ignore if we match, return false. If we want
// to keep if we match, return true. Thus, return the inverse of `is_list_ignored`.
// If a match is found, then if we wanted to ignore if we match, return false.
// If we want to keep if we match, return true. Thus, return the
// inverse of `is_list_ignored`.
!self.is_list_ignored
} else {
self.is_list_ignored
Expand Down
5 changes: 3 additions & 2 deletions src/app/frozen_state.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use super::DataCollection;

/// The [`FrozenState`] indicates whether the application state should be frozen. It is either not frozen or
/// frozen and containing a copy of the state at the time.
/// The [`FrozenState`] indicates whether the application state should be
/// frozen. It is either not frozen or frozen and containing a copy of the state
/// at the time.
pub enum FrozenState {
NotFrozen,
Frozen(Box<DataCollection>),
Expand Down
6 changes: 4 additions & 2 deletions src/app/process_killer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! This file is meant to house (OS specific) implementations on how to kill processes.
//! This file is meant to house (OS specific) implementations on how to kill
//! processes.

#[cfg(target_os = "windows")]
use windows::Win32::{
Expand Down Expand Up @@ -61,7 +62,8 @@ pub fn kill_process_given_pid(pid: Pid) -> crate::utils::error::Result<()> {
/// Kills a process, given a PID, for UNIX.
#[cfg(target_family = "unix")]
pub fn kill_process_given_pid(pid: Pid, signal: usize) -> crate::utils::error::Result<()> {
// SAFETY: the signal should be valid, and we act properly on an error (exit code not 0).
// SAFETY: the signal should be valid, and we act properly on an error (exit
// code not 0).

let output = unsafe { libc::kill(pid, signal as i32) };
if output != 0 {
Expand Down
Loading