From a940b24c70e9f397e2bfa514d3f45d27c1ee11b7 Mon Sep 17 00:00:00 2001 From: Zack H Date: Sun, 18 Sep 2022 18:50:40 -0400 Subject: [PATCH] lib/loop: Add command-line args --- Cargo.lock | 53 ++++++++++++++++++++++++++++++++++++++++++ derive-loop/src/lib.rs | 36 ++++++++++++++++++++++++---- pmb/Cargo.toml | 2 ++ pmb/src/lib.rs | 49 +++++++++++++++++++++----------------- 4 files changed, 114 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6191689..3b9534c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -613,6 +613,26 @@ dependencies = [ "syn", ] +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -1129,6 +1149,26 @@ dependencies = [ "system-deps", ] +[[package]] +name = "gumdrop" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bc700f989d2f6f0248546222d9b4258f5b02a171a431f8285a81c08142629e3" +dependencies = [ + "gumdrop_derive", +] + +[[package]] +name = "gumdrop_derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "729f9bd3449d77e7831a18abfb7ba2f99ee813dfd15b8c2167c9a54ba20aa99d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1829,7 +1869,9 @@ dependencies = [ "bincode", "bytemuck", "derive-disk", + "dirs", "flate2", + "gumdrop", "log", "lyon", "rand", @@ -1952,6 +1994,17 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + [[package]] name = "regex" version = "1.6.0" diff --git a/derive-loop/src/lib.rs b/derive-loop/src/lib.rs index 289ce55..e4e16aa 100644 --- a/derive-loop/src/lib.rs +++ b/derive-loop/src/lib.rs @@ -184,6 +184,19 @@ pub fn pmb_loop(input: proc_macro::TokenStream) -> proc_macro::TokenStream { quote::quote! { fn #loop_name() { + use powdermilk_biscuits::gumdrop::Options; + let args = powdermilk_biscuits::Args::parse_args_default_or_exit(); + + if args.version { + println!( + "Powdermilk Biscuits ({} {}, file format version {})", + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_VERSION"), + powdermilk_biscuits::migrate::Version::CURRENT, + ); + return; + } + if cfg!(unix) { let var = std::env::var("WINIT_UNIX_BACKEND"); match var.as_ref().map(|s| s.as_str()) { @@ -201,7 +214,20 @@ pub fn pmb_loop(input: proc_macro::TokenStream) -> proc_macro::TokenStream { } } - let mut config = Config::from_disk(); + let config_path = if let Some(config_path) = args.config { + config_path + } else { + if cfg!(feature = "pmb-release") { + let mut dir = powdermilk_biscuits::dirs::config_dir().unwrap(); + dir.push("powdermilk-biscuits"); + dir.push("config.ron"); + dir + } else { + std::path::PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"), "/../config.ron")) + } + }; + + let mut config = Config::from_disk(&config_path); let mut builder = WindowBuilder::new() .with_maximized(config.window_maximized) .with_title(powdermilk_biscuits::TITLE_UNMODIFIED); @@ -223,7 +249,7 @@ pub fn pmb_loop(input: proc_macro::TokenStream) -> proc_macro::TokenStream { Ui::<#backend_crate_name::#coords_name>::new(width, height) }; let mut sketch: Sketch<#backend_crate_name::#stroke_backend_name> = - if let Some(filename) = std::env::args().nth(1) { + if let Some(filename) = args.file { Sketch::with_filename(&mut ui, std::path::PathBuf::from(filename)) } else { Sketch::default() @@ -269,11 +295,11 @@ pub fn pmb_loop(input: proc_macro::TokenStream) -> proc_macro::TokenStream { .unwrap_or(false) { flow.set_exit(); - config.save(); + config.save(&config_path); } } else { flow.set_exit(); - config.save(); + config.save(&config_path); } } @@ -291,7 +317,7 @@ pub fn pmb_loop(input: proc_macro::TokenStream) -> proc_macro::TokenStream { .. } => { flow.set_exit(); - config.save(); + config.save(&config_path); } #event_enum_name::WindowEvent { diff --git a/pmb/Cargo.toml b/pmb/Cargo.toml index 039fec6..28e890e 100644 --- a/pmb/Cargo.toml +++ b/pmb/Cargo.toml @@ -20,3 +20,5 @@ lyon = { git = 'https://github.com/zphixon/lyon', branch = 'new-euclid' } serde = { version = '1.0.144', features = ['derive'] } ron = '0.8.0' slotmap = '1.0.6' +gumdrop = '0.8.1' +dirs = '4.0.0' diff --git a/pmb/src/lib.rs b/pmb/src/lib.rs index db4ccd1..85fec9b 100644 --- a/pmb/src/lib.rs +++ b/pmb/src/lib.rs @@ -15,9 +15,12 @@ use crate::{ graphics::{Color, ColorExt, PixelPos, StrokePoint, StrokePos}, stroke::{Stroke, StrokeElement}, }; +pub use dirs; use event::Combination; +pub use gumdrop; use lyon::lyon_tessellation::{StrokeOptions, StrokeTessellator}; use slotmap::{DefaultKey, SlotMap}; +use std::path::{Path, PathBuf}; pub const TITLE_UNMODIFIED: &str = "hi! <3"; pub const TITLE_MODIFIED: &str = "hi! <3 (modified)"; @@ -82,6 +85,18 @@ pub trait StrokeBackend: std::fmt::Debug { fn is_dirty(&self) -> bool; } +#[derive(gumdrop::Options, Debug)] +pub struct Args { + #[options(help = "Show this message")] + help: bool, + #[options(help = "Print the version", short = "V")] + pub version: bool, + #[options(help = "Config file location")] + pub config: Option, + #[options(free, help = "File to open")] + pub file: Option, +} + #[derive(Default, PartialEq, Debug, Clone, Copy, serde::Serialize, serde::Deserialize)] pub enum Tool { #[default] @@ -138,14 +153,12 @@ pub struct Config { } impl Default for Config { - #[cfg(feature = "pmb-release")] - fn default() -> Self { - Self::new() - } - - #[cfg(not(feature = "pmb-release"))] fn default() -> Self { - Self::debug() + if cfg!(feature = "pmb-release") { + Self::new() + } else { + Self::debug() + } } } @@ -211,19 +224,10 @@ impl Config { } } - #[cfg(not(feature = "pmb-release"))] - fn path() -> &'static str { - concat!(env!("CARGO_MANIFEST_DIR"), "/../config.ron") - } - - #[cfg(feature = "pmb-release")] - fn path() -> &'static str { - todo!() - } - // TODO registry/gsettings or something, this is dumb - pub fn from_disk() -> Config { - let file = match std::fs::read_to_string(Self::path()) { + pub fn from_disk(path: &Path) -> Config { + log::info!("load config from {}", path.display()); + let file = match std::fs::read_to_string(path) { Ok(contents) => contents, Err(err) if err.kind() == std::io::ErrorKind::NotFound => { return Config::default(); @@ -243,9 +247,12 @@ impl Config { } } - pub fn save(&self) { + pub fn save(&self, path: &Path) { + log::info!("save config to {}", path.display()); + if self.had_error_parsing { // don't overwrite broken configs + log::error!("had error"); return; } @@ -261,7 +268,7 @@ impl Config { let contents = format!("// this file generated automatically.\n// do not edit while pmb is running!!\n{contents}"); - match std::fs::write(Self::path(), contents) { + match std::fs::write(path, contents) { Err(err) => { PmbError::from(err).display_with(String::from("Couldn't read config file")); }