diff --git a/src-tauri/src/app_config.rs b/src-tauri/src/app_config.rs index f023e2d..131fe57 100644 --- a/src-tauri/src/app_config.rs +++ b/src-tauri/src/app_config.rs @@ -222,24 +222,21 @@ impl MultiAppConfig { /// 创建默认配置并自动导入已存在的提示词文件 fn default_with_auto_import() -> Result { log::info!("首次启动,创建默认配置并检测提示词文件"); - + let mut config = Self::default(); - + // 为每个应用尝试自动导入提示词 Self::auto_import_prompt_if_exists(&mut config, AppType::Claude)?; Self::auto_import_prompt_if_exists(&mut config, AppType::Codex)?; Self::auto_import_prompt_if_exists(&mut config, AppType::Gemini)?; - + Ok(config) } /// 检查并自动导入单个应用的提示词文件 - fn auto_import_prompt_if_exists( - config: &mut Self, - app: AppType, - ) -> Result<(), AppError> { + fn auto_import_prompt_if_exists(config: &mut Self, app: AppType) -> Result<(), AppError> { let file_path = prompt_file_path(&app)?; - + // 检查文件是否存在 if !file_path.exists() { log::debug!("提示词文件不存在,跳过自动导入: {file_path:?}"); @@ -273,25 +270,25 @@ impl MultiAppConfig { let prompt = crate::prompt::Prompt { id: id.clone(), name: format!( - "初始提示词 {}", + "Auto-imported Prompt {}", chrono::Local::now().format("%Y-%m-%d %H:%M") ), content, - description: Some("首次启动时自动导入".to_string()), + description: Some("Automatically imported on first launch".to_string()), enabled: true, // 自动启用 created_at: Some(timestamp), updated_at: Some(timestamp), }; - + // 插入到对应的应用配置中 let prompts = match app { AppType::Claude => &mut config.prompts.claude.prompts, AppType::Codex => &mut config.prompts.codex.prompts, AppType::Gemini => &mut config.prompts.gemini.prompts, }; - + prompts.insert(id, prompt); - + log::info!("自动导入完成: {}", app.as_str()); Ok(()) } @@ -306,6 +303,7 @@ mod tests { use tempfile::TempDir; struct TempHome { + #[allow(dead_code)] // 字段通过 Drop trait 管理临时目录生命周期 dir: TempDir, original_home: Option, original_userprofile: Option, @@ -444,7 +442,10 @@ mod tests { .expect("gemini prompt exists"); assert!(prompt.enabled, "gemini prompt should be enabled"); assert_eq!(prompt.content, "# Gemini Prompt\n\nTest content"); - assert_eq!(prompt.description, Some("首次启动时自动导入".to_string())); + assert_eq!( + prompt.description, + Some("Automatically imported on first launch".to_string()) + ); } #[test] @@ -463,8 +464,35 @@ mod tests { assert_eq!(config.prompts.gemini.prompts.len(), 1); // 验证所有提示词都被启用 - assert!(config.prompts.claude.prompts.values().next().unwrap().enabled); - assert!(config.prompts.codex.prompts.values().next().unwrap().enabled); - assert!(config.prompts.gemini.prompts.values().next().unwrap().enabled); + assert!( + config + .prompts + .claude + .prompts + .values() + .next() + .unwrap() + .enabled + ); + assert!( + config + .prompts + .codex + .prompts + .values() + .next() + .unwrap() + .enabled + ); + assert!( + config + .prompts + .gemini + .prompts + .values() + .next() + .unwrap() + .enabled + ); } } diff --git a/src-tauri/src/commands/prompt.rs b/src-tauri/src/commands/prompt.rs index c44bb03..6064e2f 100644 --- a/src-tauri/src/commands/prompt.rs +++ b/src-tauri/src/commands/prompt.rs @@ -58,9 +58,7 @@ pub async fn import_prompt_from_file( } #[tauri::command] -pub async fn get_current_prompt_file_content( - app: String, -) -> Result, String> { +pub async fn get_current_prompt_file_content(app: String) -> Result, String> { let app_type = AppType::from_str(&app).map_err(|e| e.to_string())?; PromptService::get_current_file_content(app_type).map_err(|e| e.to_string()) } diff --git a/src-tauri/src/prompt_files.rs b/src-tauri/src/prompt_files.rs index 395e01a..49aa6af 100644 --- a/src-tauri/src/prompt_files.rs +++ b/src-tauri/src/prompt_files.rs @@ -8,23 +8,9 @@ use crate::gemini_config::get_gemini_dir; /// 返回指定应用所使用的提示词文件路径。 pub fn prompt_file_path(app: &AppType) -> Result { - let base_dir = match app { - AppType::Claude => get_claude_settings_path() - .parent() - .map(|p| p.to_path_buf()) - .unwrap_or_else(|| { - dirs::home_dir() - .expect("无法获取用户目录") - .join(".claude") - }), - AppType::Codex => get_codex_auth_path() - .parent() - .map(|p| p.to_path_buf()) - .unwrap_or_else(|| { - dirs::home_dir() - .expect("无法获取用户目录") - .join(".codex") - }), + let base_dir: PathBuf = match app { + AppType::Claude => get_base_dir_with_fallback(get_claude_settings_path(), ".claude")?, + AppType::Codex => get_base_dir_with_fallback(get_codex_auth_path(), ".codex")?, AppType::Gemini => get_gemini_dir(), }; @@ -36,3 +22,23 @@ pub fn prompt_file_path(app: &AppType) -> Result { Ok(base_dir.join(filename)) } + +fn get_base_dir_with_fallback( + primary_path: PathBuf, + fallback_dir: &str, +) -> Result { + primary_path + .parent() + .map(|p| p.to_path_buf()) + .or_else(|| dirs::home_dir().map(|h| h.join(fallback_dir))) + .ok_or_else(|| { + AppError::localized( + "home_dir_not_found", + format!("无法确定 {} 配置目录:用户主目录不存在", fallback_dir), + format!( + "Cannot determine {} config directory: user home not found", + fallback_dir + ), + ) + }) +} diff --git a/src-tauri/src/services/prompt.rs b/src-tauri/src/services/prompt.rs index 191b0b4..8b4f54c 100644 --- a/src-tauri/src/services/prompt.rs +++ b/src-tauri/src/services/prompt.rs @@ -61,9 +61,7 @@ impl PromptService { if let Some(prompt) = prompts.get(id) { if prompt.enabled { - return Err(AppError::InvalidInput( - "无法删除已启用的提示词".to_string(), - )); + return Err(AppError::InvalidInput("无法删除已启用的提示词".to_string())); } } @@ -92,8 +90,9 @@ impl PromptService { if let Ok(content) = std::fs::read_to_string(&target_path) { if !content.trim().is_empty() { // 检查是否已存在相同内容的提示词,避免重复备份 - let content_exists = prompts.values().any(|p| p.content.trim() == content.trim()); - + let content_exists = + prompts.values().any(|p| p.content.trim() == content.trim()); + if !content_exists { let timestamp = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) @@ -102,7 +101,10 @@ impl PromptService { let backup_id = format!("backup-{timestamp}"); let backup_prompt = Prompt { id: backup_id.clone(), - name: format!("原始提示词 {}", chrono::Local::now().format("%Y-%m-%d %H:%M")), + name: format!( + "原始提示词 {}", + chrono::Local::now().format("%Y-%m-%d %H:%M") + ), content, description: Some("自动备份的原始提示词".to_string()), enabled: false, @@ -148,7 +150,8 @@ impl PromptService { return Err(AppError::Message("提示词文件不存在".to_string())); } - let content = std::fs::read_to_string(&file_path).map_err(|e| AppError::io(&file_path, e))?; + let content = + std::fs::read_to_string(&file_path).map_err(|e| AppError::io(&file_path, e))?; let timestamp = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() @@ -177,7 +180,8 @@ impl PromptService { if !file_path.exists() { return Ok(None); } - let content = std::fs::read_to_string(&file_path).map_err(|e| AppError::io(&file_path, e))?; + let content = + std::fs::read_to_string(&file_path).map_err(|e| AppError::io(&file_path, e))?; Ok(Some(content)) } }