diff --git a/wfassoc/src/highlevel/program.rs b/wfassoc/src/highlevel/program.rs index 293844f..0682ecf 100644 --- a/wfassoc/src/highlevel/program.rs +++ b/wfassoc/src/highlevel/program.rs @@ -24,6 +24,8 @@ pub enum ParseProgramError { #[error("parsing into Program error: {0}")] BadFileName(#[from] concept::BadFileNameError), #[error("parsing into Program error: {0}")] + ParseClsid(#[from] concept::ParseClsidError), + #[error("parsing into Program error: {0}")] ParseCmdLine(#[from] concept::ParseCmdLineError), #[error("parsing into Program error: {0}")] CastOsStr(#[from] utilities::CastOsStrError), @@ -61,6 +63,11 @@ pub struct Program { app_path: String, app_file_name: String, app_dir_path: String, + + // TODO: Remove this dead_code attribute once we start to use CLSID. + #[allow(dead_code)] + clsid: concept::Clsid, + name: Option>, icon: Option>, behavior: Option>, @@ -102,6 +109,8 @@ impl Program { .ok_or(ParseProgramError::NoDirNamePart) } + /// Flatten a `HashMap` into a `Vec` with a reverse index map, + /// by applying the given transformation function `f` to each value. fn flat_hashmap( hashmap: &HashMap, f: F, @@ -118,6 +127,8 @@ impl Program { Ok((vector, indexmap)) } + /// Resolve a key string to an `Arc` by looking it up in the index map, + /// then indexing into the vector. fn resolve_index( key: &str, vector: &Vec>, @@ -175,6 +186,9 @@ impl Program { let app_paths_key = lowlevel::AppPathsKey::new(key.clone()); let applications_key = lowlevel::ApplicationsKey::new(key.clone()); + // Parse CLSID + let clsid = schema.get_clsid().parse::()?; + // Build string, icon and behavior list, // and build mapper at the same time. let (strs, strs_index_map) = Self::flat_hashmap(schema.get_strs(), |entry| { @@ -259,6 +273,7 @@ impl Program { app_path, app_file_name, app_dir_path, + clsid, name, icon, behavior, @@ -272,6 +287,10 @@ impl Program { } impl Program { + /// Resolve the display name of this application. + /// + /// Returns the user-specified display name first. + /// Falls back to the executable file name if no display name is configured. pub fn resolve_name(&self) -> Result { // Fecch from user specified name first let name = self @@ -290,6 +309,10 @@ impl Program { Ok(self.app_file_name.clone()) } + /// Resolve the icon of this application. + /// + /// Returns the user-specified icon first, then falls back to the first icon from the executable, + /// and finally to the system default executable icon. pub fn resolve_icon(&self) -> Result { // Fetch from user specified icon first let icon = self @@ -311,14 +334,23 @@ impl Program { )?) } + /// Return the number of file extensions associated with this program. pub fn exts_len(&self) -> usize { self.ext_keys.len() } + /// Find the index of a file extension by its body (without leading dot). + /// + /// Returns `None` if the given extension is not associated with this program. pub fn find_ext(&self, body: &str) -> Option { self.ext_keys_map.get(body).copied() } + /// Resolve the extension status for the extension at the given index. + /// This status including the ProgId associated with this file extension, + /// and the display name and icon for this file extension. + /// + /// Returns the fetched status, or the error occurs when fetching. pub fn resolve_ext(&self, index: usize) -> Result { // Fetch data let progid_ext_key = self @@ -461,8 +493,7 @@ impl Program { /// Check whether this application has been registered in given view. /// /// Please note that this is a rough check and do not validate any data. - /// - /// The return value only ensures the pre-requirement of `register` and `unregister`. + /// The return value only ensures the pre-requirements of [Self::register] and [Self::unregister]. pub fn is_registered(&self, scope: Scope) -> Result { // Check App Paths subkey. debug_println!("Checking App Paths subkey..."); @@ -494,6 +525,7 @@ impl Program { Ok(true) } + /// Set this program as the default handler for the file extension at the given index. pub fn link_ext(&mut self, scope: Scope, index: usize) -> Result<(), ProgramError> { match self.ext_keys.get_mut(index) { Some(program_key) => { @@ -518,6 +550,7 @@ impl Program { Ok(()) } + /// Remove this program as the default handler for the file extension at the given index. pub fn unlink_ext(&mut self, scope: Scope, index: usize) -> Result<(), ProgramError> { match self.ext_keys.get_mut(index) { Some(program_key) => { @@ -540,6 +573,10 @@ impl Program { Ok(()) } + /// Query the current default association for the file extension at the given index. + /// + /// Returns `Ok(None)` if the extension is not associated with any program, + /// or if the associated program's registration data is missing. pub fn query_ext( &self, view: View, @@ -655,6 +692,7 @@ pub struct ProgramSelfExtStatus { } impl ProgramSelfExtStatus { + /// Create a new `ProgramSelfExtStatus`. fn new(ext: concept::Ext, name: String, icon: concept::IconRc) -> Self { Self { ext, name, icon } } @@ -695,6 +733,7 @@ pub struct ProgramExtStatus { } impl ProgramExtStatus { + /// Create a new `ProgramExtStatus`. fn new(name: String, icon: concept::IconRc) -> Self { Self { name, icon } } diff --git a/wfassoc/src/highlevel/schema.rs b/wfassoc/src/highlevel/schema.rs index f389ddb..c2bf4ea 100644 --- a/wfassoc/src/highlevel/schema.rs +++ b/wfassoc/src/highlevel/schema.rs @@ -38,6 +38,7 @@ pub struct Schema { } impl Schema { + /// Create an empty `Schema` with all fields set to their defaults. pub fn new() -> Self { Self { identifier: String::new(), @@ -76,22 +77,40 @@ impl Schema { self.path = exe_path.to_string(); } + /// Set the CLSID (Class Identifier) of the application. + /// + /// # Todo + /// + /// Currently this field is not used by this crate, + /// but you still need to fill it with a legal CLSID for future expanding. pub fn set_clsid(&mut self, clsid: &str) -> () { self.clsid = clsid.to_string(); } + /// Set the key referencing a named string resource for the application display name. + /// + /// This field is optional and can pass `None` to clear it. pub fn set_name(&mut self, name: Option<&str>) -> () { self.name = name.map(|n| n.to_string()); } + /// Set the key referencing a named icon resource for the application default icon. + /// + /// This field is optional and can pass `None` to clear it. pub fn set_icon(&mut self, icon: Option<&str>) -> () { self.icon = icon.map(|i| i.to_string()); } + /// Set the key referencing a named behavior resource for the application default execution behavior. + /// + /// This field is optional and can pass `None` to clear it. pub fn set_behavior(&mut self, behavior: Option<&str>) -> () { self.behavior = behavior.map(|b| b.to_string()); } + /// Add a named string resource entry. + /// + /// Returns error if the name already exists. pub fn add_str(&mut self, name: &str, value: &str) -> Result<(), SchemaError> { match self.strs.insert(name.to_string(), value.to_string()) { Some(_) => Err(SchemaError::DuplicateKey(name.to_string())), @@ -99,6 +118,9 @@ impl Schema { } } + /// Add a named icon resource entry. + /// + /// Returns error if the name already exists. pub fn add_icon(&mut self, name: &str, value: &str) -> Result<(), SchemaError> { match self.icons.insert(name.to_string(), value.to_string()) { Some(_) => Err(SchemaError::DuplicateKey(name.to_string())), @@ -106,6 +128,9 @@ impl Schema { } } + /// Add a named behavior (command line) entry. + /// + /// Returns error if the name already exists. pub fn add_behavior(&mut self, name: &str, value: &str) -> Result<(), SchemaError> { match self.behaviors.insert(name.to_string(), value.to_string()) { Some(_) => Err(SchemaError::DuplicateKey(name.to_string())), @@ -116,6 +141,8 @@ impl Schema { /// Add a file extension to the schema. /// /// The parameter `ext` is the file extension without leading dot `.`. + /// And the parameter `ext_name`, `ext_icon` and `ext_behavior` are the key + /// referencing a named string resource, icon resource and behavior resource respectively. pub fn add_ext( &mut self, ext: &str, @@ -135,42 +162,55 @@ impl Schema { } impl Schema { + /// Get the identifier of the schema. pub(super) fn get_identifier(&self) -> &str { &self.identifier } + /// Get the absolute path to the executable file. pub(super) fn get_path(&self) -> &str { &self.path } + /// Get the CLSID (Class Identifier) of the application. pub(super) fn get_clsid(&self) -> &str { &self.clsid } + /// Get the key referencing the named string resource for the display name. + /// Return `None` if user doesn't specify this. pub(super) fn get_name(&self) -> Option<&str> { self.name.as_ref().map(|v| v.as_str()) } + /// Get the key referencing the named icon resource for the default icon. + /// Return `None` if user doesn't specify this. pub(super) fn get_icon(&self) -> Option<&str> { self.icon.as_ref().map(|v| v.as_str()) } + /// Get the key referencing the named behavior resource for the default verb. + /// Return `None` if user doesn't specify this. pub(super) fn get_behavior(&self) -> Option<&str> { self.behavior.as_ref().map(|v| v.as_str()) } + /// Get a reference to the string resources map. pub(super) fn get_strs(&self) -> &HashMap { &self.strs } + /// Get a reference to the icon resources map. pub(super) fn get_icons(&self) -> &HashMap { &self.icons } + /// Get a reference to the behavior resources map. pub(super) fn get_behaviors(&self) -> &HashMap { &self.behaviors } + /// Get a reference to the file extensions map. pub(super) fn get_exts(&self) -> &HashMap { &self.exts } @@ -189,6 +229,7 @@ pub(crate) struct SchemaExt { } impl SchemaExt { + /// Create a new `SchemaExt` with the given name, icon key and behavior key. fn new(name: &str, icon: &str, behavior: &str) -> Self { Self { name: name.to_string(), @@ -199,14 +240,17 @@ impl SchemaExt { } impl SchemaExt { + /// Get the key referencing the named string resource for display name. pub(super) fn get_name(&self) -> &str { &self.name } + /// Get the key referencing the named icon resource for file icon. pub(super) fn get_icon(&self) -> &str { &self.icon } + /// Get the key referencing the named behavior resource. pub(super) fn get_behavior(&self) -> &str { &self.behavior } diff --git a/wfassoc/src/win32/concept.rs b/wfassoc/src/win32/concept.rs index 6ddba0c..00a12d4 100644 --- a/wfassoc/src/win32/concept.rs +++ b/wfassoc/src/win32/concept.rs @@ -294,7 +294,7 @@ impl Clsid { /// The error occurs when parsing CLSID. #[derive(Debug, TeError)] -#[error("given string \"{inner}\" is invalid for uuid")] +#[error("given string \"{inner}\" is invalid for CLSID")] pub struct ParseClsidError { /// The clone of string which is not a valid CLSID. inner: String,