use std::borrow::Cow;
use std::fmt::Display;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "clap", derive(clap::Subcommand))]
#[cfg_attr(feature = "clap", command(name = "COMMAND"))]
pub enum Command {
Run {
path: String,
},
#[cfg_attr(feature = "clap", command(name = "run-sys"))]
RunSystem {
#[cfg_attr(feature = "clap", arg(value_name = "NAME"))]
path: SystemPath,
},
Datadisk,
#[cfg_attr(feature = "clap", command(visible_alias = "sleep"))]
Hibernate,
Echo {
#[cfg_attr(feature = "clap", arg(default_value_t = Switch::On))]
value: Switch,
},
#[cfg_attr(feature = "clap", command(visible_alias = "sn"))]
SerialNumber,
#[cfg_attr(feature = "clap", command(visible_alias = "V"))]
Version,
#[cfg_attr(feature = "clap", command(visible_alias = "btn"))]
Button {
#[cfg_attr(feature = "clap", clap(subcommand))]
button: Button,
},
#[cfg_attr(feature = "clap", command(visible_alias = "msg"))]
Message {
message: String,
},
#[cfg_attr(feature = "clap", command(visible_alias = "!"))]
Custom {
cmd: String,
},
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "clap", derive(clap::Parser))]
pub enum PdxPath {
System { path: SystemPath },
User { path: PathBuf },
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
pub enum SystemPath {
Launcher,
Settings,
Catalog,
}
impl SystemPath {
pub fn as_path(&self) -> &Path {
match self {
Self::Launcher => Path::new("/System/Launcher.pdx"),
Self::Settings => Path::new("/System/Settings.pdx"),
Self::Catalog => Path::new("/System/Catalog.pdx"),
}
}
}
impl Command {
pub fn as_str(&self) -> Cow<'_, str> {
match self {
Command::Run { path } => format!("run {path}").into(),
Command::RunSystem { path } => format!("run {}", path.as_path().display()).into(),
Command::Datadisk => "datadisk".into(),
Command::Hibernate => "hibernate".into(),
Command::Echo { value: Switch::On } => "echo on".into(),
Command::Echo { value: Switch::Off } => "echo off".into(),
Command::SerialNumber => "serialread".into(),
Command::Version => "version".into(),
Command::Button { button } => format!("btn {}", button.as_btn_str()).into(),
Command::Message { message } => format!("msg {message}").into(),
Command::Custom { cmd } => cmd.into(),
}
}
}
impl Display for Command {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.as_str().fmt(f) }
}
impl Command {
pub fn with_break(&self) -> String {
let cmd = self.as_str();
let mut line = String::with_capacity(cmd.len() + 2);
line.push('\n'); line.push_str(&cmd);
line.push('\n');
line
}
pub fn with_break_to<W: Write>(&self, mut writer: W) -> std::io::Result<()> { writeln!(writer, "\n{self}\n") }
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[cfg_attr(feature = "clap", clap(name = "BOOL"))]
pub enum Switch {
#[cfg_attr(feature = "clap", value(alias = "true"))]
On,
#[cfg_attr(feature = "clap", value(alias = "false"))]
Off,
}
impl From<bool> for Switch {
fn from(value: bool) -> Self { if value { Switch::On } else { Switch::Off } }
}
impl From<Switch> for bool {
fn from(val: Switch) -> Self {
match val {
Switch::On => true,
Switch::Off => false,
}
}
}
impl std::fmt::Display for Switch {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let value = match self {
Self::On => "on",
Self::Off => "off",
};
write!(f, "{value}")
}
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "clap", derive(clap::Subcommand))]
#[cfg_attr(feature = "clap", command(name = "BTN"))]
pub enum Button {
A {
#[cfg_attr(feature = "clap", arg(required = false, default_value_t = ButtonAction::Both))]
action: ButtonAction,
},
B {
#[cfg_attr(feature = "clap", arg(required = false, default_value_t = ButtonAction::Both))]
action: ButtonAction,
},
}
impl std::fmt::Display for Button {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Button::A { action } => write!(f, "{action}a"),
Button::B { action } => write!(f, "{action}b"),
}
}
}
impl Button {
pub fn as_btn_str(&self) -> String {
match self {
Button::A { action } => format!("{}a", action.as_btn_prefix()),
Button::B { action } => format!("{}b", action.as_btn_prefix()),
}
}
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[cfg_attr(feature = "clap", clap(name = "BTN"))]
pub enum ButtonAction {
#[cfg_attr(feature = "clap", value(alias = "-"))]
Down,
#[cfg_attr(feature = "clap", value(alias = "+"))]
Up,
#[cfg_attr(feature = "clap", value(alias = "+-"), value(alias = "±"))]
Both,
}
impl Default for ButtonAction {
fn default() -> Self { Self::Both }
}
impl std::fmt::Display for ButtonAction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let value = match self {
Self::Down => "-",
Self::Up => "+",
Self::Both => "±",
};
write!(f, "{value}")
}
}
impl ButtonAction {
pub fn as_btn_prefix(&self) -> &'static str {
match self {
Self::Down => "+",
Self::Up => "-",
Self::Both => "",
}
}
}