mirror of
https://github.com/mii443/vrclipboard-ime-gui.git
synced 2025-12-03 03:08:27 +00:00
add dictionary UI
This commit is contained in:
142
src-tauri/src/dictionary.rs
Normal file
142
src-tauri/src/dictionary.rs
Normal file
@@ -0,0 +1,142 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{Read, Write},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::State;
|
||||
use tracing::{debug, error, info, trace};
|
||||
use regex::Regex;
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
converter::converter::{get_custom_converter, Converter},
|
||||
AppState,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub enum ConversionMethod {
|
||||
Replace,
|
||||
None,
|
||||
Converter(char),
|
||||
}
|
||||
|
||||
impl Default for ConversionMethod {
|
||||
fn default() -> Self {
|
||||
Self::None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct DictionaryEntry {
|
||||
pub input: String,
|
||||
pub method: ConversionMethod,
|
||||
pub output: Option<String>,
|
||||
pub use_regex: bool,
|
||||
pub priority: i32,
|
||||
}
|
||||
|
||||
impl Default for DictionaryEntry {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
input: String::new(),
|
||||
method: ConversionMethod::None,
|
||||
output: None,
|
||||
use_regex: false,
|
||||
priority: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct Dictionary {
|
||||
pub entries: Vec<DictionaryEntry>,
|
||||
}
|
||||
|
||||
impl Default for Dictionary {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
entries: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dictionary {
|
||||
pub fn load() -> Result<Dictionary> {
|
||||
debug!("Loading dictionary");
|
||||
std::fs::create_dir_all(Config::get_path())?;
|
||||
|
||||
let dict_path = Self::get_path();
|
||||
if !dict_path.exists() {
|
||||
info!("Dictionary file not found, generating default");
|
||||
Self::generate_default_dictionary()?;
|
||||
}
|
||||
let mut file = File::open(&dict_path)?;
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)?;
|
||||
trace!("Raw dictionary contents: {}", contents);
|
||||
let dictionary: Dictionary = serde_yaml::from_str(&contents)?;
|
||||
debug!("Dictionary loaded successfully with {} entries", dictionary.entries.len());
|
||||
Ok(dictionary)
|
||||
}
|
||||
|
||||
pub fn save(&self, state: State<AppState>) -> Result<(), String> {
|
||||
debug!("Saving dictionary");
|
||||
std::fs::create_dir_all(Config::get_path()).unwrap();
|
||||
|
||||
let dict_path = Self::get_path();
|
||||
let mut file = match File::create(&dict_path) {
|
||||
Ok(file) => file,
|
||||
Err(e) => {
|
||||
error!("Failed to create dictionary file: {}", e);
|
||||
return Err(format!("Failed to create dictionary file: {}", e));
|
||||
}
|
||||
};
|
||||
|
||||
match serde_yaml::to_string(&self) {
|
||||
Ok(yaml) => {
|
||||
trace!("Dictionary to be saved: {}", yaml);
|
||||
if let Err(e) = file.write_all(yaml.as_bytes()) {
|
||||
error!("Failed to write dictionary: {}", e);
|
||||
return Err(format!("Failed to write dictionary: {}", e));
|
||||
}
|
||||
let mut app_dictionary = state.dictionary.lock().unwrap();
|
||||
*app_dictionary = self.clone();
|
||||
info!("Dictionary saved successfully");
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to serialize dictionary: {}", e);
|
||||
Err(format!("Failed to serialize dictionary: {}", e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_default_dictionary() -> Result<()> {
|
||||
debug!("Generating default dictionary");
|
||||
let dict_path = Self::get_path();
|
||||
let mut file = File::create(&dict_path)?;
|
||||
let default_dict = Dictionary::default();
|
||||
let yaml = serde_yaml::to_string(&default_dict).unwrap();
|
||||
file.write_all(yaml.as_bytes())?;
|
||||
file.flush()?;
|
||||
info!("Default dictionary generated successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_path() -> PathBuf {
|
||||
let path = Config::get_path().join("dictionary.yaml");
|
||||
trace!("Dictionary path: {:?}", path);
|
||||
path
|
||||
}
|
||||
|
||||
pub fn apply_conversion(&self, text: &str) -> Result<String> {
|
||||
debug!("Applying dictionary conversions to: {}", text);
|
||||
|
||||
|
||||
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ mod tsf;
|
||||
mod tsf_conversion;
|
||||
mod tauri_emit_subscriber;
|
||||
mod tsf_availability;
|
||||
mod dictionary;
|
||||
|
||||
use std::sync::Mutex;
|
||||
|
||||
@@ -27,6 +28,7 @@ use tauri_emit_subscriber::TauriEmitSubscriber;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
use tsf_availability::check_tsf_availability;
|
||||
use tracing::debug;
|
||||
use dictionary::Dictionary;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
struct Log {
|
||||
@@ -37,9 +39,11 @@ struct Log {
|
||||
|
||||
struct AppState {
|
||||
config: Mutex<Config>,
|
||||
dictionary: Mutex<Dictionary>,
|
||||
}
|
||||
|
||||
static STATE: Lazy<Mutex<Config>> = Lazy::new(|| Mutex::new(Config::load().unwrap()));
|
||||
static DICTIONARY: Lazy<Mutex<Dictionary>> = Lazy::new(|| Mutex::new(Dictionary::load().unwrap()));
|
||||
|
||||
#[tauri::command]
|
||||
fn load_settings(state: State<AppState>) -> Result<Config, String> {
|
||||
@@ -71,6 +75,24 @@ fn check_tsf_availability_command() -> Result<bool, String> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn load_dictionary(state: State<AppState>) -> Result<Dictionary, String> {
|
||||
match Dictionary::load() {
|
||||
Ok(dictionary) => {
|
||||
let mut app_dictionary = state.dictionary.lock().unwrap();
|
||||
*app_dictionary = dictionary.clone();
|
||||
Ok(dictionary)
|
||||
}
|
||||
Err(e) => Err(format!("Failed to load dictionary: {}", e)),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn save_dictionary(dictionary: Dictionary, state: State<AppState>) -> Result<(), String> {
|
||||
*DICTIONARY.lock().unwrap() = dictionary.clone();
|
||||
dictionary.save(state).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn open_ms_settings_regionlanguage_jpnime() -> Result<(), String> {
|
||||
let _ = std::process::Command::new("cmd")
|
||||
@@ -89,11 +111,16 @@ fn main() {
|
||||
Config::generate_default_config().expect("Failed to generate default config");
|
||||
Config::load().expect("Failed to load default config")
|
||||
})),
|
||||
dictionary: Mutex::new(Dictionary::load().unwrap_or_else(|_| {
|
||||
Dictionary::generate_default_dictionary().expect("Failed to generate default dictionary");
|
||||
Dictionary::load().expect("Failed to load default dictionary")
|
||||
})),
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![load_settings, save_settings, check_tsf_availability_command, open_ms_settings_regionlanguage_jpnime])
|
||||
.invoke_handler(tauri::generate_handler![load_settings, save_settings, check_tsf_availability_command, open_ms_settings_regionlanguage_jpnime, load_dictionary, save_dictionary])
|
||||
.setup(|app| {
|
||||
let _span = tracing::span!(tracing::Level::INFO, "main");
|
||||
app.manage(STATE.lock().unwrap().clone());
|
||||
app.manage(DICTIONARY.lock().unwrap().clone());
|
||||
let app_handle = app.app_handle().clone();
|
||||
|
||||
let registry = tracing_subscriber::registry().with(TauriEmitSubscriber {
|
||||
|
||||
Reference in New Issue
Block a user