diff --git a/Cargo.lock b/Cargo.lock index 6716e1a..9564c4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,169 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "clap" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "proc-macro2" version = "1.0.101" @@ -20,6 +183,47 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.106" @@ -57,11 +261,89 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + [[package]] name = "wfassoc" version = "0.1.0" dependencies = [ + "regex", "thiserror", + "uuid", + "winreg", ] [[package]] @@ -76,6 +358,170 @@ dependencies = [ name = "wfassoc_exec" version = "0.1.0" dependencies = [ + "clap", "thiserror", "wfassoc", ] + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.4", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if", + "windows-sys 0.59.0", +] diff --git a/wfassoc/Cargo.toml b/wfassoc/Cargo.toml index 826449b..975775f 100644 --- a/wfassoc/Cargo.toml +++ b/wfassoc/Cargo.toml @@ -8,3 +8,6 @@ license = "SPDX:MIT" [dependencies] thiserror = { workspace = true } +winreg = "0.55.0" +regex = "1.11.3" +uuid = "1.18.1" diff --git a/wfassoc/src/components.rs b/wfassoc/src/components.rs index 6738297..9c5a98b 100644 --- a/wfassoc/src/components.rs +++ b/wfassoc/src/components.rs @@ -1,4 +1,67 @@ -/// The struct representing an Windows acceptable Prgram ID, +use regex::Regex; +use std::fmt::Display; +use std::path::PathBuf; +use std::str::FromStr; +use std::sync::LazyLock; +use thiserror::Error as TeError; + +/// The register kind when registering program. +pub enum RegisterKind { + /// Register for current user. + User, + /// Register for all users under this computer. + System, +} + +// region: File Extension + +/// The struct representing an file extension which must start with dot (`.`) +/// and followed by at least one arbitrary characters. +pub struct FileExt { + /// The body of file extension (excluding dot). + inner: String, +} + +impl FileExt { + pub fn new(file_ext: &str) -> Result { + static RE: LazyLock = LazyLock::new(|| Regex::new(r"^\.([^\.]+)$").unwrap()); + match RE.captures(file_ext) { + Some(v) => Ok(Self { + inner: v[1].to_string(), + }), + None => Err(ParseFileExtError::new()), + } + } +} + +/// The error occurs when try parsing string into FileExt. +#[derive(Debug, TeError)] +#[error("given file extension name is illegal")] +pub struct ParseFileExtError {} + +impl ParseFileExtError { + fn new() -> Self { + Self {} + } +} + +impl Display for FileExt { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, ".{}", self.inner) + } +} + +impl FromStr for FileExt { + type Err = ParseFileExtError; + + fn from_str(s: &str) -> Result { + Self::new(s) + } +} + +// endregion + +/// The struct representing an Windows acceptable Prgram ID, /// which looks like `Program.Document.2` pub struct ProgId { inner: String, @@ -12,30 +75,55 @@ impl ProgId { } } -/// Representing an file extension which must start with dot (`.`) -/// and followed by arbitrary characters. -pub struct FileExt { - inner: String, +// region: Executable Resource + +/// The struct representing an Windows executable resources path like +/// `path_to_file.exe,1`. +pub struct ExecRc { + /// The path to binary for finding resources. + binary: PathBuf, + /// The inner index of resources. + index: u32, } -impl FileExt { - pub fn new(file_ext: &str) -> Self { - Self { - inner: file_ext.to_string(), +impl ExecRc { + pub fn new(res_str: &str) -> Result { + static RE: LazyLock = LazyLock::new(|| Regex::new(r"^([^,]+),([0-9]+)$").unwrap()); + let caps = RE.captures(res_str); + if let Some(caps) = caps { + let binary = PathBuf::from_str(&caps[1])?; + let index = caps[2].parse::()?; + Ok(Self { binary, index }) + } else { + Err(ParseExecRcError::NoCapture) } } } -/// Representing an Windows recognizable icon string with format like: -/// `@path_to_file.exe,61`. -pub struct WinRc { - inner: String, +/// The error occurs when try parsing string into ExecRc. +#[derive(Debug, TeError)] +#[error("given string is not a valid executable resource string")] +pub enum ParseExecRcError { + /// Given string is not matched with format. + NoCapture, + /// Fail to convert executable part into path. + BadBinaryPath(#[from] std::convert::Infallible), + /// Fail to convert index part into valid number. + BadIndex(#[from] std::num::ParseIntError), } -impl WinRc { - pub fn new(icon: &str) -> Self { - Self { - inner: icon.to_string(), - } +impl FromStr for ExecRc { + type Err = ParseExecRcError; + + fn from_str(s: &str) -> Result { + ExecRc::new(s) } } + +impl Display for ExecRc { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{},{}", self.binary.to_str().unwrap(), self.index) + } +} + +// endregion diff --git a/wfassoc/src/error.rs b/wfassoc/src/error.rs new file mode 100644 index 0000000..504d7ea --- /dev/null +++ b/wfassoc/src/error.rs @@ -0,0 +1,15 @@ +use thiserror::Error as TeError; + +/// All possible error occurs in this crate. +#[derive(Debug, TeError)] +pub enum Error { + #[error("can not register because lack essential privilege. please consider running with Administrator role")] + NoPrivilege, + #[error("{0}")] + BadFileExt(#[from] super::components::ParseFileExtError), + #[error("{0}")] + BadExecRc(#[from] super::components::ParseExecRcError), +} + +/// The result type used in this crate. +pub type Result = std::result::Result; diff --git a/wfassoc/src/lib.rs b/wfassoc/src/lib.rs index b914ec9..c7d8b96 100644 --- a/wfassoc/src/lib.rs +++ b/wfassoc/src/lib.rs @@ -1,20 +1,13 @@ +//! This crate provide utilities fetching and manilupating Windows file association. +//! All code under crate are following Microsoft document: https://learn.microsoft.com/en-us/windows/win32/shell/customizing-file-types-bumper + #[cfg(not(target_os = "windows"))] compile_error!("Crate wfassoc is only supported on Windows."); +pub(crate) mod error; pub(crate) mod components; pub(crate) mod program; -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} +pub use error::Error as WfError; +pub use program::Program; +pub use components::RegisterKind; diff --git a/wfassoc/src/program.rs b/wfassoc/src/program.rs index 8670b0d..8166235 100644 --- a/wfassoc/src/program.rs +++ b/wfassoc/src/program.rs @@ -1,17 +1,35 @@ +use super::error::{Error, Result}; use super::components::*; +/// The struct representing a complete Win32 program. pub struct Program { - name: String, - prog_id: ProgId, file_exts: Vec, } impl Program { + /// Create a program descriptor. pub fn new() -> Self { Self { - name: String::new(), - prog_id: ProgId::new(""), file_exts: Vec::new(), } } } + +impl Program { + /// Register program in this computer + pub fn register(&self, kind: RegisterKind) -> Result<()> { + todo!("pretend to register >_<...") + } + + /// Unregister program from this computer. + pub fn unregister(&self) -> Result<()> { + todo!("pretend to unregister >_<...") + } +} + +impl Program { + /// Query file extension infos which this program want to associate with. + pub fn query(&self) -> Result<()> { + todo!("pretend to query >_<...") + } +} diff --git a/wfassoc_exec/Cargo.toml b/wfassoc_exec/Cargo.toml index e6629ad..69b6cc7 100644 --- a/wfassoc_exec/Cargo.toml +++ b/wfassoc_exec/Cargo.toml @@ -9,3 +9,4 @@ license = "SPDX:MIT" [dependencies] thiserror = { workspace = true } wfassoc = { path="../wfassoc" } +clap = { version="4.5.48", features=["derive"]} diff --git a/wfassoc_exec/src/main.rs b/wfassoc_exec/src/main.rs index e7a11a9..fb65262 100644 --- a/wfassoc_exec/src/main.rs +++ b/wfassoc_exec/src/main.rs @@ -1,3 +1,94 @@ -fn main() { - println!("Hello, world!"); +use clap::{Parser, Subcommand}; +use std::process; +use wfassoc::{Program, RegisterKind, WfError}; + +type Result = std::result::Result; + +// region: Command Line Parser + +/// Simple program to manage Windows file associations +#[derive(Parser)] +#[command(name = "Windows File Association Operator", version, about)] +struct Cli { + /// The toml file introducing the complete program + #[arg( + short = 'c', + long = "config", + value_name = "PROG_CONFIG", + required = true + )] + config_file: String, + + /// The scope where wfassoc operate + #[arg(short = 'f', long = "for", value_name = "TARGET", value_enum, default_value_t = ForTarget::User)] + for_which: ForTarget, + + #[command(subcommand)] + command: Commands, +} + +#[derive(clap::ValueEnum, Clone)] +enum ForTarget { + #[value(name = "user")] + User, + #[value(name = "system")] + System, +} + +impl From for RegisterKind { + fn from(target: ForTarget) -> Self { + match target { + ForTarget::User => RegisterKind::User, + ForTarget::System => RegisterKind::System, + } + } +} + +#[derive(Subcommand)] +enum Commands { + /// Register the program + #[command(name = "register")] + Register, + /// Unregister the program + #[command(name = "unregister")] + Unregister, + /// Query file associations + #[command(name = "query")] + Query, +} + +// endregion + +// region: Correponding Runner + +fn run_register(cli: Cli) -> Result<()> { + let program = Program::new(); + let kind: RegisterKind = cli.for_which.into(); + program.register(kind) +} + +fn run_unregister(cli: Cli) -> Result<()> { + let program = Program::new(); + program.unregister() +} + +fn run_query(cli: Cli) -> Result<()> { + let program = Program::new(); + program.query() +} + +// endregion + +fn main() { + let cli = Cli::parse(); + + let rv = match &cli.command { + Commands::Register => run_register(cli), + Commands::Unregister => run_unregister(cli), + Commands::Query => run_query(cli), + }; + rv.unwrap_or_else(|e| { + eprintln!("Runtime error: {}.", e); + process::exit(1) + }); }