feat: upgrade wfassoc_exec
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -762,7 +762,7 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wfassoc_dylib"
|
name = "wfassoc_cdylib"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cbindgen",
|
"cbindgen",
|
||||||
@@ -779,7 +779,6 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"toml 0.9.8",
|
"toml 0.9.8",
|
||||||
"wfassoc",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
members = ["wfassoc", "wfassoc_dylib", "wfassoc_exec"]
|
members = ["wfassoc", "wfassoc_cdylib", "wfassoc_exec"]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wfassoc_dylib"
|
name = "wfassoc_cdylib"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["yyc12345"]
|
authors = ["yyc12345"]
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
@@ -8,7 +8,7 @@ license = "SPDX:MIT"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
wfassoc = { path="../wfassoc" }
|
#wfassoc = { path="../wfassoc" }
|
||||||
clap = { version="4.5.48", features=["derive"]}
|
clap = { version="4.5.48", features=["derive"]}
|
||||||
serde = { version = "1.0.228", features=["derive"]}
|
serde = { version = "1.0.228", features=["derive"]}
|
||||||
toml = "0.9.8"
|
toml = "0.9.8"
|
||||||
|
|||||||
@@ -1,48 +1,39 @@
|
|||||||
use clap::{Parser, Subcommand, ValueEnum};
|
use clap::{Parser, Subcommand, ValueEnum};
|
||||||
use wfassoc::Scope;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, ValueEnum)]
|
// region: Clap Declaration
|
||||||
pub enum Target {
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, ValueEnum)]
|
||||||
|
enum Target {
|
||||||
#[value(name = "user")]
|
#[value(name = "user")]
|
||||||
User,
|
User,
|
||||||
#[value(name = "system")]
|
#[value(name = "system")]
|
||||||
System,
|
System,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Target> for Scope {
|
|
||||||
fn from(target: Target) -> Self {
|
|
||||||
match target {
|
|
||||||
Target::User => Scope::User,
|
|
||||||
Target::System => Scope::System,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Simple program to manage Windows file associations
|
/// Simple program to manage Windows file associations
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "Windows File Association Operator", version, about)]
|
#[command(name = "Windows File Association Operator", version, about)]
|
||||||
pub struct Cli {
|
struct Cli {
|
||||||
/// The TOML file representing the complete program
|
/// The TOML manifest file representing the complete program
|
||||||
#[arg(
|
#[arg(
|
||||||
short = 'c',
|
short = 'm',
|
||||||
long = "config",
|
long = "manifest",
|
||||||
value_name = "PROG_CONFIG",
|
value_name = "PROG_MANIFEST",
|
||||||
required = true
|
required = true
|
||||||
)]
|
)]
|
||||||
pub(crate) config_file: String,
|
manifest_file: String,
|
||||||
|
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
pub(crate) command: Commands,
|
command: CliCommands,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub enum Commands {
|
enum CliCommands {
|
||||||
/// Register the program
|
/// Register the program
|
||||||
#[command(name = "register")]
|
#[command(name = "register")]
|
||||||
#[command(about = "Register application with given manifest and scope.")]
|
#[command(about = "Register application with given manifest and scope.")]
|
||||||
Register {
|
Register {
|
||||||
/// The scope where wfassoc operate
|
/// The scope where wfassoc operate
|
||||||
#[arg(short = 't', long = "target", value_name = "TARGET", value_enum, default_value_t = Target::User)]
|
#[arg(short = 't', long = "target", value_name = "TARGET", required = true, value_enum, default_value_t = Target::User)]
|
||||||
target: Target,
|
target: Target,
|
||||||
},
|
},
|
||||||
/// Unregister the program
|
/// Unregister the program
|
||||||
@@ -50,11 +41,76 @@ pub enum Commands {
|
|||||||
#[command(about = "Unregister application with given manifest and scope.")]
|
#[command(about = "Unregister application with given manifest and scope.")]
|
||||||
Unregister {
|
Unregister {
|
||||||
/// The scope where wfassoc operate
|
/// The scope where wfassoc operate
|
||||||
#[arg(short = 't', long = "target", value_name = "TARGET", value_enum, default_value_t = Target::User)]
|
#[arg(short = 't', long = "target", value_name = "TARGET", required = true, value_enum, default_value_t = Target::User)]
|
||||||
target: Target,
|
target: Target,
|
||||||
},
|
},
|
||||||
/// Query file associations
|
/// Fetch current registration status
|
||||||
#[command(name = "query")]
|
#[command(name = "status")]
|
||||||
#[command(about = "Query file extensions association infos according toh given manifest represented application.")]
|
#[command(
|
||||||
Query,
|
about = "Fetch the status of registration for given manifest represented application."
|
||||||
|
)]
|
||||||
|
Status,
|
||||||
|
#[command(name = "ext")]
|
||||||
|
#[command(about = "File extension related operations according to given program manifest.")]
|
||||||
|
Ext {
|
||||||
|
#[command(subcommand)]
|
||||||
|
command: CliExtCommands,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
enum CliExtCommands {
|
||||||
|
#[command(name = "link")]
|
||||||
|
#[command(about = "Link user given file extension to the program declared in manifest file.")]
|
||||||
|
Link {
|
||||||
|
// The file extensions used for this operation. Specify * for all file extension.
|
||||||
|
#[arg(required = true, value_name = "EXTS", num_args = 1..)]
|
||||||
|
exts: Vec<String>,
|
||||||
|
},
|
||||||
|
#[command(name = "unlink")]
|
||||||
|
#[command(
|
||||||
|
about = "Unlink user given file extension from the program declared in manifest file."
|
||||||
|
)]
|
||||||
|
Unlink {
|
||||||
|
// The file extensions used for this operation. Specify * for all file extension.
|
||||||
|
#[arg(required = true, value_name = "EXTS", num_args = 1..)]
|
||||||
|
exts: Vec<String>,
|
||||||
|
},
|
||||||
|
#[command(name = "list")]
|
||||||
|
#[command(
|
||||||
|
about = "List the association status for all extensions declared in given program manifest."
|
||||||
|
)]
|
||||||
|
List,
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region: Exposed Type
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Request {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RequestCommand {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RequestExtCommand {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// Please note that if there is "help" or "version" command matched,
|
||||||
|
/// or any command line parse error occurs,
|
||||||
|
/// this function will order program exit immediately.
|
||||||
|
/// This is the mechanism of clap crate.
|
||||||
|
pub fn parse() -> Request {
|
||||||
|
let cli = Cli::parse();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,161 +1,33 @@
|
|||||||
pub(crate) mod cli;
|
|
||||||
pub(crate) mod manifest;
|
pub(crate) mod manifest;
|
||||||
|
pub(crate) mod cli;
|
||||||
|
pub(crate) mod runner;
|
||||||
|
|
||||||
use clap::Parser;
|
use std::path::Path;
|
||||||
use cli::{Cli, Commands, Target};
|
|
||||||
use comfy_table::Table;
|
|
||||||
use manifest::Manifest;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::process;
|
use std::process;
|
||||||
use thiserror::Error as TeError;
|
use thiserror::Error as TeError;
|
||||||
use wfassoc::{Program, Scope, Token, View};
|
|
||||||
|
|
||||||
// region: Basic Types
|
|
||||||
|
|
||||||
/// All errors occurs in this executable.
|
/// All errors occurs in this executable.
|
||||||
#[derive(TeError, Debug)]
|
#[derive(TeError, Debug)]
|
||||||
enum Error {
|
enum Error {
|
||||||
/// Error from wfassoc core.
|
|
||||||
#[error("{0}")]
|
|
||||||
Core(#[from] wfassoc::Error),
|
|
||||||
/// Error when parsing manifest TOML file.
|
/// Error when parsing manifest TOML file.
|
||||||
#[error("invalid manifest file: {0}")]
|
#[error("{0}")]
|
||||||
Manifest(#[from] manifest::Error),
|
Manifest(#[from] manifest::Error),
|
||||||
|
|
||||||
/// Error when specifying invalid manner name for extension.
|
|
||||||
#[error("extension {ext} associated manner {manner} is invalid in manifest file")]
|
|
||||||
InvalidMannerName { manner: String, ext: String },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Result type used in this executable.
|
/// Result type used in this executable.
|
||||||
type Result<T> = std::result::Result<T, Error>;
|
type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
// endregion
|
fn runner() -> Result<()> {
|
||||||
|
let raw_mf = manifest::RawManifest::from_file(Path::new(r#"D:\Repo\wfassoc\example\ppic.toml"#))?;
|
||||||
// region: Correponding Runner
|
//let mf = raw_mf.to_checked()?;
|
||||||
|
println!("{:?}", raw_mf);
|
||||||
struct Composition {
|
|
||||||
program: Program,
|
|
||||||
ext_tokens: Vec<Token>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Composition {
|
|
||||||
pub fn new(cli: &Cli) -> Result<Composition> {
|
|
||||||
// Open file and read manifest TOML file
|
|
||||||
let mf = Manifest::from_file(&cli.config_file)?;
|
|
||||||
// Create instance
|
|
||||||
let mut program = Program::new(&mf.identifier, &cli.config_file)?;
|
|
||||||
// Setup manner
|
|
||||||
let mut manner_token_map: HashMap<&str, Token> = HashMap::new();
|
|
||||||
for (k, v) in mf.manners.iter() {
|
|
||||||
let token = program.add_manner(v.as_str())?;
|
|
||||||
manner_token_map.insert(k.as_str(), token);
|
|
||||||
}
|
|
||||||
// Setup extension
|
|
||||||
let mut ext_tokens = Vec::new();
|
|
||||||
for (k, v) in mf.exts.iter() {
|
|
||||||
let token = match manner_token_map.get(v.as_str()) {
|
|
||||||
Some(v) => v,
|
|
||||||
None => {
|
|
||||||
return Err(Error::InvalidMannerName {
|
|
||||||
manner: v.to_string(),
|
|
||||||
ext: k.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let token = program.add_ext(k.as_str(), *token)?;
|
|
||||||
ext_tokens.push(token);
|
|
||||||
}
|
|
||||||
// Okey
|
|
||||||
Ok(Self {
|
|
||||||
program,
|
|
||||||
ext_tokens,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_program(&self) -> &Program {
|
|
||||||
&self.program
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter_ext_tokens(&self) -> impl Iterator<Item = Token> {
|
|
||||||
self.ext_tokens.iter().copied()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_register(cli: &Cli, target: &Target) -> Result<()> {
|
|
||||||
let composition = Composition::new(cli)?;
|
|
||||||
let scope = target.clone().into();
|
|
||||||
|
|
||||||
// Register program
|
|
||||||
let program = composition.get_program();
|
|
||||||
program.register(scope)?;
|
|
||||||
// Link all file extensions
|
|
||||||
for token in composition.iter_ext_tokens() {
|
|
||||||
program.link_ext(token, scope)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Register OK.");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_unregister(cli: &Cli, target: &Target) -> Result<()> {
|
|
||||||
let composition = Composition::new(cli)?;
|
|
||||||
let scope = target.clone().into();
|
|
||||||
|
|
||||||
// Unlink all file extensions
|
|
||||||
let program = composition.get_program();
|
|
||||||
for token in composition.iter_ext_tokens() {
|
|
||||||
program.unlink_ext(token, scope)?;
|
|
||||||
}
|
|
||||||
// Unregister prorgam
|
|
||||||
program.unregister(scope)?;
|
|
||||||
|
|
||||||
println!("Unregister OK.");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_query(cli: &Cli) -> Result<()> {
|
|
||||||
let composition = Composition::new(cli)?;
|
|
||||||
|
|
||||||
// Show file association
|
|
||||||
let mut table = Table::new();
|
|
||||||
table.set_header(["Extension", "Hybrid", "User", "System"]);
|
|
||||||
|
|
||||||
let program = composition.get_program();
|
|
||||||
for token in composition.iter_ext_tokens() {
|
|
||||||
let cell_ext = program.get_ext_str(token).unwrap();
|
|
||||||
let cell_hybrid = program
|
|
||||||
.query_ext(token, View::Hybrid)?
|
|
||||||
.map(|pi| pi.to_string())
|
|
||||||
.unwrap_or_default();
|
|
||||||
let cell_user = program
|
|
||||||
.query_ext(token, View::User)?
|
|
||||||
.map(|pi| pi.to_string())
|
|
||||||
.unwrap_or_default();
|
|
||||||
let cell_system = program
|
|
||||||
.query_ext(token, View::System)?
|
|
||||||
.map(|pi| pi.to_string())
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
table.add_row([cell_ext, cell_hybrid, cell_user, cell_system]);
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{table}");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let cli = Cli::parse();
|
let cli = cli::parse();
|
||||||
|
|
||||||
let rv = match &cli.command {
|
runner().unwrap_or_else(|e| {
|
||||||
Commands::Register { target } => run_register(&cli, target),
|
|
||||||
Commands::Unregister { target } => run_unregister(&cli, target),
|
|
||||||
Commands::Query => run_query(&cli),
|
|
||||||
};
|
|
||||||
rv.unwrap_or_else(|e| {
|
|
||||||
eprintln!("Runtime error: {}.", e);
|
eprintln!("Runtime error: {}.", e);
|
||||||
process::exit(1)
|
process::exit(1)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,30 +1,90 @@
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::path::Path;
|
||||||
use thiserror::Error as TeError;
|
use thiserror::Error as TeError;
|
||||||
use toml;
|
use toml;
|
||||||
|
|
||||||
|
/// Error occurs in this module.
|
||||||
#[derive(Debug, TeError)]
|
#[derive(Debug, TeError)]
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
/// Io error
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
/// Toml deserialization error
|
||||||
Toml(#[from] toml::de::Error),
|
Toml(#[from] toml::de::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
/// Result type used in this module.
|
||||||
|
type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
// region: Raw Manifest
|
||||||
|
|
||||||
|
/// Raw user input manifest.
|
||||||
|
///
|
||||||
|
/// This manifest is the raw input of user.
|
||||||
|
/// Some fields may not be checked due to user invalid input.
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Manifest {
|
pub struct RawManifest {
|
||||||
pub(crate) identifier: String,
|
identifier: String,
|
||||||
pub(crate) path: String,
|
path: String,
|
||||||
pub(crate) clsid: String,
|
clsid: String,
|
||||||
pub(crate) manners: HashMap<String, String>,
|
icons: HashMap<String, String>,
|
||||||
pub(crate) exts: HashMap<String, String>,
|
behaviors: HashMap<String, String>,
|
||||||
|
exts: HashMap<String, RawManifestExt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manifest {
|
impl RawManifest {
|
||||||
pub fn from_file(path: &str) -> Result<Manifest> {
|
pub fn into_checked(&self) -> Result<Manifest> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The sub-type in raw user input manifest.
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct RawManifestExt {
|
||||||
|
name: String,
|
||||||
|
icon: String,
|
||||||
|
behavior: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawManifestExt {
|
||||||
|
pub fn into_checked(&self) -> Result<ManifestExt> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawManifest {
|
||||||
|
/// Read raw user manifest.
|
||||||
|
pub fn from_file(path: &Path) -> Result<RawManifest> {
|
||||||
let contents = std::fs::read_to_string(path)?;
|
let contents = std::fs::read_to_string(path)?;
|
||||||
let config: Manifest = toml::from_str(&contents)?;
|
let config: RawManifest = toml::from_str(&contents)?;
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region: Checked Manifest
|
||||||
|
|
||||||
|
/// Converted user input manifest.
|
||||||
|
///
|
||||||
|
/// This manifest struct is prepared for final use.
|
||||||
|
/// All fields loacted in this struct is checked and ready to be used.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Manifest {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Manifest {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ManifestExt {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ManifestExt {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|||||||
162
wfassoc_exec/src/old_main.rs
Normal file
162
wfassoc_exec/src/old_main.rs
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
pub(crate) mod cli;
|
||||||
|
pub(crate) mod manifest;
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use cli::{Cli, Commands, Target};
|
||||||
|
use comfy_table::Table;
|
||||||
|
use manifest::Manifest;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::process;
|
||||||
|
use thiserror::Error as TeError;
|
||||||
|
use wfassoc::{Program, Scope, Token, View};
|
||||||
|
|
||||||
|
// region: Basic Types
|
||||||
|
|
||||||
|
/// All errors occurs in this executable.
|
||||||
|
#[derive(TeError, Debug)]
|
||||||
|
enum Error {
|
||||||
|
/// Error from wfassoc core.
|
||||||
|
#[error("{0}")]
|
||||||
|
Core(#[from] wfassoc::Error),
|
||||||
|
/// Error when parsing manifest TOML file.
|
||||||
|
#[error("invalid manifest file: {0}")]
|
||||||
|
Manifest(#[from] manifest::Error),
|
||||||
|
|
||||||
|
/// Error when specifying invalid manner name for extension.
|
||||||
|
#[error("extension {ext} associated manner {manner} is invalid in manifest file")]
|
||||||
|
InvalidMannerName { manner: String, ext: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Result type used in this executable.
|
||||||
|
type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region: Correponding Runner
|
||||||
|
|
||||||
|
struct Composition {
|
||||||
|
program: Program,
|
||||||
|
ext_tokens: Vec<Token>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Composition {
|
||||||
|
pub fn new(cli: &Cli) -> Result<Composition> {
|
||||||
|
// Open file and read manifest TOML file
|
||||||
|
let mf = Manifest::from_file(&cli.config_file)?;
|
||||||
|
// Create instance
|
||||||
|
let mut program = Program::new(&mf.identifier, &cli.config_file)?;
|
||||||
|
// Setup manner
|
||||||
|
let mut manner_token_map: HashMap<&str, Token> = HashMap::new();
|
||||||
|
for (k, v) in mf.manners.iter() {
|
||||||
|
let token = program.add_manner(v.as_str())?;
|
||||||
|
manner_token_map.insert(k.as_str(), token);
|
||||||
|
}
|
||||||
|
// Setup extension
|
||||||
|
let mut ext_tokens = Vec::new();
|
||||||
|
for (k, v) in mf.exts.iter() {
|
||||||
|
let token = match manner_token_map.get(v.as_str()) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
return Err(Error::InvalidMannerName {
|
||||||
|
manner: v.to_string(),
|
||||||
|
ext: k.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let token = program.add_ext(k.as_str(), *token)?;
|
||||||
|
ext_tokens.push(token);
|
||||||
|
}
|
||||||
|
// Okey
|
||||||
|
Ok(Self {
|
||||||
|
program,
|
||||||
|
ext_tokens,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_program(&self) -> &Program {
|
||||||
|
&self.program
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_ext_tokens(&self) -> impl Iterator<Item = Token> {
|
||||||
|
self.ext_tokens.iter().copied()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_register(cli: &Cli, target: &Target) -> Result<()> {
|
||||||
|
let composition = Composition::new(cli)?;
|
||||||
|
let scope = target.clone().into();
|
||||||
|
|
||||||
|
// Register program
|
||||||
|
let program = composition.get_program();
|
||||||
|
program.register(scope)?;
|
||||||
|
// Link all file extensions
|
||||||
|
for token in composition.iter_ext_tokens() {
|
||||||
|
program.link_ext(token, scope)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Register OK.");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_unregister(cli: &Cli, target: &Target) -> Result<()> {
|
||||||
|
let composition = Composition::new(cli)?;
|
||||||
|
let scope = target.clone().into();
|
||||||
|
|
||||||
|
// Unlink all file extensions
|
||||||
|
let program = composition.get_program();
|
||||||
|
for token in composition.iter_ext_tokens() {
|
||||||
|
program.unlink_ext(token, scope)?;
|
||||||
|
}
|
||||||
|
// Unregister prorgam
|
||||||
|
program.unregister(scope)?;
|
||||||
|
|
||||||
|
println!("Unregister OK.");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_query(cli: &Cli) -> Result<()> {
|
||||||
|
let composition = Composition::new(cli)?;
|
||||||
|
|
||||||
|
// Show file association
|
||||||
|
let mut table = Table::new();
|
||||||
|
table.set_header(["Extension", "Hybrid", "User", "System"]);
|
||||||
|
|
||||||
|
let program = composition.get_program();
|
||||||
|
for token in composition.iter_ext_tokens() {
|
||||||
|
let cell_ext = program.get_ext_str(token).unwrap();
|
||||||
|
let cell_hybrid = program
|
||||||
|
.query_ext(token, View::Hybrid)?
|
||||||
|
.map(|pi| pi.to_string())
|
||||||
|
.unwrap_or_default();
|
||||||
|
let cell_user = program
|
||||||
|
.query_ext(token, View::User)?
|
||||||
|
.map(|pi| pi.to_string())
|
||||||
|
.unwrap_or_default();
|
||||||
|
let cell_system = program
|
||||||
|
.query_ext(token, View::System)?
|
||||||
|
.map(|pi| pi.to_string())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
table.add_row([cell_ext, cell_hybrid, cell_user, cell_system]);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{table}");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let cli = Cli::parse();
|
||||||
|
|
||||||
|
let rv = match &cli.command {
|
||||||
|
Commands::Register { target } => run_register(&cli, target),
|
||||||
|
Commands::Unregister { target } => run_unregister(&cli, target),
|
||||||
|
Commands::Query => run_query(&cli),
|
||||||
|
};
|
||||||
|
rv.unwrap_or_else(|e| {
|
||||||
|
eprintln!("Runtime error: {}.", e);
|
||||||
|
process::exit(1)
|
||||||
|
});
|
||||||
|
}
|
||||||
0
wfassoc_exec/src/runner.rs
Normal file
0
wfassoc_exec/src/runner.rs
Normal file
Reference in New Issue
Block a user