From 8f70c6df34861a179bbb93af43f89cb264b5b576 Mon Sep 17 00:00:00 2001 From: Lennard Kittner Date: Sun, 3 May 2026 17:58:57 +0200 Subject: [PATCH] Add verbose flag and improve argument handling in CLI --- README.md | 4 ++ src/bin/hyper_headset_cli.rs | 86 +++++++++++++++++++++++++++++------- src/lib.rs | 8 ++++ src/main.rs | 25 ++++++++++- 4 files changed, 105 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 05c5dd6..749605e 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,8 @@ Options: Mute or unmute playback. [possible values: true, false] --activate_noise_gate Activates noise gate. [possible values: true, false] + -v, --verbose + Use verbose output -h, --help Print help -V, --version @@ -166,6 +168,8 @@ Options: Set the refresh interval (in seconds) [default: 3] --press_mute_key The app will simulate pressing the microphone mute key whoever the headsets is muted or unmuted. [default: true] [possible values: true, false] + -v, --verbose + Use verbose output -h, --help Print help -V, --version diff --git a/src/bin/hyper_headset_cli.rs b/src/bin/hyper_headset_cli.rs index eefa3e9..02012c1 100644 --- a/src/bin/hyper_headset_cli.rs +++ b/src/bin/hyper_headset_cli.rs @@ -1,11 +1,51 @@ use std::time::Duration; -use clap::{Arg, Command}; -use hyper_headset::devices::{connect_compatible_device, DeviceEvent}; +use clap::{Arg, ArgAction, Command}; +use hyper_headset::{ + devices::{connect_compatible_device, Device, DeviceError, DeviceEvent}, + VERBOSE, +}; const SHOW_ALL_OPTIONS: bool = false; +/// helper function to enable help messages +fn device_supports(device: &Result, DeviceError>, f: F) -> bool +where + F: FnOnce(&Box) -> bool, +{ + device.as_ref().map(f).unwrap_or(false) +} + fn main() { + let pre = Command::new(env!("CARGO_PKG_NAME")) + .version(env!("CARGO_PKG_VERSION")) + .disable_version_flag(true) // we have to implement version manually + .disable_help_flag(true) + .arg( + Arg::new("verbose") + .long("verbose") + .short('v') + .action(ArgAction::SetTrue) + .required(false) + .help("Use verbose output "), + ) + .arg( + Arg::new("version") + .long("version") + .short('V') + .action(ArgAction::SetTrue), + ) + .allow_external_subcommands(true) + .try_get_matches(); + + if let Ok(pre) = pre { + VERBOSE.set(pre.get_flag("verbose")).unwrap(); + if pre.get_flag("version") { + println!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); + return; + } + } + #[cfg(target_os = "linux")] { use hyper_headset::act_as_askpass_handler; @@ -22,16 +62,12 @@ fn main() { } prompt_user_for_udev_rule(); } - let mut device = match connect_compatible_device() { - Ok(device) => device, - Err(error) => { - eprintln!("{error}"); - std::process::exit(1); - } - }; + + let device = connect_compatible_device(); let matches = Command::new(env!("CARGO_PKG_NAME")) .version(env!("CARGO_PKG_VERSION")) + .disable_version_flag(false) .author(env!("CARGO_PKG_AUTHORS")) .about("A CLI application for monitoring and managing HyperX headsets.") .after_help("Help only lists commands supported by this headset.") @@ -43,7 +79,7 @@ fn main() { "Set the delay in minutes after which the headset will automatically shutdown.\n0 will disable automatic shutdown.", ) .hide(!SHOW_ALL_OPTIONS - && !device.can_set_automatic_shutdown()) + && !device_supports(&device, |d| d.can_set_automatic_shutdown())) .value_parser(clap::value_parser!(u8)), ) .arg( @@ -52,7 +88,7 @@ fn main() { .required(false) .help("Mute or unmute the headset.") .hide(!SHOW_ALL_OPTIONS - && !device.can_set_mute()) + && !device_supports(&device, |d| d.can_set_mute())) .value_parser(clap::value_parser!(bool)), ) .arg( @@ -61,7 +97,7 @@ fn main() { .required(false) .help("Enable or disable side tone.") .hide(!SHOW_ALL_OPTIONS - && !device.can_set_side_tone()) + && !device_supports(&device, |d| d.can_set_side_tone())) .value_parser(clap::value_parser!(bool)), ) .arg( @@ -70,7 +106,7 @@ fn main() { .required(false) .help("Set the side tone volume.") .hide(!SHOW_ALL_OPTIONS - && !device.can_set_side_tone_volume()) + && !device_supports(&device, |d| d.can_set_side_tone_volume())) .value_parser(clap::value_parser!(u8)), ) .arg( @@ -79,7 +115,7 @@ fn main() { .required(false) .help("Enable voice prompt. This may not be supported on your device.") .hide(!SHOW_ALL_OPTIONS - && !device.can_set_voice_prompt()) + && !device_supports(&device, |d| d.can_set_voice_prompt())) .value_parser(clap::value_parser!(bool)), ) .arg( @@ -88,7 +124,7 @@ fn main() { .required(false) .help("Enables surround sound. This may be on by default and cannot be changed on your device.") .hide(!SHOW_ALL_OPTIONS - && !device.can_set_surround_sound()) + && !device_supports(&device, |d| d.can_set_surround_sound())) .value_parser(clap::value_parser!(bool)), ) .arg( @@ -97,7 +133,7 @@ fn main() { .required(false) .help("Mute or unmute playback.") .hide(!SHOW_ALL_OPTIONS - && !device.can_set_silent_mode()) + && !device_supports(&device, |d| d.can_set_silent_mode())) .value_parser(clap::value_parser!(bool)), ) .arg( @@ -106,11 +142,27 @@ fn main() { .required(false) .help("Activates noise gate.") .hide(!SHOW_ALL_OPTIONS - && !device.can_set_silent_mode()) + && !device_supports(&device, |d| d.can_set_silent_mode())) .value_parser(clap::value_parser!(bool)), ) + .arg( + Arg::new("verbose") + .long("verbose") + .short('v') + .action(ArgAction::SetTrue) + .required(false) + .help("Use verbose output "), + ) .get_matches(); + let mut device = match device { + Ok(device) => device, + Err(e) => { + eprintln!("{e}"); + std::process::exit(1) + } + }; + let mut commands = Vec::new(); if let Some(delay) = matches.get_one::("automatic_shutdown") { let delay = *delay as u64; diff --git a/src/lib.rs b/src/lib.rs index c0c0df7..97dedc2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +use std::sync::OnceLock; #[cfg(target_os = "linux")] use std::{fs, io, process::Command, time::Duration}; @@ -7,11 +8,18 @@ use dialog::{Choice, DialogBox}; // #![warn(missing_docs)] pub mod devices; +pub static VERBOSE: OnceLock = OnceLock::new(); + #[macro_export] macro_rules! debug_println { ($($args:tt)*) => { #[cfg(debug_assertions)] println!($($args)*); + + #[cfg(not(debug_assertions))] + if *$crate::VERBOSE.get().unwrap_or(&false) { + println!($($args)*); + } }; } diff --git a/src/main.rs b/src/main.rs index dae13aa..858313e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,9 +10,11 @@ mod tray_battery_icon_state; #[cfg(not(target_os = "linux"))] fn main() { + use clap::ArgAction; use std::sync::mpsc; use hyper_headset::devices::{DeviceEvent, DeviceProperties}; + use hyper_headset::VERBOSE; use winit::event_loop::{ControlFlow, EventLoop, EventLoopProxy}; use crate::status_tray_not_linux::TrayApp; @@ -34,6 +36,7 @@ fn main() { let matches = Command::new(env!("CARGO_PKG_NAME")) .version(env!("CARGO_PKG_VERSION")) + .disable_version_flag(false) .author(env!("CARGO_PKG_AUTHORS")) .about("A tray application for monitoring HyperX headsets.") .arg( @@ -52,8 +55,17 @@ fn main() { .default_value("true") .value_parser(clap::value_parser!(bool)), ) + .arg(Arg::new("verbose") + .long("verbose") + .short('v') + .action(ArgAction::SetTrue) + .required(false) + .help("Use verbose output ") + ) .get_matches(); + VERBOSE.set(matches.get_flag("verbose")).unwrap(); + let press_mute_key = *matches.get_one::("press_mute_key").unwrap_or(&true); let mut enigo = if press_mute_key { match Enigo::new(&Settings::default()) { @@ -128,6 +140,7 @@ fn main() { #[cfg(target_os = "linux")] fn main() { + use clap::ArgAction; use clap::{Arg, Command}; use enigo::{Direction, Enigo, Key, Keyboard, Settings}; use std::sync::mpsc; @@ -136,8 +149,8 @@ fn main() { use hyper_headset::devices::connect_compatible_device; use status_tray::{StatusTray, TrayHandler}; - use hyper_headset::act_as_askpass_handler; use hyper_headset::prompt_user_for_udev_rule; + use hyper_headset::{act_as_askpass_handler, VERBOSE}; if let Ok(name) = std::env::current_exe() { if let Some(name) = name.to_str() { @@ -151,6 +164,7 @@ fn main() { prompt_user_for_udev_rule(); let matches = Command::new(env!("CARGO_PKG_NAME")) .version(env!("CARGO_PKG_VERSION")) + .disable_version_flag(false) .author(env!("CARGO_PKG_AUTHORS")) .about("A tray application for monitoring HyperX headsets.") .arg( @@ -169,6 +183,13 @@ fn main() { .default_value("true") .value_parser(clap::value_parser!(bool)), ) + .arg(Arg::new("verbose") + .long("verbose") + .short('v') + .action(ArgAction::SetTrue) + .required(false) + .help("Use verbose output ") + ) .get_matches(); let press_mute_key = *matches.get_one::("press_mute_key").unwrap_or(&true); @@ -183,6 +204,8 @@ fn main() { } else { None }; + VERBOSE.set(matches.get_flag("verbose")).unwrap(); + let refresh_interval = *matches.get_one::("refresh_interval").unwrap_or(&3); let refresh_interval = Duration::from_secs(refresh_interval); let (tx, rx) = mpsc::channel();