other: mention memory/network alias in deprecation warnings (#2102)

This commit is contained in:
Clement Tsang
2026-06-22 02:25:54 -04:00
committed by GitHub
parent 9332d46b40
commit b3694fc3f4
5 changed files with 74 additions and 23 deletions
+3 -2
View File
@@ -20,11 +20,12 @@ That said, these are more guidelines rather than hard rules, though the project
--- ---
## 0.14.1 - 2026-06-21 ## 0.14.1 - 2026-06-22
### Bug Fixes ### Other
- [#2096](https://github.com/ClementTsang/bottom/pull/2096): Fix documentation suggestions around `memory_graph`. - [#2096](https://github.com/ClementTsang/bottom/pull/2096): Fix documentation suggestions around `memory_graph`.
- [#2102](https://github.com/ClementTsang/bottom/pull/2102): Mention memory/network alias in deprecation warnings.
## 0.14.0 - 2026-06-20 ## 0.14.0 - 2026-06-20
@@ -50,8 +50,8 @@ each time:
| `retention` | String (human readable time, such as "10m", "1h", etc.) | How much data is stored at once in terms of time. | | `retention` | String (human readable time, such as "10m", "1h", etc.) | How much data is stored at once in terms of time. |
| `unnormalized_cpu` | Boolean | Deprecated - use `processes.unnormalized_cpu`. Show process CPU% without normalizing over the number of cores. | | `unnormalized_cpu` | Boolean | Deprecated - use `processes.unnormalized_cpu`. Show process CPU% without normalizing over the number of cores. |
| `expanded` | Boolean | Expand the default widget upon starting the app. | | `expanded` | Boolean | Expand the default widget upon starting the app. |
| `memory_legend` | String (one of ["none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right"]) | Deprecated - use `memory_graph.legend_position`. Where to place the legend for the memory widget. | | `memory_legend` | String (one of ["none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right"]) | Deprecated - use `memory_graph.legend_position` or `memory.legend_position`; where to place the legend for the memory widget. |
| `network_legend` | String (one of ["none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right"]) | Deprecated - use `network_graph.legend_position`. Where to place the legend for the network widget. | | `network_legend` | String (one of ["none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right"]) | Deprecated - use `network_graph.legend_position` or `network.legend_position`; where to place the legend for the network widget. |
| `average_cpu_row` | Boolean | Deprecated - use `cpu.basic_average_cpu_row`. Moves the average CPU usage entry to its own row when using basic mode. | | `average_cpu_row` | Boolean | Deprecated - use `cpu.basic_average_cpu_row`. Moves the average CPU usage entry to its own row when using basic mode. |
| `tree_collapse` | Boolean | Deprecated - use `processes.tree_collapse`. Collapse process tree by default. | | `tree_collapse` | Boolean | Deprecated - use `processes.tree_collapse`. Collapse process tree by default. |
| `autohide_time` | Boolean | Temporarily shows the time scale in graphs. | | `autohide_time` | Boolean | Temporarily shows the time scale in graphs. |
+2 -2
View File
@@ -147,11 +147,11 @@
# How much data is stored at once in terms of time. # How much data is stored at once in terms of time.
#retention = "10m" #retention = "10m"
# Deprecated - use memory_graph.legend_position. # Deprecated - use memory_graph.legend_position or memory.legend_position.
# Where to place the legend for the memory widget. One of "none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right". # Where to place the legend for the memory widget. One of "none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right".
#memory_legend = "top-right" #memory_legend = "top-right"
# Deprecated - use network_graph.legend_position. # Deprecated - use network_graph.legend_position or network.legend_position.
# Where to place the legend for the network widget. One of "none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right". # 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" #network_legend = "top-right"
+2 -2
View File
@@ -396,11 +396,11 @@ pub(crate) const CONFIG_TEXT: &str = r#"# This is a default config file for bott
# How much data is stored at once in terms of time. # How much data is stored at once in terms of time.
#retention = "10m" #retention = "10m"
# Deprecated - use memory_graph.legend_position. # Deprecated - use memory_graph.legend_position or memory.legend_position.
# Where to place the legend for the memory widget. One of "none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right". # Where to place the legend for the memory widget. One of "none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right".
#memory_legend = "top-right" #memory_legend = "top-right"
# Deprecated - use network_graph.legend_position. # Deprecated - use network_graph.legend_position or network.legend_position.
# Where to place the legend for the network widget. One of "none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right". # 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" #network_legend = "top-right"
+65 -15
View File
@@ -95,6 +95,26 @@ macro_rules! enabled_option_with_deprecated {
false false
} }
}; };
($arg:expr, $config:expr, $section:ident . $field:ident, $flags:ident . $deprecated_flag:ident, $alias:literal $(,)?) => {
if $arg {
true
} else if let Some(section) = &$config.$section {
section.$field.unwrap_or(false)
} else if let Some(flags) = &$config.flags {
flags
.$deprecated_flag
.inspect(|_| {
deprecated_warning_with_alias(
stringify!($deprecated_flag),
stringify!($section.$field),
$alias,
)
})
.unwrap_or(false)
} else {
false
}
};
} }
/// Get the value of a field for a specific section in the config file if set. If not set, the default is used. /// Get the value of a field for a specific section in the config file if set. If not set, the default is used.
@@ -283,6 +303,7 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
config, config,
memory_graph.free_arc, memory_graph.free_arc,
flags.free_arc, flags.free_arc,
"memory.free_arc",
); );
// For processes // For processes
@@ -381,6 +402,7 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
config, config,
network_graph.use_binary_prefix, network_graph.use_binary_prefix,
flags.network_use_binary_prefix, flags.network_use_binary_prefix,
"network.use_binary_prefix",
); );
let network_show_packets = let network_show_packets =
is_flag_enabled_in!(show_packets, args.network, config.network_graph); is_flag_enabled_in!(show_packets, args.network, config.network_graph);
@@ -418,6 +440,9 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
.and_then(|cfg| cfg.include_unmounted) .and_then(|cfg| cfg.include_unmounted)
.unwrap_or(false); .unwrap_or(false);
let enable_cache_memory = get_enable_cache_memory(args, config);
let enable_gpu = get_enable_gpu(args, config);
// TODO: Can probably just reuse the options struct. // TODO: Can probably just reuse the options struct.
let app_config_fields = AppConfigFields { let app_config_fields = AppConfigFields {
update_rate: get_update_rate(args, config)?, update_rate: get_update_rate(args, config)?,
@@ -454,9 +479,9 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
table_gap: config_or_default!(config, flags.table_gap), table_gap: config_or_default!(config, flags.table_gap),
disable_click: is_flag_enabled!(disable_click, args.general, config), disable_click: is_flag_enabled!(disable_click, args.general, config),
disable_keys: is_flag_enabled!(disable_keys, args.general, config), disable_keys: is_flag_enabled!(disable_keys, args.general, config),
enable_gpu: get_enable_gpu(args, config), enable_gpu,
short_gpu_names: get_short_gpu_names(args, config), short_gpu_names: get_short_gpu_names(args, config),
enable_cache_memory: get_enable_cache_memory(args, config), enable_cache_memory,
show_table_scroll_position: is_flag_enabled!( show_table_scroll_position: is_flag_enabled!(
show_table_scroll_position, show_table_scroll_position,
args.general, args.general,
@@ -710,8 +735,8 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
let used_widgets = UsedWidgets { let used_widgets = UsedWidgets {
use_cpu: used_widget_set.contains(&Cpu) || used_widget_set.contains(&BasicCpu), use_cpu: used_widget_set.contains(&Cpu) || used_widget_set.contains(&BasicCpu),
use_mem, use_mem,
use_cache: use_mem && get_enable_cache_memory(args, config), use_cache: use_mem && enable_cache_memory,
use_gpu: get_enable_gpu(args, config), use_gpu: enable_gpu,
use_net: used_widget_set.contains(&Net) || used_widget_set.contains(&BasicNet), use_net: used_widget_set.contains(&Net) || used_widget_set.contains(&BasicNet),
use_proc: used_widget_set.contains(&Proc), use_proc: used_widget_set.contains(&Proc),
use_disk: used_widget_set.contains(&Disk), use_disk: used_widget_set.contains(&Disk),
@@ -953,6 +978,14 @@ fn deprecated_warning(deprecated_field: &str, new_field: &str) {
); );
} }
/// Mark a config option field as deprecated, and what to use instead with an alias.
#[inline]
fn deprecated_warning_with_alias(deprecated_field: &str, new_field: &str, alias: &str) {
eprintln!(
"Warning: The config option '{deprecated_field}' is deprecated and will eventually be removed. Please use '{new_field}' or '{alias}' instead.",
);
}
/// How quickly we update data. /// How quickly we update data.
#[inline] #[inline]
fn get_update_rate(args: &BottomArgs, config: &Config) -> OptionResult<u64> { fn get_update_rate(args: &BottomArgs, config: &Config) -> OptionResult<u64> {
@@ -1166,6 +1199,7 @@ fn get_enable_cache_memory(args: &BottomArgs, config: &Config) -> bool {
config, config,
memory_graph.cache_memory, memory_graph.cache_memory,
flags.enable_cache_memory, flags.enable_cache_memory,
"memory.cache_memory",
) )
} }
@@ -1220,7 +1254,11 @@ fn get_network_unit_type(args: &BottomArgs, config: &Config) -> DataUnit {
} else if let Some(flags) = &config.flags } else if let Some(flags) = &config.flags
&& let Some(network_use_bytes) = flags.network_use_bytes && let Some(network_use_bytes) = flags.network_use_bytes
{ {
deprecated_warning("network_use_bytes", "network_graph.use_bytes"); deprecated_warning_with_alias(
"network_use_bytes",
"network_graph.use_bytes",
"network.use_bytes",
);
if network_use_bytes { if network_use_bytes {
return DataUnit::Byte; return DataUnit::Byte;
@@ -1240,7 +1278,11 @@ fn get_network_scale_type(args: &BottomArgs, config: &Config) -> AxisScaling {
} else if let Some(flags) = &config.flags } else if let Some(flags) = &config.flags
&& let Some(network_use_log) = flags.network_use_log && let Some(network_use_log) = flags.network_use_log
{ {
deprecated_warning("network_use_log", "network_graph.use_log"); deprecated_warning_with_alias(
"network_use_log",
"network_graph.use_log",
"network.use_log",
);
if network_use_log { if network_use_log {
return AxisScaling::Log; return AxisScaling::Log;
@@ -1269,7 +1311,7 @@ fn get_retention(args: &BottomArgs, config: &Config) -> OptionResult<u64> {
#[inline] #[inline]
fn parse_legend_position( fn parse_legend_position(
arg: Option<&String>, cfg: Option<&String>, deprecated_cfg: Option<(&String, &'static str)>, arg: Option<&String>, cfg: Option<&String>, deprecated_cfg: Option<(&String, &'static str)>,
setting: &'static str, setting: &'static str, alias: Option<&'static str>,
) -> OptionResult<Option<LegendPosition>> { ) -> OptionResult<Option<LegendPosition>> {
#[inline] #[inline]
fn parse_position_or_err<F: FnOnce(&'static str) -> OptionError>( fn parse_position_or_err<F: FnOnce(&'static str) -> OptionError>(
@@ -1287,7 +1329,11 @@ fn parse_legend_position(
parse_position_or_err(s, setting, OptionError::invalid_config_value) parse_position_or_err(s, setting, OptionError::invalid_config_value)
} else if let Some((s, name)) = deprecated_cfg { } else if let Some((s, name)) = deprecated_cfg {
// Remove the deprecated args/code paths and copy back to the function above later. // Remove the deprecated args/code paths and copy back to the function above later.
deprecated_warning(name, setting); if let Some(alias) = alias {
deprecated_warning_with_alias(name, setting, alias);
} else {
deprecated_warning(name, setting);
}
parse_position_or_err(s, setting, OptionError::invalid_config_value) parse_position_or_err(s, setting, OptionError::invalid_config_value)
} else { } else {
Ok(Some(LegendPosition::default())) Ok(Some(LegendPosition::default()))
@@ -1309,6 +1355,7 @@ fn get_network_legend_position(
.and_then(|flags| flags.network_legend.as_ref()) .and_then(|flags| flags.network_legend.as_ref())
.map(|s| (s, "network_legend")), .map(|s| (s, "network_legend")),
"network_graph.legend_position", "network_graph.legend_position",
Some("network.legend_position"),
) )
} }
@@ -1327,6 +1374,7 @@ fn get_memory_legend_position(
.and_then(|flags| flags.memory_legend.as_ref()) .and_then(|flags| flags.memory_legend.as_ref())
.map(|s| (s, "memory_legend")), .map(|s| (s, "memory_legend")),
"memory_graph.legend_position", "memory_graph.legend_position",
Some("memory.legend_position"),
) )
} }
@@ -1339,6 +1387,7 @@ fn get_temperature_legend_position(config: &Config) -> OptionResult<Option<Legen
.and_then(|settings| settings.legend_position.as_ref()), .and_then(|settings| settings.legend_position.as_ref()),
None, None,
"legend_position", "legend_position",
None,
) )
} }
@@ -1351,6 +1400,7 @@ fn get_disk_io_legend_position(config: &Config) -> OptionResult<Option<LegendPos
.and_then(|settings| settings.legend_position.as_ref()), .and_then(|settings| settings.legend_position.as_ref()),
None, None,
"disk_io_graph.legend_position", "disk_io_graph.legend_position",
None,
) )
} }
@@ -1394,7 +1444,7 @@ mod test {
// No arg, no config. // No arg, no config.
assert_eq!( assert_eq!(
parse_legend_position(None, None, None, setting), parse_legend_position(None, None, None, setting, None),
Ok(Some(LegendPosition::default())) Ok(Some(LegendPosition::default()))
); );
@@ -1402,40 +1452,40 @@ mod test {
let arg = " ToP-lEfT ".to_string(); let arg = " ToP-lEfT ".to_string();
let cfg = "bottom-right".to_string(); let cfg = "bottom-right".to_string();
assert_eq!( assert_eq!(
parse_legend_position(Some(&arg), Some(&cfg), None, setting), parse_legend_position(Some(&arg), Some(&cfg), None, setting, None),
Ok(Some(LegendPosition::TopLeft)) Ok(Some(LegendPosition::TopLeft))
); );
// "none" disables the legend, from either source. // "none" disables the legend, from either source.
let none_arg = "None".to_string(); let none_arg = "None".to_string();
assert_eq!( assert_eq!(
parse_legend_position(Some(&none_arg), None, None, setting), parse_legend_position(Some(&none_arg), None, None, setting, None),
Ok(None) Ok(None)
); );
let none_cfg = "none".to_string(); let none_cfg = "none".to_string();
assert_eq!( assert_eq!(
parse_legend_position(None, Some(&none_cfg), None, setting), parse_legend_position(None, Some(&none_cfg), None, setting, None),
Ok(None) Ok(None)
); );
// Config value is used when no arg is provided. // Config value is used when no arg is provided.
let cfg_only = "left".to_string(); let cfg_only = "left".to_string();
assert_eq!( assert_eq!(
parse_legend_position(None, Some(&cfg_only), None, setting), parse_legend_position(None, Some(&cfg_only), None, setting, None),
Ok(Some(LegendPosition::Left)) Ok(Some(LegendPosition::Left))
); );
// Invalid arg value. // Invalid arg value.
let bad_arg = "bad".to_string(); let bad_arg = "bad".to_string();
assert_eq!( assert_eq!(
parse_legend_position(Some(&bad_arg), None, None, setting), parse_legend_position(Some(&bad_arg), None, None, setting, None),
Err(OptionError::invalid_arg_value(setting)) Err(OptionError::invalid_arg_value(setting))
); );
// Invalid config value. // Invalid config value.
let bad_cfg = "bad".to_string(); let bad_cfg = "bad".to_string();
assert_eq!( assert_eq!(
parse_legend_position(None, Some(&bad_cfg), None, setting), parse_legend_position(None, Some(&bad_cfg), None, setting, None),
Err(OptionError::invalid_config_value(setting)) Err(OptionError::invalid_config_value(setting))
); );
} }