other: partial migration of network/memory config options from flags (#2062)

This change moves some options to a more appropriate section for the config file. This only deprecates the old options for now, so they're still valid, but we will remove them later (maybe after the next stable release, to give warning).

One thing I want to do for the legend position options is maybe expand it, and now is the best time to do so, but for now I'm just copying it over verbatim.

The deprecated options will also emit a warning to stderr.

This PR also contains a driveby to alias `[network]` to `[network_graph]`.
This commit is contained in:
Clement Tsang
2026-05-12 04:59:59 -04:00
committed by GitHub
parent 859ec27a05
commit edc295e3ed
22 changed files with 369 additions and 141 deletions
+2
View File
@@ -45,6 +45,8 @@ That said, these are more guidelines rather than hard rules, though the project
- [#2031](https://github.com/ClementTsang/bottom/pull/2031): Tweak display/hiding logic for a graph widget's legend.
- [#2039](https://github.com/ClementTsang/bottom/pull/2039): Replace `hide_table_gap` with `table_gap`.
- [#2061](https://github.com/ClementTsang/bottom/pull/2061): Take cgroup into account for RAM/swap usage.
- [#2062](https://github.com/ClementTsang/bottom/pull/2062): Rename `[network]` to `[network_graph]` in the config file; `[network]` remains valid as an alias.
- [#2062](https://github.com/ClementTsang/bottom/pull/2062): Move network and memory graph config file options from flags to be under `[network_graph]` and `[memory_graph]`.
### Other
@@ -0,0 +1,9 @@
# Memory Graph
## Settings
If you want to change some of the default behaviour of the memory graph widget, you can configure some things in the config file.
| Field | Type | Functionality |
| ----------------- | ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------- |
| `legend_position` | String (one of ["none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right"]) | Where to place the legend for the memory widget. |
@@ -0,0 +1,38 @@
# Network Graph
## Settings
If you want to change some of the default behaviour of the network graph widget, you can configure some things in the config file.
| Field | Type | Functionality |
| ------------------- | ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `show_packets` | Boolean | Displays packet rate and average packet size info. |
| `legend_position` | String (one of ["none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right"]) | Where to place the legend for the network widget. |
| `use_bytes` | Boolean | Displays the network widget using bytes. Defaults to bits. |
| `use_log` | Boolean | Displays the network widget with a log scale. Defaults to a non-log scale. |
| `use_binary_prefix` | Boolean | Displays the network widget with a binary prefix (e.g. kibibits) rather than a decimal prefix (e.g. kilobits). Defaults to decimal prefixes. |
## Filtering Entries
You can filter out what entries to show by configuring `[network_graph.interface_filter]` .
In particular, you can set a list of things to filter with by setting `list`, and configure how that list is processed with the other options.
For example, here we are ignoring any entry with a name that matches the regex `eth0.*`, or specifically `virbr0`.
```toml
[network_graph.interface_filter]
# Whether to ignore any matches. Defaults to true.
is_list_ignored = true
# A list of filters to try and match.
list = ["virbr0", "eth0slab"]
# Whether to use regex. Defaults to false.
regex = true
# Whether to be case-sensitive. Defaults to false.
case_sensitive = false
# Whether to require matching the whole word. Defaults to false.
whole_word = false
```
@@ -1,34 +0,0 @@
# Network
## Settings
If you want to change some of the default behaviour of the network widget, you can configure some things in the config file.
| Field | Type | Functionality |
| -------------- | ------- | -------------------------------------------------- |
| `show_packets` | Boolean | Displays packet rate and average packet size info. |
## Filtering Entries
You can filter out what entries to show by configuring `[network.interface_filter]` .
In particular, you can set a list of things to filter with by setting `list`, and configure how that list is processed with the other options.
For example, here we are ignoring any entry with a name that matches `/dev/sda<NUMBERS>`, or specifically `/dev/nvme0n1p2`.
```toml
[network.interface_filter]
# Whether to ignore any matches. Defaults to true.
is_list_ignored = true
# A list of filters to try and match.
list = ["virbr0.*"]
# Whether to use regex. Defaults to false.
regex = true
# Whether to be case-sensitive. Defaults to false.
case_sensitive = false
# Whether to require matching the whole word. Defaults to false.
whole_word = false
```
+4 -3
View File
@@ -162,8 +162,8 @@ nav:
- "Basic Mode": usage/basic-mode.md
- "Widgets":
- "CPU Widget": usage/widgets/cpu.md
- "Memory Widget": usage/widgets/memory.md
- "Network Widget": usage/widgets/network.md
- "Memory Graph Widget": usage/widgets/memory-graph.md
- "Network Graph Widget": usage/widgets/network-graph.md
- "Process Widget": usage/widgets/process.md
- "Disk Widget": usage/widgets/disk.md
- "Temperature Widget": usage/widgets/temperature-table.md
@@ -176,7 +176,8 @@ nav:
- configuration/config-file/index.md
- "CPU Widget": configuration/config-file/cpu.md
- "Disk Table Widget": configuration/config-file/disk-table.md
- "Network Widget": configuration/config-file/network.md
- "Memory Graph Widget": configuration/config-file/memory-graph.md
- "Network Graph Widget": configuration/config-file/network-graph.md
- "Processes Widget": configuration/config-file/processes.md
- "Temperature Table Widget": configuration/config-file/temperature-table.md
- "Temperature Graph Widget": configuration/config-file/temperature-graph.md
+2 -9
View File
@@ -134,7 +134,6 @@
# Where to place the legend for the network widget. One of "none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right".
#network_legend = "top-right"
# Processes widget configuration
#[processes]
# The columns shown by the process widget. The following columns are supported (the GPU columns are only available if the GPU feature is enabled when built):
@@ -148,7 +147,6 @@
# Gather process child thread information
#get_threads = false
# CPU widget configuration
#[cpu]
# One of "all" (default), "average"/"avg"
@@ -157,7 +155,6 @@
# Whether to show a decimal place for CPU usage values.
#show_decimal = false
# Disk widget configuration
#[disk]
@@ -206,7 +203,6 @@
# Whether to require matching the whole word. Defaults to false.
#whole_word = false
# Temperature widget configuration
#[temperature]
@@ -233,7 +229,6 @@
# Whether to require matching the whole word. Defaults to false.
#whole_word = false
# Temperature graph widget configuration
#[temperature_graph]
@@ -261,11 +256,10 @@
# Whether to require matching the whole word. Defaults to false.
#whole_word = false
# Network widget configuration
#[network]
#[network_graph]
# By default, there are no network interface filters enabled. An example use case is provided below.
#[network.interface_filter]
#[network_graph.interface_filter]
# Whether to ignore any matches. Defaults to true.
#is_list_ignored = true
@@ -281,7 +275,6 @@
# Whether to require matching the whole word. Defaults to false.
#whole_word = false
# These are all the components that support custom theming. Note that colour support
# will depend on terminal support.
#[styles] # Uncomment if you want to use custom styling
+102 -51
View File
@@ -35,10 +35,20 @@
}
]
},
"network": {
"memory_graph": {
"anyOf": [
{
"$ref": "#/$defs/NetworkConfig"
"$ref": "#/$defs/MemoryGraphConfig"
},
{
"type": "null"
}
]
},
"network_graph": {
"anyOf": [
{
"$ref": "#/$defs/NetworkGraphConfig"
},
{
"type": "null"
@@ -100,33 +110,33 @@
"description": "Styling specific to the battery widget.",
"type": "object",
"properties": {
"high_battery_color": {
"high_battery_colour": {
"description": "The colour of the battery widget bar when the battery is over 50%.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
}
]
},
"low_battery_color": {
"low_battery_colour": {
"description": "The colour of the battery widget bar when the battery is under 10%.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
}
]
},
"medium_battery_color": {
"medium_battery_colour": {
"description": "The colour of the battery widget bar when the battery between 10% to\n50%.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
@@ -135,7 +145,7 @@
}
}
},
"ColorStr": {
"ColourStr": {
"type": "string"
},
"CpuConfig": {
@@ -167,36 +177,36 @@
"description": "Styling specific to the CPU widget.",
"type": "object",
"properties": {
"all_entry_color": {
"all_entry_colour": {
"description": "The colour of the \"All\" CPU label.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
}
]
},
"avg_entry_color": {
"avg_entry_colour": {
"description": "The colour of the average CPU label and graph line.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
}
]
},
"cpu_core_colors": {
"cpu_core_colours": {
"description": "Colour of each CPU threads' label and graph line. Read in order.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
}
}
}
@@ -597,11 +607,11 @@
"description": "General styling for graph widgets.",
"type": "object",
"properties": {
"graph_color": {
"graph_colour": {
"description": "The general colour of the parts of the graph.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
@@ -651,58 +661,71 @@
"list"
]
},
"MemoryGraphConfig": {
"description": "Memory-related configuration file options.",
"type": "object",
"properties": {
"legend_position": {
"description": "Where to place the legend for the memory chart widget.",
"type": [
"string",
"null"
]
}
}
},
"MemoryStyle": {
"description": "Styling specific to the memory widget.",
"type": "object",
"properties": {
"arc_color": {
"arc_colour": {
"description": "The colour of the ARC label and graph line.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
}
]
},
"cache_color": {
"cache_colour": {
"description": "The colour of the cache label and graph line. Does not do anything on\nWindows.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
}
]
},
"gpu_colors": {
"gpu_colours": {
"description": "Colour of each GPU's memory label and graph line. Read in order.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
}
},
"ram_color": {
"ram_colour": {
"description": "The colour of the RAM label and graph line.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
}
]
},
"swap_color": {
"swap_colour": {
"description": "The colour of the swap label and graph line.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
@@ -711,7 +734,7 @@
}
}
},
"NetworkConfig": {
"NetworkGraphConfig": {
"description": "Network configuration.",
"type": "object",
"properties": {
@@ -726,12 +749,40 @@
}
]
},
"legend_position": {
"description": "Where to place the legend for the network chart widget.",
"type": [
"string",
"null"
]
},
"show_packets": {
"description": "Displays packet rate and average packet size info.",
"type": [
"boolean",
"null"
]
},
"use_binary_prefix": {
"description": "Displays the network widget with a binary prefix (e.g. kibibits) rather than a decimal\nprefix (e.g. kilobits). Defaults to decimal prefixes.",
"type": [
"boolean",
"null"
]
},
"use_bytes": {
"description": "Displays the network widget using bytes. Defaults to bits.",
"type": [
"boolean",
"null"
]
},
"use_log": {
"description": "Displays the network widget with a log scale. Defaults to a non-log scale.",
"type": [
"boolean",
"null"
]
}
}
},
@@ -739,44 +790,44 @@
"description": "Styling specific to the network widget.",
"type": "object",
"properties": {
"rx_color": {
"rx_colour": {
"description": "The colour of the RX (download) label and graph line.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
}
]
},
"rx_total_color": {
"description": "he colour of the total RX (download) label in basic mode.",
"rx_total_colour": {
"description": "The colour of the total RX (download) label in basic mode.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
}
]
},
"tx_color": {
"tx_colour": {
"description": "The colour of the TX (upload) label and graph line.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
}
]
},
"tx_total_color": {
"tx_total_colour": {
"description": "The colour of the total TX (upload) label in basic mode.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
@@ -1123,14 +1174,14 @@
"description": "Styling specific to the temperature graph widget.",
"type": "object",
"properties": {
"temp_graph_color_styles": {
"temp_graph_colour_styles": {
"description": "Colour of each temperature sensor's graph line. Read in order.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
}
}
}
@@ -1150,16 +1201,16 @@
"description": "A style for text.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "object",
"properties": {
"bg_color": {
"bg_colour": {
"description": "A built-in ANSI colour, RGB hex, or RGB colour code.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
@@ -1173,11 +1224,11 @@
"null"
]
},
"color": {
"colour": {
"description": "A built-in ANSI colour, RGB hex, or RGB colour code.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
@@ -1208,22 +1259,22 @@
"description": "General styling for generic widgets.",
"type": "object",
"properties": {
"bg_color": {
"description": "Background color for widgets.",
"bg_colour": {
"description": "Background colour for widgets.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
}
]
},
"border_color": {
"border_colour": {
"description": "The colour of the widgets' borders.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
@@ -1241,11 +1292,11 @@
}
]
},
"selected_border_color": {
"selected_border_colour": {
"description": "The colour of a widget's borders when the widget is selected.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
"$ref": "#/$defs/ColourStr"
},
{
"type": "null"
+24 -5
View File
@@ -64,10 +64,29 @@ mod test {
use super::*;
/// Quick test for filtering w/ regex.
#[test]
fn filter_simple() {
let values = ["eth0slab", "virbr0", "eth0", "wlan0", "lo"];
let filter = Filter {
is_list_ignored: false,
list: vec![Regex::new("virbr0").unwrap(), Regex::new("eth0").unwrap()],
};
assert_eq!(
values
.into_iter()
.filter(|r| filter.should_keep(r))
.collect::<Vec<_>>(),
vec!["eth0slab", "virbr0", "eth0"]
);
}
/// Test based on the issue in <https://github.com/ClementTsang/bottom/pull/1037>.
#[test]
fn filter_is_list_ignored() {
let results = [
let values = [
"CPU socket temperature",
"wifi_0",
"motherboard temperature",
@@ -80,7 +99,7 @@ mod test {
};
assert_eq!(
results
values
.into_iter()
.filter(|r| ignore_true.should_keep(r))
.collect::<Vec<_>>(),
@@ -93,7 +112,7 @@ mod test {
};
assert_eq!(
results
values
.into_iter()
.filter(|r| ignore_false.should_keep(r))
.collect::<Vec<_>>(),
@@ -109,7 +128,7 @@ mod test {
};
assert_eq!(
results
values
.into_iter()
.filter(|r| multi_true.should_keep(r))
.collect::<Vec<_>>(),
@@ -125,7 +144,7 @@ mod test {
};
assert_eq!(
results
values
.into_iter()
.filter(|r| multi_false.should_keep(r))
.collect::<Vec<_>>(),
+2 -2
View File
@@ -512,9 +512,9 @@ pub(crate) const CONFIG_TEXT: &str = r#"# This is a default config file for bott
# Network widget configuration
#[network]
#[network_graph]
# By default, there are no network interface filters enabled. An example use case is provided below.
#[network.interface_filter]
#[network_graph.interface_filter]
# Whether to ignore any matches. Defaults to true.
#is_list_ignored = true
+78 -17
View File
@@ -303,9 +303,11 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
let network_unit_type = get_network_unit_type(args, config);
let network_scale_type = get_network_scale_type(args, config);
let network_use_binary_prefix =
is_flag_enabled!(network_use_binary_prefix, args.network, config);
let network_show_packets = is_flag_enabled_in!(show_packets, args.network, config.network);
// Use + update this again after deprecation
// let network_use_binary_prefix = is_flag_enabled!(network_use_binary_prefix, args.network, config);
let network_use_binary_prefix = get_network_use_binary_prefix(args, config);
let network_show_packets =
is_flag_enabled_in!(show_packets, args.network, config.network_graph);
let proc_columns: Option<IndexSet<ProcWidgetColumn>> = {
config.processes.as_ref().and_then(|cfg| {
@@ -587,9 +589,9 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
.context("Update 'temperature_graph.sensor_filter' in your config file")?,
None => None,
};
let net_interface_filter = match &config.network {
let net_interface_filter = match &config.network_graph {
Some(cfg) => get_ignore_list(&cfg.interface_filter)
.context("Update 'network.interface_filter' in your config file")?,
.context("Update 'network_graph.interface_filter' in your config file")?,
None => None,
};
@@ -781,6 +783,14 @@ macro_rules! parse_ms_option {
}};
}
/// Mark a config option field as deprecated, and what to use instead.
#[inline]
fn deprecated_warning(deprecated_field: &str, new_field: &str) {
eprintln!(
"Warning: The config option '{deprecated_field}' is deprecated and will eventually be removed. Please use '{new_field}' instead.",
);
}
/// How quickly we update data.
#[inline]
fn get_update_rate(args: &BottomArgs, config: &Config) -> OptionResult<u64> {
@@ -1016,8 +1026,14 @@ fn get_ignore_list(ignore_list: &Option<IgnoreList>) -> OptionResult<Option<Filt
fn get_network_unit_type(args: &BottomArgs, config: &Config) -> DataUnit {
if args.network.network_use_bytes {
return DataUnit::Byte;
} else if let Some(use_bytes) = config.network_graph.as_ref().and_then(|cfg| cfg.use_bytes) {
if use_bytes {
return DataUnit::Byte;
}
} else if let Some(flags) = &config.flags {
if let Some(network_use_bytes) = flags.network_use_bytes {
deprecated_warning("network_use_bytes", "network_graph.use_bytes");
if network_use_bytes {
return DataUnit::Byte;
}
@@ -1030,8 +1046,14 @@ fn get_network_unit_type(args: &BottomArgs, config: &Config) -> DataUnit {
fn get_network_scale_type(args: &BottomArgs, config: &Config) -> AxisScaling {
if args.network.network_use_log {
return AxisScaling::Log;
} else if let Some(use_log) = config.network_graph.as_ref().and_then(|cfg| cfg.use_log) {
if use_log {
return AxisScaling::Log;
}
} else if let Some(flags) = &config.flags {
if let Some(network_use_log) = flags.network_use_log {
deprecated_warning("network_use_log", "network_graph.use_log");
if network_use_log {
return AxisScaling::Log;
}
@@ -1041,6 +1063,29 @@ fn get_network_scale_type(args: &BottomArgs, config: &Config) -> AxisScaling {
AxisScaling::Linear
}
fn get_network_use_binary_prefix(args: &BottomArgs, config: &Config) -> bool {
if args.network.network_use_binary_prefix {
return true;
} else if let Some(use_binary_prefix) = config
.network_graph
.as_ref()
.and_then(|cfg| cfg.use_binary_prefix)
{
return use_binary_prefix;
} else if let Some(flags) = &config.flags {
if let Some(network_use_binary_prefix) = flags.network_use_binary_prefix {
deprecated_warning(
"network_use_binary_prefix",
"network_graph.use_binary_prefix",
);
return network_use_binary_prefix;
}
}
false
}
fn get_retention(args: &BottomArgs, config: &Config) -> OptionResult<u64> {
const DEFAULT_RETENTION_MS: u64 = 600 * 1000; // Keep 10 minutes of data.
@@ -1059,7 +1104,8 @@ fn get_retention(args: &BottomArgs, config: &Config) -> OptionResult<u64> {
#[inline]
fn parse_legend_position(
arg: Option<&String>, cfg: Option<&String>, setting: &'static str,
arg: Option<&String>, cfg: Option<&String>, deprecated_cfg: Option<(&String, &'static str)>,
setting: &'static str,
) -> OptionResult<Option<LegendPosition>> {
#[inline]
fn parse_position_or_err<F: FnOnce(&'static str) -> OptionError>(
@@ -1075,6 +1121,10 @@ fn parse_legend_position(
parse_position_or_err(s, setting, OptionError::invalid_arg_value)
} else if let Some(s) = cfg {
parse_position_or_err(s, setting, OptionError::invalid_config_value)
} else if let Some((s, name)) = deprecated_cfg {
// Remove the deprecated args/code paths and copy back to the function above later.
deprecated_warning(name, setting);
parse_position_or_err(s, setting, OptionError::invalid_config_value)
} else {
Ok(Some(LegendPosition::default()))
}
@@ -1085,11 +1135,16 @@ fn get_network_legend_position(
) -> OptionResult<Option<LegendPosition>> {
parse_legend_position(
args.network.network_legend.as_ref(),
config
.network_graph
.as_ref()
.and_then(|cfg| cfg.legend_position.as_ref()),
config
.flags
.as_ref()
.and_then(|flags| flags.network_legend.as_ref()),
"network_legend",
.and_then(|flags| flags.network_legend.as_ref())
.map(|s| (s, "network_legend")),
"network.legend_position",
)
}
@@ -1098,11 +1153,16 @@ fn get_memory_legend_position(
) -> OptionResult<Option<LegendPosition>> {
parse_legend_position(
args.memory.memory_legend.as_ref(),
config
.memory_graph
.as_ref()
.and_then(|cfg| cfg.legend_position.as_ref()),
config
.flags
.as_ref()
.and_then(|flags| flags.memory_legend.as_ref()),
"memory_legend",
.and_then(|flags| flags.memory_legend.as_ref())
.map(|s| (s, "memory_legend")),
"memory.legend_position",
)
}
@@ -1113,6 +1173,7 @@ fn get_temperature_legend_position(config: &Config) -> OptionResult<Option<Legen
.temperature_graph
.as_ref()
.and_then(|settings| settings.legend_position.as_ref()),
None,
"legend_position",
)
}
@@ -1157,7 +1218,7 @@ mod test {
// No arg, no config.
assert_eq!(
parse_legend_position(None, None, setting),
parse_legend_position(None, None, None, setting),
Ok(Some(LegendPosition::default()))
);
@@ -1165,40 +1226,40 @@ mod test {
let arg = " ToP-lEfT ".to_string();
let cfg = "bottom-right".to_string();
assert_eq!(
parse_legend_position(Some(&arg), Some(&cfg), setting),
parse_legend_position(Some(&arg), Some(&cfg), None, setting),
Ok(Some(LegendPosition::TopLeft))
);
// "none" disables the legend, from either source.
let none_arg = "None".to_string();
assert_eq!(
parse_legend_position(Some(&none_arg), None, setting),
parse_legend_position(Some(&none_arg), None, None, setting),
Ok(None)
);
let none_cfg = "none".to_string();
assert_eq!(
parse_legend_position(None, Some(&none_cfg), setting),
parse_legend_position(None, Some(&none_cfg), None, setting),
Ok(None)
);
// Config value is used when no arg is provided.
let cfg_only = "left".to_string();
assert_eq!(
parse_legend_position(None, Some(&cfg_only), setting),
parse_legend_position(None, Some(&cfg_only), None, setting),
Ok(Some(LegendPosition::Left))
);
// Invalid arg value.
let bad_arg = "bad".to_string();
assert_eq!(
parse_legend_position(Some(&bad_arg), None, setting),
parse_legend_position(Some(&bad_arg), None, None, setting),
Err(OptionError::invalid_arg_value(setting))
);
// Invalid config value.
let bad_cfg = "bad".to_string();
assert_eq!(
parse_legend_position(None, Some(&bad_cfg), setting),
parse_legend_position(None, Some(&bad_cfg), None, setting),
Err(OptionError::invalid_config_value(setting))
);
}
+7 -3
View File
@@ -3,7 +3,8 @@ pub mod disk;
pub mod flags;
mod ignore_list;
pub mod layout;
pub mod network;
pub mod memory_graph;
pub mod network_graph;
pub mod process;
pub mod style;
pub mod temperature;
@@ -11,7 +12,7 @@ pub mod temperature_graph;
use disk::DiskConfig;
use flags::GeneralConfig;
use network::NetworkConfig;
use network_graph::NetworkGraphConfig;
use serde::{Deserialize, Serialize};
use style::StyleConfig;
use temperature::TempConfig;
@@ -19,6 +20,7 @@ use temperature_graph::TempGraphConfig;
pub use self::ignore_list::IgnoreList;
use self::{cpu::CpuConfig, layout::Row, process::ProcessesConfig};
use crate::options::config::memory_graph::MemoryGraphConfig;
/// Overall config for `bottom`.
#[derive(Clone, Debug, Default, Deserialize)]
@@ -32,7 +34,9 @@ pub struct Config {
pub(crate) disk: Option<DiskConfig>,
pub(crate) temperature: Option<TempConfig>,
pub(crate) temperature_graph: Option<TempGraphConfig>,
pub(crate) network: Option<NetworkConfig>,
#[serde(alias = "network")]
pub(crate) network_graph: Option<NetworkGraphConfig>,
pub(crate) memory_graph: Option<MemoryGraphConfig>,
pub(crate) cpu: Option<CpuConfig>,
}
+6 -1
View File
@@ -53,7 +53,9 @@ pub(crate) struct GeneralConfig {
pub(crate) disable_click: Option<bool>,
pub(crate) disable_keys: Option<bool>,
pub(crate) no_write: Option<bool>,
pub(crate) network_legend: Option<String>, // TODO: Migrate this to per-widget config
// FIXME: Deprecate this in the future.
pub(crate) network_legend: Option<String>,
// FIXME: Deprecate this in the future.
pub(crate) memory_legend: Option<String>,
pub(crate) process_memory_as_value: Option<bool>,
pub(crate) tree: Option<bool>,
@@ -70,8 +72,11 @@ pub(crate) struct GeneralConfig {
pub(crate) hide_k_threads: Option<bool>,
// #[cfg(feature = "zfs")]
pub(crate) free_arc: Option<bool>,
// FIXME: Deprecate this in the future.
pub(crate) network_use_bytes: Option<bool>,
// FIXME: Deprecate this in the future.
pub(crate) network_use_log: Option<bool>,
// FIXME: Deprecate this in the future.
pub(crate) network_use_binary_prefix: Option<bool>,
pub(crate) disable_gpu: Option<bool>,
pub(crate) enable_cache_memory: Option<bool>,
+14
View File
@@ -0,0 +1,14 @@
//! Memory graph configuration.
use serde::Deserialize;
/// Memory-related configuration file options.
#[derive(Clone, Debug, Default, Deserialize)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
#[cfg_attr(test, serde(deny_unknown_fields), derive(PartialEq, Eq))]
pub struct MemoryGraphConfig {
// TODO: We probably want to make this an enum...? If we want to also support external legends
// (e.g. table-style, list-style) then we probably need a new system outright.
/// Where to place the legend for the memory chart widget.
pub(crate) legend_position: Option<String>,
}
-14
View File
@@ -1,14 +0,0 @@
use serde::Deserialize;
use super::IgnoreList;
/// Network configuration.
#[derive(Clone, Debug, Default, Deserialize)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
#[cfg_attr(test, serde(deny_unknown_fields), derive(PartialEq, Eq))]
pub(crate) struct NetworkConfig {
/// A filter over the network interface names.
pub(crate) interface_filter: Option<IgnoreList>,
/// Displays packet rate and average packet size info.
pub(crate) show_packets: Option<bool>,
}
+30
View File
@@ -0,0 +1,30 @@
use serde::Deserialize;
use super::IgnoreList;
/// Network configuration.
#[derive(Clone, Debug, Default, Deserialize)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
#[cfg_attr(test, serde(deny_unknown_fields), derive(PartialEq, Eq))]
pub(crate) struct NetworkGraphConfig {
/// A filter over the network interface names.
pub(crate) interface_filter: Option<IgnoreList>,
/// Displays packet rate and average packet size info.
pub(crate) show_packets: Option<bool>,
// TODO: We probably want to make this an enum...? If we want to also support external legends
// (e.g. table-style, list-style) then we probably need a new system outright.
/// Where to place the legend for the network chart widget.
pub(crate) legend_position: Option<String>,
/// Displays the network widget using bytes. Defaults to bits.
pub(crate) use_bytes: Option<bool>,
/// Displays the network widget with a log scale. Defaults to a non-log scale.
pub(crate) use_log: Option<bool>,
/// Displays the network widget with a binary prefix (e.g. kibibits) rather than a decimal
/// prefix (e.g. kilobits). Defaults to decimal prefixes.
pub(crate) use_binary_prefix: Option<bool>,
}
+16
View File
@@ -210,3 +210,19 @@ fn test_temp_disk_sort_columns() {
fn test_proc_default_sort() {
run_and_kill(&["-C", "./tests/valid_configs/proc_default_sort.toml"]);
}
#[test]
fn test_newer_mem_network() {
run_and_kill(&["-C", "./tests/valid_configs/newer_mem_network.toml"]);
}
/// This uses deprecated network and memory settings - once they are removed, this test file should be moved to invalid configs.
#[test]
fn test_deprecated_mem_network() {
run_and_kill(&["-C", "./tests/valid_configs/deprecated_mem_network.toml"]);
}
#[test]
fn test_network_alias() {
run_and_kill(&["-C", "./tests/valid_configs/network_alias.toml"]);
}
@@ -0,0 +1,9 @@
# This uses deprecated network and memory settings - once they are removed, this test file should be moved to invalid configs.
[flags]
network_use_bytes = true
network_use_log = true
network_use_binary_prefix = true
network_legend = "left"
memory_legend = "left"
+2 -2
View File
@@ -21,8 +21,8 @@ regex = false
case_sensitive = false
whole_word = false
[network]
[network.interface_filter]
[network_graph]
[network_graph.interface_filter]
is_list_ignored = true
list = ["virbr0.*"]
regex = true
+14
View File
@@ -0,0 +1,14 @@
# We allow [network] as an alias since that's what it used to be called.
[network]
use_log = false
use_bytes = false
legend_position = "right"
use_binary_prefix = false
[network.interface_filter]
is_list_ignored = true
list = ["virbr0.*"]
regex = true
case_sensitive = false
whole_word = false
@@ -0,0 +1,10 @@
# This uses the newer memory/network config location.
[network_graph]
use_log = true
use_bytes = true
use_binary_prefix = true
legend_position = "left"
[memory_graph]
legend_position = "left"