1
0

feat: update highlevel parse

This commit is contained in:
2026-05-07 13:21:35 +08:00
parent 3edb08efc7
commit fe81541eeb

View File

@@ -1,8 +1,8 @@
use crate::{lowlevel, utilities, win32}; use crate::{lowlevel, utilities, win32::concept};
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::rc::Rc;
use std::path::Path; use std::path::Path;
use std::rc::Rc;
use thiserror::Error as TeError; use thiserror::Error as TeError;
pub use lowlevel::{Scope, View}; pub use lowlevel::{Scope, View};
@@ -20,13 +20,17 @@ pub enum SchemaError {
#[derive(Debug, TeError)] #[derive(Debug, TeError)]
pub enum ParseProgramError { pub enum ParseProgramError {
#[error("{0}")] #[error("{0}")]
BadFileName(#[from] win32::concept::BadFileNameError), BadFileName(#[from] concept::BadFileNameError),
#[error("{0}")]
ParseCmdLine(#[from] concept::ParseCmdLineError),
#[error("{0}")] #[error("{0}")]
CastOsStr(#[from] utilities::CastOsStrError), CastOsStr(#[from] utilities::CastOsStrError),
#[error("given path doesn't has legal file name part")] #[error("given path doesn't has legal file name part")]
NoFileNamePart, NoFileNamePart,
#[error("given path doesn't has legal directory part")] #[error("given path doesn't has legal directory part")]
NoDirNamePart, NoDirNamePart,
#[error("given identifier is not presented in dict")]
NoSuchIdentifier,
} }
/// Error occurs when operating with `Program`. /// Error occurs when operating with `Program`.
@@ -177,9 +181,9 @@ pub struct Program {
applications_key: lowlevel::ApplicationsKey, applications_key: lowlevel::ApplicationsKey,
file_name: String, file_name: String,
dir_name: String, dir_name: String,
name: Rc<ProgramStr>, name: Option<Rc<ProgramStr>>,
icon: Rc<ProgramIcon>, icon: Option<Rc<ProgramIcon>>,
behavior: Rc<ProgramBehavior>, behavior: Option<Rc<ProgramBehavior>>,
strs: Vec<Rc<ProgramStr>>, strs: Vec<Rc<ProgramStr>>,
icons: Vec<Rc<ProgramIcon>>, icons: Vec<Rc<ProgramIcon>>,
@@ -215,6 +219,36 @@ impl Program {
.ok_or(ParseProgramError::NoDirNamePart) .ok_or(ParseProgramError::NoDirNamePart)
} }
fn flat_hashmap<V, U, F>(
hashmap: &HashMap<String, V>,
f: F,
) -> Result<(Vec<U>, HashMap<String, usize>), ParseProgramError>
where
F: Fn(&V) -> Result<U, ParseProgramError>,
{
let mut indexmap: HashMap<String, usize> = HashMap::with_capacity(hashmap.len());
let mut vector: Vec<U> = Vec::with_capacity(hashmap.len());
for (key, value) in hashmap.into_iter() {
indexmap.insert(key.clone(), vector.len());
vector.push(f(value)?);
}
Ok((vector, indexmap))
}
fn resolve_index<T>(
key: &String,
vector: &Vec<Rc<T>>,
index_map: &HashMap<String, usize>,
) -> Result<Rc<T>, ParseProgramError> {
match index_map.get(key) {
Some(index) => match vector.get(*index) {
Some(value) => Ok(value.clone()),
None => Err(ParseProgramError::NoSuchIdentifier),
},
None => Err(ParseProgramError::NoSuchIdentifier),
}
}
/// Try creating Program from Schema. /// Try creating Program from Schema.
pub fn new(schema: Schema) -> Result<Self, ParseProgramError> { pub fn new(schema: Schema) -> Result<Self, ParseProgramError> {
// Extract file name part and directory name part respectively. // Extract file name part and directory name part respectively.
@@ -224,10 +258,52 @@ impl Program {
let dir_name = Self::extract_dir_name(schema_path)?; let dir_name = Self::extract_dir_name(schema_path)?;
let dir_name = String::from(utilities::osstr_to_str(dir_name)?); let dir_name = String::from(utilities::osstr_to_str(dir_name)?);
// Build app paths key and applications key respectively // Build app paths key and applications key respectively
let key = win32::concept::FileName::new(&file_name)?; let key = concept::FileName::new(&file_name)?;
let app_paths_key = lowlevel::AppPathsKey::new(key.clone()); let app_paths_key = lowlevel::AppPathsKey::new(key.clone());
let applications_key = lowlevel::ApplicationsKey::new(key.clone()); let applications_key = lowlevel::ApplicationsKey::new(key.clone());
// Build string, icon and behavior list,
// and build mapper at the same time.
let (strs, strs_index_map) = Self::flat_hashmap(&schema.strs, |entry| {
let str_res_variant: lowlevel::StrResVariant = entry.as_str().into();
let program_str = ProgramStr {
inner: str_res_variant,
};
Ok(Rc::new(program_str))
})?;
let (icons, icons_index_map) = Self::flat_hashmap(&schema.icons, |entry| {
let icon_res_variant: lowlevel::IconResVariant = entry.as_str().into();
let program_icon = ProgramIcon {
inner: icon_res_variant,
};
Ok(Rc::new(program_icon))
})?;
let (behaviors, behaviors_index_map) = Self::flat_hashmap(&schema.behaviors, |entry| {
// We simply always use "Open" verb.
let cmdline: concept::CmdLine = entry.as_str().parse()?;
let verb = concept::Verb::OPEN.clone();
let shell_verb = lowlevel::ShellVerb::new(verb, cmdline);
let program_behavior = ProgramBehavior { inner: shell_verb };
Ok(Rc::new(program_behavior))
})?;
// Setup default name, icon and behavior
let name = schema
.name
.map(|name| Self::resolve_index(&name, &strs, &strs_index_map))
.transpose()?;
let icon = schema
.icon
.map(|icon| Self::resolve_index(&icon, &icons, &icons_index_map))
.transpose()?;
let behavior = schema
.behavior
.map(|behavior| Self::resolve_index(&behavior, &behaviors, &behaviors_index_map))
.transpose()?;
// Process file extensions.
// We need create ProgIds list and Exts list at the same time.
todo!(); todo!();
// Ok(Self { // Ok(Self {
// app_paths_key, // app_paths_key,
@@ -296,7 +372,7 @@ struct ProgramIcon {
/// Internal used enum presenting a Program behavior (command line setups). /// Internal used enum presenting a Program behavior (command line setups).
#[derive(Debug)] #[derive(Debug)]
struct ProgramBehavior { struct ProgramBehavior {
inner: win32::concept::CmdLine, inner: lowlevel::ShellVerb,
} }
/// Internal used struct presenting a Program ProgId. /// Internal used struct presenting a Program ProgId.
@@ -312,7 +388,7 @@ struct ProgramProgIdKey {
#[derive(Debug)] #[derive(Debug)]
struct ProgramExtKey { struct ProgramExtKey {
key: lowlevel::ExtKey, key: lowlevel::ExtKey,
assoc: Rc<ProgramProgIdKey> assoc: Rc<ProgramProgIdKey>,
} }
// endregion // endregion