use std::io::{self, Write};
use clap::Parser;
use whatcable::{DeviceManager, Sysfs};
mod output;
use output::{print_json, print_text};
#[derive(Parser, Debug)]
#[command(
name = "whatcable",
version,
about = "Tells you what each USB cable / device on Linux can actually do.",
long_about = "WhatCable — shows what each USB cable / device can do.\n\
Port of WhatCable (macOS) by Darryl Morley."
)]
struct Cli {
#[arg(long)]
json: bool,
#[arg(long)]
watch: bool,
#[arg(long)]
raw: bool,
#[arg(long, value_name = "PATH")]
sysfs_root: Option<std::path::PathBuf>,
}
fn main() -> io::Result<()> {
let cli = Cli::parse();
let sysfs = match cli.sysfs_root.as_ref() {
Some(p) => Sysfs::with_root(p),
None => Sysfs::linux(),
};
let mut mgr = DeviceManager::with_sysfs(sysfs);
if cli.watch {
#[cfg(feature = "watch")]
return run_watch(&mut mgr, cli.json, cli.raw);
#[cfg(not(feature = "watch"))]
{
eprintln!("--watch is not available: built without the `watch` feature.");
std::process::exit(2);
}
}
mgr.refresh();
let stdout = io::stdout();
let mut out = stdout.lock();
if cli.json {
print_json(&mut out, &mgr, cli.raw)
} else {
print_text(&mut out, &mgr, cli.raw)
}
}
#[cfg(feature = "watch")]
fn run_watch(mgr: &mut DeviceManager, use_json: bool, show_raw: bool) -> io::Result<()> {
use std::time::Duration;
use whatcable::watch::{run_loop, RefreshReason};
run_loop(Duration::from_millis(500), |reason| {
mgr.refresh();
let stdout = io::stdout();
let mut out = stdout.lock();
if !use_json {
if matches!(reason, RefreshReason::Hotplug | RefreshReason::Initial) {
write!(out, "\x1b[2J\x1b[H")?;
}
print_text(&mut out, mgr, show_raw)?;
} else {
print_json(&mut out, mgr, show_raw)?;
}
out.flush()
})
}