feat(cli): full command-line interface via clap

Replace the ad-hoc `--serve` arg sniff with a clap-parsed CLI:

- positional <file> to open at startup (also the OS file-association path)
- --new, --read-only, --backend, --safe-mode/--no-gpu
- --serve/--port (headless JSON automation, unchanged behaviour)
- --export IN OUT (headless format convert via the automation load/save infra)
- --script FILE (run command lines at startup)
- --log/RUST_LOG, plus --version/--help for free

GUI-only options pass to app::boot through a OnceLock config; read-only
gates the save paths. The web build skips parsing (no args).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-20 13:59:20 +03:00
commit 79bb1d67b1
8 changed files with 399 additions and 30 deletions

View file

@ -32,6 +32,29 @@ pub fn serve() {
}
}
/// Headless one-shot format conversion (`--export IN OUT`). Loads `input`,
/// writes `output` (format chosen from `output`'s extension), and returns a
/// process exit code (0 on success). No window is created.
pub fn export_headless(input: &std::path::Path, output: &std::path::Path) -> i32 {
let doc = match crate::io::load_file(input) {
Ok(doc) => doc,
Err(e) => {
eprintln!("export: cannot read {}: {e}", input.display());
return 1;
}
};
match crate::io::save(&doc, output) {
Ok(()) => {
println!("Exported {} → {}", input.display(), output.display());
0
}
Err(e) => {
eprintln!("export: cannot write {}: {e}", output.display());
1
}
}
}
/// `--port <N>` if present on the command line.
fn port_arg() -> Option<u16> {
let mut args = std::env::args();