Skip to content

Commit a6cba84

Browse files
committed
feat (core): 支持语言配置更新
1 parent b0e463c commit a6cba84

12 files changed

Lines changed: 342 additions & 33 deletions

File tree

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
"@tauri-apps/plugin-opener": "^2",
1616
"@tauri-apps/plugin-shell": "^2.3.0",
1717
"@vueuse/core": "^13.6.0",
18+
"lodash-es": "^4.17.21",
1819
"lucide-vue-next": "^0.539.0",
1920
"vue": "^3.5.13"
2021
},
2122
"devDependencies": {
2223
"@tailwindcss/postcss": "^4.1.11",
2324
"@tauri-apps/cli": "^2",
25+
"@types/lodash-es": "^4.17.12",
2426
"@vitejs/plugin-vue": "^5.2.1",
2527
"autoprefixer": "^10.4.21",
2628
"postcss": "^8.5.6",

src-tauri/src/config.rs

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use crate::plugins::PluginConfig;
2+
// 全局配置管理器
3+
use crate::PluginManagerState;
24
use log::{info, warn};
35
use serde::{Deserialize, Serialize};
46
use std::fs;
57
use std::path::PathBuf;
6-
// 全局配置管理器
78
use std::sync::Mutex;
8-
use tauri::command;
9+
use tauri::{AppHandle, Manager, command};
10+
911
static CONFIG_MANAGER: Mutex<Option<ConfigManager>> = Mutex::new(None);
1012

1113
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -35,9 +37,9 @@ pub struct ConfigManager {
3537
}
3638

3739
impl ConfigManager {
38-
pub fn new() -> Result<Self, String> {
40+
pub fn new(app_handle: Option<&AppHandle>) -> Result<Self, String> {
3941
let config_path = Self::get_config_path()?;
40-
let config = Self::load_config(&config_path)?;
42+
let config = Self::load_config(&config_path, app_handle)?;
4143

4244
Ok(Self {
4345
config_path,
@@ -59,27 +61,65 @@ impl ConfigManager {
5961
Ok(config_file)
6062
}
6163

62-
fn load_config(config_path: &PathBuf) -> Result<AppConfig, String> {
64+
fn load_config(
65+
config_path: &PathBuf,
66+
app_handle: Option<&AppHandle>,
67+
) -> Result<AppConfig, String> {
68+
println!("读取配置 -> 正在读取配置文件 {:?}", config_path);
6369
if config_path.exists() {
6470
match fs::read_to_string(config_path) {
6571
Ok(content) => match serde_json::from_str::<AppConfig>(&content) {
66-
Ok(config) => {
67-
info!("读取配置 -> 成功加载配置文件: {:?}", config_path);
72+
Ok(mut config) => {
73+
println!("读取配置 -> 成功加载配置文件: {:?}", config_path);
74+
75+
// 检查 plugins 是否为 null,如果是则加载默认配置
76+
if config.plugins.is_none() {
77+
println!("读取配置 -> plugins 为 null,加载默认插件配置");
78+
config.plugins = Self::get_default_plugins_config(app_handle);
79+
}
80+
6881
Ok(config)
6982
}
7083
Err(e) => {
7184
warn!("读取配置 -> 配置文件格式错误,使用默认配置: {}", e);
72-
Ok(AppConfig::default())
85+
Ok(Self::create_default_config(app_handle))
7386
}
7487
},
7588
Err(e) => {
7689
warn!("读取配置 -> 读取配置文件失败,使用默认配置: {}", e);
77-
Ok(AppConfig::default())
90+
Ok(Self::create_default_config(app_handle))
7891
}
7992
}
8093
} else {
81-
info!("读取配置 -> 配置文件不存在,使用默认配置");
82-
Ok(AppConfig::default())
94+
println!("读取配置 -> 配置文件不存在,使用默认配置");
95+
Ok(Self::create_default_config(app_handle))
96+
}
97+
}
98+
99+
fn get_default_plugins_config(app_handle: Option<&AppHandle>) -> Option<Vec<PluginConfig>> {
100+
if let Some(handle) = app_handle {
101+
// 从 Tauri 状态中获取 PluginManager
102+
if let Some(plugin_manager_state) = handle.try_state::<PluginManagerState>() {
103+
// 同步访问插件管理器
104+
if let Ok(manager) = plugin_manager_state.try_lock() {
105+
return Some(manager.get_all_plugin_default_config());
106+
} else {
107+
println!("读取配置 -> 无法获取插件管理器锁,使用空配置");
108+
}
109+
} else {
110+
println!("读取配置 -> 无法获取插件管理器状态,使用空配置");
111+
}
112+
}
113+
Some(vec![])
114+
}
115+
116+
fn create_default_config(app_handle: Option<&AppHandle>) -> AppConfig {
117+
AppConfig {
118+
log_directory: None,
119+
auto_clear_logs: Some(true),
120+
keep_log_days: Some(30),
121+
theme: Some("system".to_string()),
122+
plugins: Self::get_default_plugins_config(app_handle),
83123
}
84124
}
85125

@@ -89,7 +129,7 @@ impl ConfigManager {
89129

90130
fs::write(&self.config_path, content).map_err(|e| format!("写入配置文件失败: {}", e))?;
91131

92-
info!("保存配置 -> 配置文件已保存: {:?}", self.config_path);
132+
info!("保存配置 -> 配置文件已保存 {}", self.config_path.display());
93133
Ok(())
94134
}
95135

@@ -108,15 +148,15 @@ impl ConfigManager {
108148
}
109149

110150
// 初始化配置
111-
pub fn init_config() -> Result<(), String> {
112-
let config_manager = ConfigManager::new()?;
151+
pub fn init_config(app_handle: Option<&AppHandle>) -> Result<(), String> {
152+
let config_manager = ConfigManager::new(app_handle)?;
113153

114154
// 如果配置中有自定义日志目录,设置到日志系统
115155
if let Some(log_dir) = config_manager.get_log_directory() {
116-
info!("初始化 -> 从配置文件加载日志目录: {}", log_dir);
156+
println!("读取配置 -> 从配置文件加载日志目录: {}", log_dir);
117157
// 使用内部函数设置,避免循环保存
118158
if let Err(e) = crate::logger::set_log_directory_internal(log_dir.to_string()) {
119-
warn!("初始化 -> 应用配置中的日志目录失败: {}", e);
159+
warn!("读取配置 -> 应用配置中的日志目录失败: {}", e);
120160
}
121161
}
122162

src-tauri/src/main.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ async fn execute_code(
4646
"codeforge_{}_{}.{}",
4747
request.language,
4848
execution_id,
49-
plugin.get_file_extension().first().unwrap().to_string()
49+
plugin.get_file_extension()
5050
));
5151

5252
let processed_code = plugin.pre_execute_hook(&request.code).map_err(|e| {
@@ -62,7 +62,7 @@ async fn execute_code(
6262
.map_err(|e| format!("Failed to write temporary file: {}", e))?;
6363

6464
let start_time = std::time::Instant::now();
65-
let mut last_error = String::new();
65+
let mut last_error: String = String::new();
6666

6767
let cmd = plugin.get_command();
6868
let args = plugin.get_execute_args(file_path.to_str().unwrap());
@@ -162,6 +162,16 @@ async fn get_info(
162162
.get_plugin(&language)
163163
.ok_or_else(|| format!("Unsupported language: {}", language))?;
164164

165+
plugin.pre_execute_hook(&String::new()).map_err(|e| {
166+
error!(
167+
"获取环境 -> 调用插件 [ {} ] pre_execute_hook 出现错误 {:?}",
168+
language, e
169+
);
170+
171+
error!("获取环境 -> 调用插件 [ {} ] 失败", language);
172+
format!("Pre-execution hook failed: {}", e)
173+
})?;
174+
165175
let cmd = plugin.get_command();
166176
debug!("获取环境 -> 插件 [ {} ] 命令 {}", language, cmd);
167177

@@ -239,7 +249,7 @@ fn main() {
239249
.manage(PluginManagerState::new(PluginManager::new()))
240250
.setup(|app| {
241251
// 第一步:初始化配置系统
242-
if let Err(e) = init_config() {
252+
if let Err(e) = init_config(Some(app.handle())) {
243253
eprintln!("Failed to initialize config: {}", e);
244254
}
245255

src-tauri/src/plugins/manager.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{LanguagePlugin, python2::Python2Plugin, python3::Python3Plugin};
1+
use super::{python2::Python2Plugin, python3::Python3Plugin, LanguagePlugin, PluginConfig};
22
use std::collections::HashMap;
33

44
pub struct PluginManager {
@@ -53,7 +53,7 @@ impl PluginManager {
5353
pub fn get_plugin_info(&self, language: &str) -> Option<PluginInfo> {
5454
self.get_plugin(language).map(|plugin| PluginInfo {
5555
name: plugin.get_language_name().to_string(),
56-
file_extension: plugin.get_file_extension().first().unwrap().to_string(),
56+
file_extension: plugin.get_file_extension(),
5757
available_commands: vec![plugin.get_command().to_string()],
5858
})
5959
}
@@ -64,11 +64,18 @@ impl PluginManager {
6464
.values()
6565
.map(|plugin| PluginInfo {
6666
name: plugin.get_language_name().to_string(),
67-
file_extension: plugin.get_file_extension().first().unwrap().to_string(),
68-
available_commands: vec![plugin.get_command().to_string()]
67+
file_extension: plugin.get_file_extension(),
68+
available_commands: vec![plugin.get_command().to_string()],
6969
})
7070
.collect()
7171
}
72+
73+
pub fn get_all_plugin_default_config(&self) -> Vec<PluginConfig> {
74+
self.plugins
75+
.values()
76+
.map(|plugin| plugin.get_default_config())
77+
.collect()
78+
}
7279
}
7380

7481
#[derive(Debug, serde::Serialize)]

src-tauri/src/plugins/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub struct LanguageInfo {
3333
pub struct PluginConfig {
3434
pub enabled: bool, // 插件是否启用
3535
pub execute_home: Option<String>, // 插件的执行路径
36-
pub extensions: Vec<String>, // 插件支持的文件扩展名
36+
pub extension: String, // 插件支持的文件扩展名
3737
pub language: String, // 插件所属语言
3838
pub before_compile: Option<String>, // 插件在编译前执行的命令
3939
pub after_compile: Option<String>, // 插件在编译完成后执行的命令
@@ -55,8 +55,8 @@ pub trait LanguagePlugin: Send + Sync {
5555
fn get_language_key(&self) -> &'static str;
5656

5757
// 获取插件支持的文件扩展名
58-
fn get_file_extension(&self) -> Vec<String> {
59-
self.get_config().unwrap().extensions.clone()
58+
fn get_file_extension(&self) -> String {
59+
self.get_config().unwrap().extension.clone()
6060
}
6161

6262
// 获取执行目录

src-tauri/src/plugins/python2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl LanguagePlugin for Python2Plugin {
3333
enabled: true,
3434
language: String::from("python2"),
3535
before_compile: None,
36-
extensions: vec![String::from("py")],
36+
extension: String::from("py"),
3737
execute_home: None,
3838
run_command: Option::from(String::from("python2 $filename")),
3939
after_compile: None,

src-tauri/src/plugins/python3.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ impl LanguagePlugin for Python3Plugin {
3232
enabled: true,
3333
language: String::from("python3"),
3434
before_compile: None,
35-
extensions: vec![String::from("py")],
35+
extension: String::from("py"),
3636
execute_home: None,
3737
run_command: Option::from(String::from("python3 $filename")),
3838
after_compile: None,

src-tauri/src/setup/menus/app.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
use log::info;
12
use tauri::{
2-
AppHandle, Emitter,
3-
menu::{MenuItemBuilder, Submenu, SubmenuBuilder},
3+
menu::{MenuItemBuilder, Submenu, SubmenuBuilder}, AppHandle,
4+
Emitter,
45
};
56

67
pub fn create_app_submenu(app: &AppHandle) -> tauri::Result<Submenu<tauri::Wry>> {
@@ -38,6 +39,7 @@ pub fn handle_app_menu_event(app: &AppHandle, event_id: &str) {
3839
let _event = app.emit("show-settings", ());
3940
}
4041
"quit" => {
42+
info!("CodeForge 应用关闭");
4143
app.exit(0);
4244
}
4345
_ => {}

src/components/Settings.vue

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,33 @@
11
<template>
22
<Modal v-model:show="isVisible" title="设置" size="4xl" :close-on-backdrop="false" :close-on-esc="false" @close="closeSettings">
33
<Tabs v-model="activeTab" type="card" size="md" :tabs="tabsData">
4+
<!-- 通用配置 -->
45
<template #general>
56
<General/>
67
</template>
8+
9+
<!-- 语言配置 -->
10+
<template #language>
11+
<Language/>
12+
</template>
713
</Tabs>
814
</Modal>
915
</template>
1016

1117
<script setup lang="ts">
1218
import { nextTick, onMounted, ref } from 'vue'
13-
import { ShieldIcon } from 'lucide-vue-next'
19+
import { BracesIcon, ShieldIcon } from 'lucide-vue-next'
1420
import Modal from '../ui/Modal.vue'
1521
import Tabs from '../ui/Tabs.vue'
1622
import General from './setting/General.vue'
23+
import Language from './setting/Language.vue'
24+
import { useToast } from '../plugins/toast.ts'
1725
1826
const isVisible = ref(false)
1927
const activeTab = ref('general')
2028
const tabsData = [
21-
{ key: 'general', label: '通用', icon: ShieldIcon }
29+
{ key: 'general', label: '通用', icon: ShieldIcon },
30+
{ key: 'language', label: '语言', icon: BracesIcon }
2231
]
2332
2433
const emit = defineEmits<{
@@ -32,6 +41,8 @@ const closeSettings = () => {
3241
}, 300)
3342
}
3443
44+
const toast = useToast()
45+
3546
onMounted(async () => {
3647
// 延迟显示动画
3748
await nextTick()

0 commit comments

Comments
 (0)