Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 40 additions & 15 deletions src-tauri/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,35 @@ use tauri::{AppHandle, Manager};
static LOG_DIRECTORY: Mutex<Option<PathBuf>> = Mutex::new(None);

pub fn setup_logger(app: &AppHandle) -> Result<(), fern::InitError> {
// 获取日志目录(可能是自定义的,也可能是默认的)
// 获取日志目录
let log_dir = get_effective_log_directory(app);

// 创建日志目录
if let Err(e) = fs::create_dir_all(&log_dir) {
eprintln!("Failed to create log directory: {}", e);
// 如果自定义目录创建失败,回退到默认目录
let default_dir = get_default_log_directory(app);
fs::create_dir_all(&default_dir).expect("Failed to create default log directory");

// 更新为默认目录
{
let mut guard = LOG_DIRECTORY.lock().unwrap();
*guard = None; // 清除自定义设置
*guard = None;
}

warn!("日志目录创建失败,使用默认目录: {:?}", default_dir);
} else {
info!("日志目录: {:?}", log_dir);
}

// 生成当天的日志文件名
let today = Local::now().format("%Y-%m-%d").to_string();
let log_file = log_dir.join(format!("codeforge-{}.log", today));

// 配置日志
fern::Dispatch::new()
// 不同级别的日志文件
let all_log_file = log_dir.join(format!("codeforge-{}.log", today));
let error_log_file = log_dir.join(format!("codeforge-error-{}.log", today));
let warn_log_file = log_dir.join(format!("codeforge-warn-{}.log", today));
let info_log_file = log_dir.join(format!("codeforge-info-{}.log", today));
let debug_log_file = log_dir.join(format!("codeforge-debug-{}.log", today));

// 基础配置
let base_config = fern::Dispatch::new()
.format(|out, message, record| {
out.finish(format_args!(
"[{}] [{}] [{}:{}] {}",
Expand All @@ -45,17 +47,40 @@ pub fn setup_logger(app: &AppHandle) -> Result<(), fern::InitError> {
message
))
})
.level(LevelFilter::Debug) // 设置日志级别
.level_for("hyper", LevelFilter::Warn) // 减少第三方库的日志
.level(LevelFilter::Debug)
.level_for("hyper", LevelFilter::Warn)
.level_for("reqwest", LevelFilter::Warn)
.level_for("tauri", LevelFilter::Info) // Tauri 框架日志
.chain(std::io::stdout()) // 同时输出到控制台
.chain(fern::log_file(&log_file)?) // 输出到文件
.level_for("tauri", LevelFilter::Info);

// 配置不同级别的日志输出
base_config
.chain(std::io::stdout()) // 控制台输出
.chain(fern::log_file(&all_log_file)?) // 所有级别写入总文件
.chain(
fern::Dispatch::new()
.filter(|metadata| metadata.level() == log::Level::Error)
.chain(fern::log_file(&error_log_file)?),
)
.chain(
fern::Dispatch::new()
.filter(|metadata| metadata.level() == log::Level::Warn)
.chain(fern::log_file(&warn_log_file)?),
)
.chain(
fern::Dispatch::new()
.filter(|metadata| metadata.level() == log::Level::Info)
.chain(fern::log_file(&info_log_file)?),
)
.chain(
fern::Dispatch::new()
.filter(|metadata| metadata.level() == log::Level::Debug)
.chain(fern::log_file(&debug_log_file)?),
)
.apply()?;

info!("CodeForge 应用启动");
info!("应用版本: {}", env!("CARGO_PKG_VERSION"));
info!("日志文件: {:?}", log_file);
info!("日志文件目录 {}", log_dir.display());

Ok(())
}
Expand Down
12 changes: 7 additions & 5 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ async fn execute_code(
let start_time = std::time::Instant::now();
let mut _last_error: String = String::new();

let cmd = plugin.get_command();
let cmd = plugin.get_command(None);
let args = plugin.get_execute_args(file_path.to_str().unwrap());
info!(
"执行代码 -> 调用插件 [ {} ] 执行命令 {} 携带参数 {}",
Expand All @@ -74,7 +74,7 @@ async fn execute_code(
);

let output = Command::new(&cmd)
.args(&args)
.args(args)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output();
Expand Down Expand Up @@ -142,7 +142,9 @@ async fn execute_code(
request.language,
request.language,
_last_error,
plugin.get_command().to_string()
plugin
.get_command(Some(file_path.to_str().unwrap()))
.to_string()
),
execution_time,
timestamp,
Expand Down Expand Up @@ -172,7 +174,7 @@ async fn get_info(
format!("Pre-execution hook failed: {}", e)
})?;

let cmd = plugin.get_command();
let cmd = plugin.get_command(None);
debug!("获取环境 -> 插件 [ {} ] 命令 {}", language, cmd);

let version_output = Command::new(&cmd).args(plugin.get_version_args()).output();
Expand Down Expand Up @@ -211,7 +213,7 @@ async fn get_info(
Ok(LanguageInfo {
installed: false,
version: "Not found".to_string(),
path: format!("Not found - tried: {:?}", plugin.get_command()),
path: format!("Not found - tried: {:?}", plugin.get_command(None)),
language: plugin.get_language_name().to_string(),
})
}
Expand Down
4 changes: 2 additions & 2 deletions src-tauri/src/plugins/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl PluginManager {
self.get_plugin(language).map(|plugin| PluginInfo {
name: plugin.get_language_name().to_string(),
file_extension: plugin.get_file_extension(),
available_commands: vec![plugin.get_command().to_string()],
available_commands: vec![plugin.get_command(None).to_string()],
})
}

Expand All @@ -65,7 +65,7 @@ impl PluginManager {
.map(|plugin| PluginInfo {
name: plugin.get_language_name().to_string(),
file_extension: plugin.get_file_extension(),
available_commands: vec![plugin.get_command().to_string()],
available_commands: vec![plugin.get_command(None).to_string()],
})
.collect()
}
Expand Down
41 changes: 33 additions & 8 deletions src-tauri/src/plugins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,23 @@ pub trait LanguagePlugin: Send + Sync {
fn get_execute_home(&self) -> Option<PathBuf> {
self.get_config()
.and_then(|config| config.execute_home.clone())
.filter(|path| !path.trim().is_empty()) // 过滤掉空字符串和只有空白字符的字符串
.map(PathBuf::from)
}

// 获取插件支持的命令
fn get_command(&self) -> String {
fn get_command(&self, file_path: Option<&str>) -> String {
if let Some(config) = self.get_config() {
if let Some(run_cmd) = &config.run_command {
return run_cmd
.split_whitespace()
.next()
.unwrap_or(&config.language)
.to_string();
if let Some(path) = file_path {
return run_cmd.replace("$filename", path);
} else {
return run_cmd
.split_whitespace()
.next()
.unwrap_or(&config.language)
.to_string();
}
}
}
self.get_default_command()
Expand Down Expand Up @@ -120,7 +125,23 @@ pub trait LanguagePlugin: Send + Sync {
}

fn get_version_args(&self) -> Vec<&'static str>;
fn get_execute_args(&self, file_path: &str) -> Vec<String>;

fn get_execute_args(&self, file_path: &str) -> Vec<String> {
if let Some(config) = self.get_config() {
if let Some(run_cmd) = &config.run_command {
// 替换 $filename 后分割,跳过第一个元素(命令本身)
let full_cmd = run_cmd.replace("$filename", file_path);
return full_cmd
.split_whitespace()
.skip(1) // 跳过命令部分,只返回参数
.map(|s| s.to_string())
.collect();
}
}
// 默认情况下,文件路径就是唯一的参数
vec![file_path.to_string()]
}

fn get_path_command(&self) -> String;

// 构建默认配置
Expand Down Expand Up @@ -193,7 +214,11 @@ pub trait LanguagePlugin: Send + Sync {
}

// 后执行钩子
fn post_execute_hook(&self, _result: &mut ExecutionResult) -> Result<(), String> {
fn post_execute_hook(&self, result: &mut ExecutionResult) -> Result<(), String> {
if result.success && result.stdout.is_empty() && result.stderr.is_empty() {
result.stdout = "代码执行成功 (无输出)".to_string();
}

Ok(())
}
}
Expand Down
4 changes: 0 additions & 4 deletions src-tauri/src/plugins/python2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ impl LanguagePlugin for Python2Plugin {
vec!["--version"]
}

fn get_execute_args(&self, file_path: &str) -> Vec<String> {
vec![file_path.to_string()]
}

fn get_path_command(&self) -> String {
"import sys; print(sys.executable)".to_string()
}
Expand Down
22 changes: 1 addition & 21 deletions src-tauri/src/plugins/python3.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{ExecutionResult, LanguagePlugin, PluginConfig};
use super::{LanguagePlugin, PluginConfig};

pub struct Python3Plugin;

Expand All @@ -19,10 +19,6 @@ impl LanguagePlugin for Python3Plugin {
vec!["--version"]
}

fn get_execute_args(&self, file_path: &str) -> Vec<String> {
vec![file_path.to_string()]
}

fn get_path_command(&self) -> String {
"import sys; print(sys.executable)".to_string()
}
Expand All @@ -43,20 +39,4 @@ impl LanguagePlugin for Python3Plugin {
fn get_default_command(&self) -> String {
self.get_config().unwrap().run_command.unwrap()
}

fn post_execute_hook(&self, result: &mut ExecutionResult) -> Result<(), String> {
// Python 特定的后处理
if result.success && result.stdout.is_empty() && result.stderr.is_empty() {
result.stdout = "代码执行成功 (无输出)".to_string();
}

// 清理 Python 特定的错误信息
if !result.stderr.is_empty() {
result.stderr = result
.stderr
.replace("Traceback (most recent call last):", "Error:");
}

Ok(())
}
}
2 changes: 1 addition & 1 deletion src/components/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<!-- 语言配置 -->
<template #language>
<Language/>
<Language v-if="activeTab === 'language'"/>
</template>
</Tabs>
</Modal>
Expand Down
2 changes: 1 addition & 1 deletion src/components/setting/Language.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="-mt-2">
<Tabs v-model="activeTab" type="card" size="md" position="left" :tabs="tabsData" @change="handleTabChange">
<Tabs v-model="activeTab" type="card" size="md" position="left" :tab-button-class="['w-36']" :tabs="tabsData" @change="handleTabChange">
<template #[activeTab]="{ tab }">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
<Settings2 class="w-5 h-5 mr-2"/>
Expand Down
23 changes: 19 additions & 4 deletions src/ui/Tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,14 @@ const getTabButtonClasses = (tab: Tab, _index: number) => {
'transition-all', 'duration-200', 'cursor-pointer', 'whitespace-nowrap'
]

// 位置相关
if (props.position === 'left' || props.position === 'right') {
baseClasses.push('my-0.5')
}
else {
baseClasses.push('mx-0.5')
}

// 尺寸
if (props.size === 'sm') {
baseClasses.push('px-3', 'py-1.5', 'text-xs')
Expand All @@ -270,7 +278,7 @@ const getTabButtonClasses = (tab: Tab, _index: number) => {
baseClasses.push('text-blue-600', 'dark:text-blue-400', 'border-blue-600', 'dark:border-blue-400')
}
else {
baseClasses.push('text-gray-600', 'hover:text-gray-900', 'dark:text-gray-400', 'dark:hover:text-gray-100', 'hover:border-gray-300', 'dark:hover:border-gray-600')
baseClasses.push('text-gray-600', 'hover:text-blue-500', 'dark:text-gray-400', 'dark:hover:text-blue-300', 'hover:border-blue-300', 'dark:hover:border-blue-500')
}
break

Expand All @@ -281,7 +289,7 @@ const getTabButtonClasses = (tab: Tab, _index: number) => {
baseClasses.push('bg-white', 'dark:bg-gray-700', 'shadow-sm', 'text-blue-600', 'dark:text-blue-400')
}
else {
baseClasses.push('text-gray-600', 'hover:text-gray-900', 'dark:text-gray-400', 'dark:hover:text-gray-100')
baseClasses.push('text-gray-600', 'hover:text-blue-500', 'dark:text-gray-400', 'dark:hover:text-blue-300', 'hover:bg-gray-100', 'dark:hover:bg-gray-600')
}
break

Expand All @@ -291,7 +299,14 @@ const getTabButtonClasses = (tab: Tab, _index: number) => {
baseClasses.push('bg-blue-600', 'text-white', 'border-blue-600', 'z-10')
}
else {
baseClasses.push('bg-white', 'dark:bg-gray-800', 'text-gray-600', 'hover:text-gray-900', 'dark:text-gray-400', 'dark:hover:text-gray-100')
baseClasses.push('bg-white',
'dark:bg-gray-800',
'text-gray-600',
'hover:text-blue-500',
'dark:text-gray-400',
'dark:hover:text-blue-300',
'hover:bg-blue-50',
'dark:hover:bg-blue-900/20')
}
break

Expand All @@ -300,7 +315,7 @@ const getTabButtonClasses = (tab: Tab, _index: number) => {
baseClasses.push('text-blue-600', 'dark:text-blue-400')
}
else {
baseClasses.push('text-gray-600', 'hover:text-gray-900', 'dark:text-gray-400', 'dark:hover:text-gray-100')
baseClasses.push('text-gray-600', 'hover:text-blue-500', 'dark:text-gray-400', 'dark:hover:text-blue-300')
}
}

Expand Down
Loading