add dictionary UI

This commit is contained in:
mii
2025-03-05 22:04:32 +09:00
parent 89b688176b
commit 75210c08c9
7 changed files with 904 additions and 7 deletions

142
src-tauri/src/dictionary.rs Normal file
View 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!()
}
}

View File

@@ -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 {