From 30b676d9db0bfdd7c2dcbe6b7b412175bad8d0d3 Mon Sep 17 00:00:00 2001 From: ClementTsang <34804052+ClementTsang@users.noreply.github.com> Date: Wed, 10 Jan 2024 23:09:59 -0500 Subject: [PATCH] Revert "Try macros" This reverts commit 93c7306f8ae8b906e0a66d1a4d758aad51efe3eb. --- src/bin/main.rs | 2 +- src/options/args.rs | 219 +++++++++++++++++++++++++++----------------- 2 files changed, 135 insertions(+), 86 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 64d2a526..0ee3289f 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -37,7 +37,7 @@ use tui::{backend::CrosstermBackend, Terminal}; fn main() -> Result<()> { // let _profiler = dhat::Profiler::new_heap(); - let matches = args::build_app().get_matches(); + let matches = args::get_matches(); #[cfg(feature = "logging")] { diff --git a/src/options/args.rs b/src/options/args.rs index 8f0c1fc7..b6b3c17a 100644 --- a/src/options/args.rs +++ b/src/options/args.rs @@ -78,6 +78,10 @@ Supported widget names: } }; +pub fn get_matches() -> ArgMatches { + build_app().get_matches() +} + /// Returns an [`Ordering`] for two [`Arg`] values. /// /// Note this assumes that they both have a _long_ name, and will @@ -114,25 +118,10 @@ trait CommandBuilder { fn add_args(self) -> Self; } -macro_rules! load_args { - ( $cmd:expr, $heading:expr, $arg:expr $(,)?) => { - $cmd.arg($arg.help_heading($heading)) - }; - ( $cmd:expr, $heading:expr, $( $arg:expr ),+ $(,)? ) => { - { - let mut args = [ - $( - $arg.help_heading($heading), - )* - ]; - args.sort_unstable_by(sort_args); - $cmd.args(args) - } - }; -} - impl CommandBuilder for Command { fn general_args(self) -> Command { + const HEADING: &str = "General Options"; + let autohide_time = Arg::new("autohide_time") .long("autohide_time") .action(ArgAction::SetTrue) @@ -141,7 +130,8 @@ impl CommandBuilder for Command { "Automatically hides the time scale in graphs after being shown for \ a brief moment when zoomed in/out. If time is disabled via --hide_time \ then this will have no effect.", - ); + ) + .help_heading(HEADING); let basic = Arg::new("basic") .short('b') @@ -150,39 +140,45 @@ impl CommandBuilder for Command { .help("Hides graphs and uses a more basic look.") .long_help( "Hides graphs and uses a more basic look. Design is largely inspired by htop's.", - ); + ) + .help_heading(HEADING); let disable_click = Arg::new("disable_click") .long("disable_click") .action(ArgAction::SetTrue) .help("Disables mouse clicks.") - .long_help("Disables mouse clicks from interacting with the program."); + .long_help("Disables mouse clicks from interacting with the program.") + .help_heading(HEADING); let dot_marker = Arg::new("dot_marker") .short('m') .long("dot_marker") .action(ArgAction::SetTrue) .help("Uses a dot marker for graphs.") - .long_help("Uses a dot marker for graphs as opposed to the default braille marker."); + .long_help("Uses a dot marker for graphs as opposed to the default braille marker.") + .help_heading(HEADING); let hide_table_gap = Arg::new("hide_table_gap") .long("hide_table_gap") .action(ArgAction::SetTrue) .help("Hides spacing between table headers and entries.") - .long_help("Hides the spacing between table headers and entries."); + .long_help("Hides the spacing between table headers and entries.") + .help_heading(HEADING); let hide_time = Arg::new("hide_time") .long("hide_time") .action(ArgAction::SetTrue) .help("Hides the time scale.") - .long_help("Completely hides the time scale from being shown."); + .long_help("Completely hides the time scale from being shown.") + .help_heading(HEADING); let left_legend = Arg::new("left_legend") .short('l') .long("left_legend") .action(ArgAction::SetTrue) .help("Puts the CPU chart legend to the left side.") - .long_help("Puts the CPU chart legend to the left side rather than the right side."); + .long_help("Puts the CPU chart legend to the left side rather than the right side.") + .help_heading(HEADING); let show_table_scroll_position = Arg::new("show_table_scroll_position") .long("show_table_scroll_position") @@ -190,7 +186,8 @@ impl CommandBuilder for Command { .help("Shows the scroll position tracker in table widgets.") .long_help( "Shows the list scroll position tracker in the widget title for table widgets.", - ); + ) + .help_heading(HEADING); let config_location = Arg::new("config_location") .short('C') @@ -202,7 +199,8 @@ impl CommandBuilder for Command { "Sets the location of the config file. Expects a config file in the TOML format. \ If it doesn't exist, one is created.", ) - .value_hint(ValueHint::AnyPath); + .value_hint(ValueHint::AnyPath) + .help_heading(HEADING); let default_time_value = Arg::new("default_time_value") .short('t') @@ -212,7 +210,8 @@ impl CommandBuilder for Command { .help("Default time value for graphs.") .long_help( "Default time value for graphs. Takes a number in milliseconds or a human duration (e.g. 60s). The minimum time is 30s, and the default is 60s.", - ); + ) + .help_heading(HEADING); // TODO: Charts are broken in the manpage let default_widget_count = Arg::new("default_widget_count") @@ -239,21 +238,24 @@ And we set our default widget type to 'CPU'. If we set the default widget. If we set '--default_widget_count 3', it would use CPU (3) as the default instead. ", - ); + ) + .help_heading(HEADING); let default_widget_type = Arg::new("default_widget_type") .long("default_widget_type") .action(ArgAction::Set) .value_name("WIDGET TYPE") .help("Sets the default widget type, use --help for info.") - .long_help(DEFAULT_WIDGET_TYPE_STR); + .long_help(DEFAULT_WIDGET_TYPE_STR) + .help_heading(HEADING); let expanded_on_startup = Arg::new("expanded_on_startup") .short('e') .long("expanded") .action(ArgAction::SetTrue) .help("Expand the default widget upon starting the app.") - .long_help("Expand the default widget upon starting the app. Same as pressing \"e\" inside the app. Use with \"default_widget_type\" and \"default_widget_count\" to select desired expanded widget. This flag has no effect in basic mode (--basic)."); + .long_help("Expand the default widget upon starting the app. Same as pressing \"e\" inside the app. Use with \"default_widget_type\" and \"default_widget_count\" to select desired expanded widget. This flag has no effect in basic mode (--basic)") + .help_heading(HEADING); let rate = Arg::new("rate") .short('r') @@ -261,7 +263,8 @@ use CPU (3) as the default instead. .action(ArgAction::Set) .value_name("TIME") .help("Sets the data refresh rate.") - .long_help("Sets the data refresh rate. Takes a number in milliseconds or a human duration (e.g. 5s). The minimum is 250ms, and defaults to 1000ms. Smaller values may take more computer resources."); + .long_help("Sets the data refresh rate. Takes a number in milliseconds or a human duration (e.g. 5s). The minimum is 250ms, and defaults to 1000ms. Smaller values may take more computer resources.") + .help_heading(HEADING); let time_delta = Arg::new("time_delta") .short('d') @@ -269,18 +272,18 @@ use CPU (3) as the default instead. .action(ArgAction::Set) .value_name("TIME") .help("The amount of time changed upon zooming.") - .long_help("The amount of time changed when zooming in/out. Takes a number in milliseconds or a human duration (e.g. 30s). The minimum is 1s, and defaults to 15s."); + .long_help("The amount of time changed when zooming in/out. Takes a number in milliseconds or a human duration (e.g. 30s). The minimum is 1s, and defaults to 15s.") + .help_heading(HEADING); let retention = Arg::new("retention") .long("retention") .action(ArgAction::Set) .value_name("TIME") .help("The timespan of data stored.") - .long_help("How much data is stored at once in terms of time. Takes a number in milliseconds or a human duration (e.g. 20m), with a minimum of 1 minute. Note higher values will take up more memory. Defaults to 10 minutes."); + .long_help("How much data is stored at once in terms of time. Takes a number in milliseconds or a human duration (e.g. 20m), with a minimum of 1 minute. Note higher values will take up more memory. Defaults to 10 minutes.") + .help_heading(HEADING); - load_args!( - self, - "General Options", + let mut args = [ autohide_time, basic, disable_click, @@ -297,10 +300,15 @@ use CPU (3) as the default instead. rate, time_delta, retention, - ) + ]; + args.sort_unstable_by(sort_args); + + self.args(args) } fn style_args(self) -> Command { + const HEADING: &str = "Style Options"; + // TODO: File an issue with manpage, it cannot render charts correctly. let color = Arg::new("color") .long("color") @@ -334,30 +342,36 @@ Use a pre-defined color scheme. Currently supported values are: +------------------------------------------------------------+ Defaults to \"default\". ", - ); + ) + .help_heading(HEADING); - load_args!(self, "Style Options", color) + self.arg(color) } fn temperature_args(self) -> Command { + const HEADING: &str = "Temperature Options"; + let celsius = Arg::new("celsius") .short('c') .long("celsius") .action(ArgAction::SetTrue) .help("Use Celsius as the temperature unit.") - .long_help("Use Celsius as the temperature unit. This is the default option."); + .long_help("Use Celsius as the temperature unit. This is the default option.") + .help_heading(HEADING); let fahrenheit = Arg::new("fahrenheit") .short('f') .long("fahrenheit") .action(ArgAction::SetTrue) - .help("Use Fahrenheit as the temperature unit."); + .help("Use Fahrenheit as the temperature unit.") + .help_heading(HEADING); let kelvin = Arg::new("kelvin") .short('k') .long("kelvin") .action(ArgAction::SetTrue) - .help("Use Kelvin as the temperature unit."); + .help("Use Kelvin as the temperature unit.") + .help_heading(HEADING); let temperature_group = ArgGroup::new("TEMPERATURE_TYPE").args([ celsius.get_id(), @@ -365,24 +379,29 @@ Defaults to \"default\". kelvin.get_id(), ]); - load_args!(self, "Temperature Options", celsius, fahrenheit, kelvin) - .group(temperature_group) + let args = [celsius, fahrenheit, kelvin]; + + self.args(args).group(temperature_group) } fn process_args(self) -> Command { + const HEADING: &str = "Process Options"; + let case_sensitive = Arg::new("case_sensitive") .short('S') .long("case_sensitive") .action(ArgAction::SetTrue) .help("Enables case sensitivity by default.") - .long_help("When searching for a process, enables case sensitivity by default."); + .long_help("When searching for a process, enables case sensitivity by default.") + .help_heading(HEADING); let current_usage = Arg::new("current_usage") .short('u') .long("current_usage") .action(ArgAction::SetTrue) .help("Sets process CPU% to be based on current CPU%.") - .long_help("Sets process CPU% usage to be based on the current system CPU% usage rather than total CPU usage."); + .long_help("Sets process CPU% usage to be based on the current system CPU% usage rather than total CPU usage.") + .help_heading(HEADING); let unnormalized_cpu = Arg::new("unnormalized_cpu") .short('n') @@ -391,33 +410,38 @@ Defaults to \"default\". .help("Show process CPU% usage without normalizing over the number of cores.") .long_help( "Shows all process CPU% usage without averaging over the number of CPU cores in the system.", - ); + ) + .help_heading(HEADING); let group_processes = Arg::new("group_processes") .short('g') .long("group_processes") .action(ArgAction::SetTrue) .help("Groups processes with the same name by default.") - .long_help("Groups processes with the same name by default."); + .long_help("Groups processes with the same name by default.") + .help_heading(HEADING); let process_command = Arg::new("process_command") .long("process_command") .action(ArgAction::SetTrue) .help("Show processes as their commands by default.") - .long_help("Show processes as their commands by default in the process widget."); + .long_help("Show processes as their commands by default in the process widget.") + .help_heading(HEADING); let regex = Arg::new("regex") .short('R') .long("regex") .action(ArgAction::SetTrue) .help("Enables regex by default.") - .long_help("When searching for a process, enables regex by default."); + .long_help("When searching for a process, enables regex by default.") + .help_heading(HEADING); let disable_advanced_kill = Arg::new("disable_advanced_kill") .long("disable_advanced_kill") .action(ArgAction::SetTrue) .help("Hides advanced process killing.") - .long_help("Hides advanced options to stop a process on Unix-like systems. The only option shown is 15 (TERM)."); + .long_help("Hides advanced options to stop a process on Unix-like systems. The only option shown is 15 (TERM).") + .help_heading(HEADING); let whole_word = Arg::new("whole_word") .short('W') @@ -426,18 +450,18 @@ Defaults to \"default\". .help("Enables whole-word matching by default.") .long_help( "When searching for a process, return results that match the entire query by default.", - ); + ) + .help_heading(HEADING); let tree = Arg::new("tree") .short('T') .long("tree") .action(ArgAction::SetTrue) .help("Defaults the process widget be in tree mode.") - .long_help("Defaults to showing the process widget in tree mode."); + .long_help("Defaults to showing the process widget in tree mode.") + .help_heading(HEADING); - load_args!( - self, - "Style Options", + let mut args = [ case_sensitive, current_usage, unnormalized_cpu, @@ -447,45 +471,60 @@ Defaults to \"default\". whole_word, disable_advanced_kill, tree, - ) + ]; + args.sort_unstable_by(sort_args); + + self.args(args) } fn cpu_args(self) -> Command { + const HEADING: &str = "CPU Options"; + let hide_avg_cpu = Arg::new("hide_avg_cpu") .short('a') .long("hide_avg_cpu") .action(ArgAction::SetTrue) .help("Hides the average CPU usage.") - .long_help("Hides the average CPU usage from being shown."); + .long_help("Hides the average CPU usage from being shown.") + .help_heading(HEADING); // let default_avg_cpu = Arg::new(""); - load_args!(self, "CPU Options", hide_avg_cpu) + let mut args = [hide_avg_cpu]; + args.sort_unstable_by(sort_args); + + self.args(args) } fn mem_args(self) -> Command { + const HEADING: &str = "Memory Options"; + let mem_as_value = Arg::new("mem_as_value") .long("mem_as_value") .action(ArgAction::SetTrue) .help("Defaults to showing process memory usage by value.") - .long_help("Defaults to showing process memory usage by value. Otherwise, it defaults to showing it by percentage."); + .long_help("Defaults to showing process memory usage by value. Otherwise, it defaults to showing it by percentage.") + .help_heading(HEADING); #[cfg(not(target_os = "windows"))] { let enable_cache_memory = Arg::new("enable_cache_memory") .long("enable_cache_memory") .action(ArgAction::SetTrue) - .help("Enable collecting and displaying cache and buffer memory."); + .help("Enable collecting and displaying cache and buffer memory.") + .help_heading(HEADING); - load_args!(self, "Memory Options", mem_as_value, enable_cache_memory) + self.args([mem_as_value, enable_cache_memory]) } #[cfg(target_os = "windows")] { - load_args!(self, "Memory Options", mem_as_value) + self.arg(mem_as_value) } } fn network_args(self) -> Command { + const HEADING: &str = "Network Options"; + let use_old_network_legend = Arg::new("use_old_network_legend") .long("use_old_network_legend") .action(ArgAction::SetTrue) @@ -493,21 +532,22 @@ Defaults to \"default\". .long_help( "DEPRECATED - uses an older (pre-0.4), separate network widget legend. This display is not \ tested anymore and could be broken.", - ); + ) + .help_heading(HEADING); let network_use_bytes = Arg::new("network_use_bytes") .long("network_use_bytes") .action(ArgAction::SetTrue) .help("Displays the network widget using bytes.") - .long_help("Displays the network widget using bytes. Defaults to bits."); + .long_help("Displays the network widget using bytes. Defaults to bits.") + .help_heading(HEADING); let network_use_log = Arg::new("network_use_log") .long("network_use_log") .action(ArgAction::SetTrue) .help("Displays the network widget with a log scale.") - .long_help( - "Displays the network widget with a log scale. Defaults to a non-log scale.", - ); + .long_help("Displays the network widget with a log scale. Defaults to a non-log scale.") + .help_heading(HEADING); let network_use_binary_prefix = Arg::new("network_use_binary_prefix") .long("network_use_binary_prefix") @@ -515,30 +555,34 @@ Defaults to \"default\". .help("Displays the network widget with binary prefixes.") .long_help( "Displays the network widget with binary prefixes (i.e. kibibits, mebibits) rather than a decimal prefix (i.e. kilobits, megabits). Defaults to decimal prefixes.", - ); + ) + .help_heading(HEADING); - load_args!( - self, - "Network Options", + let mut args = [ use_old_network_legend, network_use_bytes, network_use_log, network_use_binary_prefix, - ) + ]; + + args.sort_unstable_by(sort_args); + + self.args(args) } fn battery_args(self) -> Command { #[cfg(feature = "battery")] { let battery = Arg::new("battery") - .long("battery") - .action(ArgAction::SetTrue) - .help("Shows the battery widget.") - .long_help( - "Shows the battery widget in default or basic mode. No effect on custom layouts.", - ); + .long("battery") + .action(ArgAction::SetTrue) + .help("Shows the battery widget.") + .long_help( + "Shows the battery widget in default or basic mode. No effect on custom layouts.", + ) + .help_heading("Battery Options"); - load_args!(self, "Battery Options", battery) + self.arg(battery) } #[cfg(not(feature = "battery"))] { @@ -552,9 +596,10 @@ Defaults to \"default\". let enable_gpu = Arg::new("enable_gpu") .long("enable_gpu") .action(ArgAction::SetTrue) - .help("Enable collecting and displaying GPU usage."); + .help("Enable collecting and displaying GPU usage.") + .help_heading("GPU Options"); - load_args!(self, "GPU Options", enable_gpu) + self.arg(enable_gpu) } #[cfg(not(feature = "gpu"))] { @@ -563,19 +608,23 @@ Defaults to \"default\". } fn other(self) -> Command { + const HEADING: &str = "Other Options"; + let help = Arg::new("help") .short('h') .long("help") .action(ArgAction::Help) - .help("Prints help (see more with '--help')."); + .help("Prints help (see more with '--help').") + .help_heading(HEADING); let version = Arg::new("version") .short('V') .long("version") .action(ArgAction::Version) - .help("Prints version information."); + .help("Prints version information.") + .help_heading(HEADING); - load_args!(self, "Other Options", help, version) + self.args([help, version]) } fn add_args(self) -> Self {