bar-rubble 0.5.2

Quickly generate output for viewing in swaybar or similar
Documentation
use clap::Parser;
use clap::Subcommand;
use serde_json::json;
use std::error::Error;
use rubblets::PrintFormattingStringsArgs;
use rubblets::RubbleResult;

#[cfg(feature = "device")]
use rubblets::device;
#[cfg(feature = "ip")]
use rubblets::ip;
#[cfg(feature = "mail")]
use rubblets::mail;
#[cfg(feature = "mpris")]
use rubblets::mpris;
#[cfg(feature = "network")]
use rubblets::network;
#[cfg(feature = "razor")]
use rubblets::razor;
#[cfg(feature = "weather")]
use rubblets::weather;
#[cfg(feature = "wireguard")]
use rubblets::wireguard;

#[derive(Parser)]
#[clap(author, version, about, arg_required_else_help = true)]
/// Quickly generate output for viewing in swaybar or similar
struct RubbleArgs {
    #[command(subcommand)]
    command: Option<Commands>,
    user_format: Option<String>,
}

#[derive(Subcommand)]
/// These are the rubblets available
enum Commands {
    /// Prints local ip addr
    #[cfg(feature = "ip")]
    IP,
    /// Print number of unread emails
    #[cfg(feature = "mail")]
    Mail(mail::MailArgs),
    /// Prints currently playing media eg spotify/youtube
    #[cfg(feature = "mpris")]
    Mpris,
    #[cfg(feature = "network")]
    /// Prints status of network adapter
    Network(network::NetworkArgs),
    /// Print charge level of razor mouse as a percentage
    #[cfg(feature = "razor")]
    Razor,
    #[cfg(feature = "device")]
    /// Print system level information
    Device(device::DeviceArgs),
    /// Prints Weather. Defaults to --city=portsmouth
    #[cfg(feature = "weather")]
    Weather(weather::WeatherArgs),
    /// Prints Status of WG connection
    #[cfg(feature = "wireguard")]
    Wireguard,
    /// Add this to the beginning of the arguments to see possible formatting options
    ListFormattingStrings(PrintFormattingStringsArgs),
}

impl Commands {
    /// Checks a rubblet for the available output strings
    fn formatting_strings(self) -> &'static str {
        match self {
            #[cfg(feature = "ip")]
            Commands::IP => ip::formatting_strings(),
            #[cfg(feature = "mail")]
            Commands::Mail(_) => mail::formatting_strings(),
            #[cfg(feature = "mpris")]
            Commands::Mpris => mpris::formatting_strings(),
            #[cfg(feature = "network")]
            Commands::Network(_) => network::formatting_strings(),
            #[cfg(feature = "razor")]
            Commands::Razor => razor::formatting_strings(),
            #[cfg(feature = "device")]
            Commands::Device(args) => args.selector.formatting_strings(),
            #[cfg(feature = "weather")]
            Commands::Weather(_) => weather::formatting_strings(),
            #[cfg(feature = "wireguard")]
            Commands::Wireguard => wireguard::formatting_strings(),
            Commands::ListFormattingStrings(_) => "",
        }
    }

    /// reads an str and returns a rubblet command enum
    /// # Examples
    /// ```
    /// let result = from_str("ip").unwrap()
    /// assert_eq!(result, Commands::IP);
    /// ```
    fn from_str(
        input: &str,
        select: Option<device::SystemStats>,
    ) -> Result<Commands, Box<dyn Error>> {
        match input {
            #[cfg(feature = "ip")]
            "ip" => Ok(Commands::IP),
            #[cfg(feature = "mail")]
            "mail" => Ok(Commands::Mail(mail::MailArgs::empty())),
            #[cfg(feature = "mpris")]
            "mpris" => Ok(Commands::Mpris),
            #[cfg(feature = "network")]
            "network" => Ok(Commands::Network(network::NetworkArgs::empty())),
            #[cfg(feature = "razor")]
            "razor" => Ok(Commands::Razor),
            #[cfg(feature = "device")]
            "device" => Ok(Commands::Device(device::DeviceArgs {
                selector: select.unwrap(),
            })),
            #[cfg(feature = "weather")]
            "weather" => Ok(Commands::Weather(weather::WeatherArgs::empty())),
            #[cfg(feature = "wireguard")]
            "wireguard" => Ok(Commands::Wireguard),
            _ => panic!("No matching Command"),
        }
    }
}

/// Returns a RubbleResult so the available strings for the rubblet can be shown to user
fn print_formatting_strings(args: &PrintFormattingStringsArgs) -> RubbleResult {
    let available = Commands::from_str(args.command.as_str(), args.selector)
        .unwrap()
        .formatting_strings();
    let formatted = rubblets::format_formatting_strings(available);
    return RubbleResult::new(
        Ok(json!({ "available": formatted })),
        "{{available}}"
    )
}

/// Parse arguments and run function
#[tokio::main]
/// Quickly generate output for viewing in swaybar or similar
async fn main() {
    let args = RubbleArgs::parse();

    let mut rubble_result = match args.command {
        #[cfg(feature = "ip")]
        Some(Commands::IP) => ip::print_ip(),
        #[cfg(feature = "mail")]
        Some(Commands::Mail(mailargs)) => mail::count(&mailargs),
        #[cfg(feature = "mpris")]
        Some(Commands::Mpris) => mpris::currently_playing(),
        #[cfg(feature = "network")]
        Some(Commands::Network(networkargs)) => network::check_status(&networkargs),
        #[cfg(feature = "razor")]
        Some(Commands::Razor) => razor::mouse_battery_level(),
        #[cfg(feature = "device")]
        Some(Commands::Device(deviceargs)) => device::SystemStats::to_result(&deviceargs.selector),
        #[cfg(feature = "weather")]
        Some(Commands::Weather(weatherargs)) => weather::weather_json(&weatherargs).await,
        #[cfg(feature = "wireguard")]
        Some(Commands::Wireguard) => wireguard::wg_status(),
        Some(Commands::ListFormattingStrings(printargs)) => print_formatting_strings(&printargs),
        None => panic!("wtf"),
    };
    rubble_result.user_format = args.user_format;
    rubble_result.print()
}