From ec5c78e8cefe9c4d76c31291ad2dc673a9a65d84 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Fri, 8 May 2026 14:08:51 +0800 Subject: [PATCH] feat: finish highlevel --- wfassoc/src/highlevel.rs | 138 ++++++++++++++++++++++++++++++++++----- 1 file changed, 121 insertions(+), 17 deletions(-) diff --git a/wfassoc/src/highlevel.rs b/wfassoc/src/highlevel.rs index b2a86f0..c6f1d3c 100644 --- a/wfassoc/src/highlevel.rs +++ b/wfassoc/src/highlevel.rs @@ -51,6 +51,8 @@ pub enum ParseProgramError { pub enum ProgramError { #[error("{0}")] Lowlevel(#[from] lowlevel::Error), + #[error("given index is invalid")] + BadIndex, } // endregion @@ -236,8 +238,11 @@ pub struct Program { icon: Option>, behavior: Option>, + #[allow(dead_code)] strs: Vec>, + #[allow(dead_code)] icons: Vec>, + #[allow(dead_code)] behaviors: Vec>, ext_keys: Vec, @@ -463,8 +468,8 @@ impl Program { // Create ProgId subkeys one by one debug_println!("Adding ProgId subkey..."); - for program_progid_key in &mut self.ext_keys { - let progid_key = &mut program_progid_key.progid_key; + for program_key in &mut self.ext_keys { + let progid_key = &mut program_key.progid_key; debug_println!( "Adding ProgId \"{0}\" subkey...", progid_key.inner().to_string() @@ -473,14 +478,14 @@ impl Program { // Create ProgId subkey progid_key.ensure(scope)?; // Write ProgId values - let name = Some(&program_progid_key.name.inner); + let name = Some(&program_key.name.inner); progid_key.set_default(scope, name)?; - progid_key.set_shell_verb(scope, &program_progid_key.behavior.inner)?; + progid_key.set_shell_verb(scope, &program_key.behavior.inner)?; progid_key.set_friendly_type_name(scope, name)?; - progid_key.set_default_icon(scope, Some(&program_progid_key.icon.inner))?; + progid_key.set_default_icon(scope, Some(&program_key.icon.inner))?; // Add this progid to file extension "open with" list. - let ext_key = &mut program_progid_key.ext_key; + let ext_key = &mut program_key.ext_key; ext_key.add_into_open_with_progids(scope, progid_key.inner())?; } @@ -505,8 +510,8 @@ impl Program { // Delete ProgId subkeys one by one. debug_println!("Adding ProgId subkey..."); - for program_progid_key in &mut self.ext_keys { - let progid_key = &mut program_progid_key.progid_key; + for program_key in &mut self.ext_keys { + let progid_key = &mut program_key.progid_key; debug_println!( "Deleting ProgId \"{0}\" subkey...", progid_key.inner().to_string() @@ -518,7 +523,7 @@ impl Program { // So we simply remove it from "open with" list. // Remove this ProgId from file extension "open with" list. - let ext_key = &mut program_progid_key.ext_key; + let ext_key = &mut program_key.ext_key; ext_key.remove_from_open_with_progids(scope, progid_key.inner())?; // Delete ProgId subkey @@ -551,8 +556,8 @@ impl Program { // Check ProgId subkey. debug_println!("Checking ProgId subkey..."); - for program_progid_key in &self.ext_keys { - let progid_key = &program_progid_key.progid_key; + for program_key in &self.ext_keys { + let progid_key = &program_key.progid_key; debug_println!( "Checking ProgId \"{0}\" subkey...", progid_key.inner().to_string() @@ -567,16 +572,115 @@ impl Program { Ok(true) } - pub fn link_ext(&self, scope: Scope, index: usize) -> Result<(), ProgramError> { - todo!() + pub fn link_ext(&mut self, scope: Scope, index: usize) -> Result<(), ProgramError> { + match self.ext_keys.get_mut(index) { + Some(program_key) => { + let ext_key = &mut program_key.ext_key; + let progid_key = &program_key.progid_key; + + // Before setting it, we must make sure this extension is existing + ext_key.ensure(scope)?; + ext_key.set_default(scope, Some(progid_key.inner()))?; + Ok(()) + } + None => Err(ProgramError::BadIndex), + } } - pub fn unlink_ext(&self, scope: Scope, index: usize) -> Result<(), ProgramError> { - todo!() + pub fn unlink_ext(&mut self, scope: Scope, index: usize) -> Result<(), ProgramError> { + match self.ext_keys.get_mut(index) { + Some(program_key) => { + let ext_key = &mut program_key.ext_key; + + // Before setting it, we must make sure this extension is existing + ext_key.ensure(scope)?; + ext_key.set_default(scope, None)?; + Ok(()) + } + None => Err(ProgramError::BadIndex), + } } - pub fn ext_status(&self, view: View, index: usize) -> Result<(), ProgramError> { - todo!() + pub fn ext_status( + &self, + view: View, + index: usize, + ) -> Result, ProgramError> { + match self.ext_keys.get(index) { + Some(program_key) => { + let ext_key = &program_key.ext_key; + + // If there is no such extension key, return None about this extension. + if !ext_key.is_exist(view)? { + return Ok(None); + } + // Let we fetch its associated default ProgId. + // If there is no such key, return None instead. + let progid = match ext_key.get_default(view)? { + Some(progid) => progid, + None => return Ok(None), + }; + // Now we build ProgId key from gotten association + let progid_key = lowlevel::ProgIdKey::new(progid); + // If this associated ProgId key is not presented, + // we return None instead. + if !progid_key.is_exist(view)? { + return Ok(None); + } + // Now try fetch its diaplay name in modern way first. + // If there is no modern way, use legacy way instead. + // If there is still no display name, use ProgId self instead as display name. + let name = match progid_key.get_friendly_type_name(view)? { + Some(name) => name.extract()?, + None => match progid_key.get_default(view)? { + Some(name) => name.extract()?, + None => progid_key.inner().to_string(), + }, + }; + // Now try to fetch icon. + let icon = progid_key + .get_default_icon(view)? + .map(|ico| ico.extract(concept::IconSizeKind::Small)) + .transpose()?; + + // Okey, return it. + Ok(Some(ProgramExtStatus::new(name, icon))) + } + None => Err(ProgramError::BadIndex), + } + } +} + +// endregion + +// region: Program Exposed Structs + +/// Exposed struct representing the default associated program of specific file extension. +/// +/// The data including the diaplay name and icon. +pub struct ProgramExtStatus { + name: String, + icon: Option, +} + +impl ProgramExtStatus { + fn new(name: String, icon: Option) -> Self { + Self { name, icon } + } + + /// Get the display name of this program. + /// + /// The program provided display name will be used firstly. + /// If this program has no display name, the stringified ProgId will be used instead. + pub fn get_name(&self) -> &str { + self.name.as_str() + } + + /// Get the icon of this program. + /// + /// Due to the icon is optional, if there is no icon, return None. + pub fn get_icon(&self) -> Option<&concept::IconRc> { + self.icon.as_ref() } }