Add setup tray entry, wizard progress/log, config add/remove, stale-wine check
- tray: uninstalled launchers now show a "Setup…" entry that spawns the setup wizard as a child process. - setup.rs: download shows a progress bar (bytes / total), and umu-run stdout+stderr stream into a scrollable log pane. A 250 ms tick subscription pulls updates from the shared state. - config add-launcher / remove-launcher CLI, with sensible defaults for prefix_dir, gameid, and process_pattern derived from name/exe. - diagnose: flag stale wineserver processes when no launcher is running, suggesting `umutray kill`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -61,6 +61,21 @@ fn default_proton_version() -> String {
|
||||
"GE-Proton".into()
|
||||
}
|
||||
|
||||
fn regex_escape(s: &str) -> String {
|
||||
let mut out = String::with_capacity(s.len() + 4);
|
||||
for c in s.chars() {
|
||||
if matches!(
|
||||
c,
|
||||
'.' | '*' | '?' | '+' | '(' | ')' | '[' | ']'
|
||||
| '{' | '}' | '|' | '\\' | '^' | '$'
|
||||
) {
|
||||
out.push('\\');
|
||||
}
|
||||
out.push(c);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// The six launchers umutray ships out of the box. `exe_path`, `gameid`,
|
||||
/// and `process_pattern` are best-effort defaults for typical installs —
|
||||
/// users can adjust per-launcher via `umutray config edit`.
|
||||
@@ -231,6 +246,60 @@ impl Config {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn add_launcher(
|
||||
&mut self,
|
||||
name: String,
|
||||
display: Option<String>,
|
||||
exe_path: PathBuf,
|
||||
prefix_dir: Option<PathBuf>,
|
||||
gameid: Option<String>,
|
||||
process_pattern: Option<String>,
|
||||
installer_url: Option<String>,
|
||||
) -> Result<()> {
|
||||
if self.launchers.iter().any(|l| l.name == name) {
|
||||
anyhow::bail!("launcher '{name}' already exists");
|
||||
}
|
||||
let display = display.unwrap_or_else(|| name.clone());
|
||||
let prefix_dir = prefix_dir
|
||||
.unwrap_or_else(|| home_dir().join("Games").join(&name));
|
||||
let gameid = gameid.unwrap_or_else(|| format!("umu-{name}"));
|
||||
let process_pattern = process_pattern.unwrap_or_else(|| {
|
||||
exe_path
|
||||
.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
.map(regex_escape)
|
||||
.unwrap_or_else(|| name.clone())
|
||||
});
|
||||
self.launchers.push(Launcher {
|
||||
name: name.clone(),
|
||||
display,
|
||||
prefix_dir,
|
||||
exe_path,
|
||||
gameid,
|
||||
process_pattern,
|
||||
installer_url,
|
||||
proton_version: None,
|
||||
});
|
||||
self.save()?;
|
||||
println!("\x1b[1;32m✓\x1b[0m Added launcher '{name}'.");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_launcher(&mut self, name: &str) -> Result<()> {
|
||||
let before = self.launchers.len();
|
||||
self.launchers.retain(|l| l.name != name);
|
||||
if self.launchers.len() == before {
|
||||
anyhow::bail!("no launcher named '{name}'");
|
||||
}
|
||||
self.save()?;
|
||||
println!(
|
||||
"\x1b[1;32m✓\x1b[0m Removed '{name}'. \
|
||||
The Wine prefix on disk was left untouched."
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Update global fields non-interactively, then save.
|
||||
/// Use `config edit` for per-launcher changes.
|
||||
pub fn set_globals(
|
||||
|
||||
Reference in New Issue
Block a user