1use std::borrow::Cow;
2use std::fmt::Display;
3use std::io::Write;
4use std::path::Path;
5use std::path::PathBuf;
6
7
8#[derive(Debug, Clone)]
9#[cfg_attr(feature = "clap", derive(clap::Subcommand))]
10#[cfg_attr(feature = "clap", command(name = "COMMAND"))]
11pub enum Command {
12 Run {
14 path: String,
17 },
18
19 #[cfg_attr(feature = "clap", command(name = "run-sys"))]
21 RunSystem {
22 #[cfg_attr(feature = "clap", arg(value_name = "NAME"))]
24 path: SystemPath,
25 },
26
27 Datadisk,
29
30 #[cfg_attr(feature = "clap", command(visible_alias = "sleep"))]
32 Hibernate,
33
34 Echo {
36 #[cfg_attr(feature = "clap", arg(default_value_t = Switch::On))]
37 value: Switch,
38 },
39
40 #[cfg_attr(feature = "clap", command(visible_alias = "sn"))]
42 SerialNumber,
43
44 #[cfg_attr(feature = "clap", command(visible_alias = "V"))]
46 Version,
47
48 #[cfg_attr(feature = "clap", command(visible_alias = "btn"))]
52 Button {
53 #[cfg_attr(feature = "clap", clap(subcommand))]
55 button: Button,
56 },
57
58 #[cfg_attr(feature = "clap", command(visible_alias = "msg"))]
60 Message {
61 message: String,
63 },
64
65 #[cfg_attr(feature = "clap", command(visible_alias = "!"))]
67 Custom {
68 cmd: String,
70 },
71}
72
73
74#[derive(Debug, Clone)]
75#[cfg_attr(feature = "clap", derive(clap::Parser))]
76pub enum PdxPath {
77 System { path: SystemPath },
78 User { path: PathBuf },
79}
80
81
82#[derive(Debug, Clone)]
83#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
84pub enum SystemPath {
85 Launcher,
89 Settings,
93 Catalog,
97}
98
99impl SystemPath {
100 pub fn as_path(&self) -> &Path {
101 match self {
102 Self::Launcher => Path::new("/System/Launcher.pdx"),
103 Self::Settings => Path::new("/System/Settings.pdx"),
104 Self::Catalog => Path::new("/System/Catalog.pdx"),
105 }
106 }
107}
108
109
110impl Command {
111 pub fn as_str(&self) -> Cow<'_, str> {
112 match self {
113 Command::Run { path } => format!("run {path}").into(),
114 Command::RunSystem { path } => format!("run {}", path.as_path().display()).into(),
115 Command::Datadisk => "datadisk".into(),
116 Command::Hibernate => "hibernate".into(),
117 Command::Echo { value: Switch::On } => "echo on".into(),
118 Command::Echo { value: Switch::Off } => "echo off".into(),
119 Command::SerialNumber => "serialread".into(),
120 Command::Version => "version".into(),
121 Command::Button { button } => format!("btn {}", button.as_btn_str()).into(),
122 Command::Message { message } => format!("msg {message}").into(),
123 Command::Custom { cmd } => cmd.into(),
124 }
125 }
126}
127
128
129impl Display for Command {
130 #[inline]
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.as_str().fmt(f) }
132}
133
134impl Command {
135 pub fn with_break(&self) -> String {
136 let cmd = self.as_str();
137 let mut line = String::with_capacity(cmd.len() + 2);
138 line.push('\n'); line.push_str(&cmd);
140 line.push('\n');
141 line
142 }
143
144 pub fn with_break_to<W: Write>(&self, mut writer: W) -> std::io::Result<()> { writeln!(writer, "\n{self}\n") }
145}
146
147
148#[derive(Debug, Clone, Copy)]
149#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
150#[cfg_attr(feature = "clap", clap(name = "BOOL"))]
151pub enum Switch {
152 #[cfg_attr(feature = "clap", value(alias = "true"))]
155 On,
156 #[cfg_attr(feature = "clap", value(alias = "false"))]
159 Off,
160}
161
162impl From<bool> for Switch {
163 fn from(value: bool) -> Self { if value { Switch::On } else { Switch::Off } }
164}
165
166impl From<Switch> for bool {
167 fn from(val: Switch) -> Self {
168 match val {
169 Switch::On => true,
170 Switch::Off => false,
171 }
172 }
173}
174
175impl std::fmt::Display for Switch {
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 let value = match self {
178 Self::On => "on",
179 Self::Off => "off",
180 };
181 write!(f, "{value}")
182 }
183}
184
185
186#[derive(Debug, Clone, Copy)]
187#[cfg_attr(feature = "clap", derive(clap::Subcommand))]
188#[cfg_attr(feature = "clap", command(name = "BTN"))]
189pub enum Button {
190 A {
191 #[cfg_attr(feature = "clap", arg(required = false, default_value_t = ButtonAction::Both))]
192 action: ButtonAction,
193 },
194 B {
195 #[cfg_attr(feature = "clap", arg(required = false, default_value_t = ButtonAction::Both))]
196 action: ButtonAction,
197 },
198}
199
200impl std::fmt::Display for Button {
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 match self {
203 Button::A { action } => write!(f, "{action}a"),
204 Button::B { action } => write!(f, "{action}b"),
205 }
206 }
207}
208
209impl Button {
210 pub fn as_btn_str(&self) -> String {
211 match self {
212 Button::A { action } => format!("{}a", action.as_btn_prefix()),
213 Button::B { action } => format!("{}b", action.as_btn_prefix()),
214 }
215 }
216}
217
218
219#[derive(Debug, Clone, Copy)]
220#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
221#[cfg_attr(feature = "clap", clap(name = "BTN"))]
222pub enum ButtonAction {
223 #[cfg_attr(feature = "clap", value(alias = "-"))]
224 Down,
225 #[cfg_attr(feature = "clap", value(alias = "+"))]
226 Up,
227 #[cfg_attr(feature = "clap", value(alias = "+-"), value(alias = "±"))]
228 Both,
229}
230
231impl Default for ButtonAction {
232 fn default() -> Self { Self::Both }
233}
234
235impl std::fmt::Display for ButtonAction {
236 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
237 let value = match self {
238 Self::Down => "-",
239 Self::Up => "+",
240 Self::Both => "±",
241 };
242 write!(f, "{value}")
243 }
244}
245
246impl ButtonAction {
247 pub fn as_btn_prefix(&self) -> &'static str {
248 match self {
249 Self::Down => "+",
250 Self::Up => "-",
251 Self::Both => "",
252 }
253 }
254}