Skip to content

Commit 356a3a6

Browse files
committed
feat (language): 支持 Kotlin 语言
1 parent bb8918b commit 356a3a6

5 files changed

Lines changed: 120 additions & 27 deletions

File tree

src-tauri/src/execution.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use std::thread;
99
use std::time::{SystemTime, UNIX_EPOCH};
1010
use tauri::{AppHandle, Emitter, State};
1111
use tokio::sync::Mutex;
12-
use uuid::Uuid;
1312

1413
// 执行任务结构
1514
#[derive(Debug)]
@@ -81,27 +80,27 @@ pub async fn execute_code(
8180
.get_plugin(&request.language)
8281
.ok_or_else(|| format!("Unsupported language: {}", request.language))?;
8382

84-
let execution_id = Uuid::new_v4().to_string();
8583
let temp_dir = std::env::temp_dir();
8684
let file_path = temp_dir.join(format!(
87-
"codeforge_{}_{}.{}",
85+
"Codeforge_{}.{}",
8886
request.language,
89-
execution_id,
9087
plugin.get_file_extension()
9188
));
9289

93-
let processed_code = plugin.pre_execute_hook(&request.code).map_err(|e| {
94-
error!(
95-
"执行代码 -> 调用插件 [ {} ] pre_execute_hook 出现错误 {:?}",
96-
request.language, e
97-
);
98-
format!("Pre-execution hook failed: {}", e)
99-
})?;
100-
10190
// 写入代码到临时文件
102-
fs::write(&file_path, &processed_code)
91+
fs::write(&file_path, &request.code)
10392
.map_err(|e| format!("Failed to write temporary file: {}", e))?;
10493

94+
let _processed_code = plugin
95+
.pre_execute_hook(&request.code, file_path.to_str().unwrap())
96+
.map_err(|e| {
97+
error!(
98+
"执行代码 -> 调用插件 [ {} ] pre_execute_hook 出现错误 {:?}",
99+
request.language, e
100+
);
101+
format!("Pre-execution hook failed: {}", e)
102+
})?;
103+
105104
let start_time = std::time::Instant::now();
106105

107106
let cmd = plugin.get_command(None);

src-tauri/src/plugin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub async fn get_info(
1818
.get_plugin(&language)
1919
.ok_or_else(|| format!("Unsupported language: {}", language))?;
2020

21-
plugin.pre_execute_hook("").map_err(|e| {
21+
plugin.pre_execute_hook("", "").map_err(|e| {
2222
error!(
2323
"获取环境 -> 调用插件 [ {} ] pre_execute_hook 出现错误 {:?}",
2424
language, e

src-tauri/src/plugins/kotlin.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use super::{LanguagePlugin, PluginConfig};
2+
use std::vec;
3+
4+
pub struct KotlinPlugin;
5+
6+
impl LanguagePlugin for KotlinPlugin {
7+
fn get_order(&self) -> i32 {
8+
10
9+
}
10+
11+
fn get_language_name(&self) -> &'static str {
12+
"Kotlin"
13+
}
14+
15+
fn get_language_key(&self) -> &'static str {
16+
"kotlin"
17+
}
18+
19+
fn get_file_extension(&self) -> String {
20+
self.get_config()
21+
.map(|config| config.extension.clone())
22+
.unwrap_or_else(|| "kt".to_string())
23+
}
24+
25+
fn get_version_args(&self) -> Vec<&'static str> {
26+
vec!["-version"]
27+
}
28+
29+
fn get_path_command(&self) -> String {
30+
"which kotlinc".to_string()
31+
}
32+
33+
fn get_execute_args(&self, file_path: &str) -> Vec<String> {
34+
if let Some(config) = self.get_config() {
35+
if let Some(run_cmd) = &config.run_command {
36+
let processed_cmd = if run_cmd.contains("$classname") {
37+
// 为 Kotlin 生成类名:Codeforge_kotlin.kt -> Codeforge_kotlinKt
38+
let class_name = std::path::Path::new(file_path)
39+
.file_stem()
40+
.unwrap_or_default()
41+
.to_string_lossy()
42+
.to_string()
43+
+ "Kt";
44+
run_cmd.replace("$classname", &class_name)
45+
} else {
46+
run_cmd.replace("$filename", file_path)
47+
};
48+
49+
return processed_cmd
50+
.split_whitespace()
51+
.skip(1) // 跳过命令部分,只返回参数
52+
.map(|s| s.to_string())
53+
.collect();
54+
}
55+
}
56+
// 默认情况下,文件路径就是唯一的参数
57+
vec![file_path.to_string()]
58+
}
59+
60+
fn get_default_config(&self) -> PluginConfig {
61+
PluginConfig {
62+
enabled: true,
63+
language: String::from("kotlin"),
64+
before_compile: Some(String::from("kotlinc $filename")),
65+
extension: String::from("kt"),
66+
execute_home: None,
67+
run_command: Some(String::from("kotlin $classname")),
68+
after_compile: Some(String::from("rm -f *.class")),
69+
template: Some(String::from(
70+
"// Kotlin 示例代码 - CodeForge 代码执行环境\n\nfun main() {\n println(\"🎉 欢迎使用 CodeForge!\")\n println(\"Welcome to CodeForge!\")\n println(\"\")\n\n println(\"=========================================\")\n println(\" CodeForge Kotlin \")\n println(\"=========================================\")\n println(\"\")\n\n // 基本输出示例\n println(\"✅ Kotlin 运行成功! (Kotlin is working!)\")\n println(\"🚀 这是 Kotlin 脚本 (This is Kotlin script)\")\n println(\"\")\n\n // 变量操作\n val name = \"CodeForge\"\n val version = \"Kotlin\"\n val number1 = 10\n val number2 = 20\n val result = number1 + number2\n\n println(\"🔢 简单计算 (Simple calculation):\")\n println(\"$number1 + $number2 = $result\")\n println(\"\")\n\n // 字符串操作\n println(\"📝 字符串操作 (String operations):\")\n println(\"平台名称 (Platform): $name\")\n println(\"语言版本 (Language): $version\")\n println(\"完整信息 (Full info): $name - $version\")\n println(\"\")\n\n // 循环示例\n println(\"🔄 循环输出 (Loop output):\")\n for (i in 1..5) {\n println(\"第 $i 次输出 (Output #$i): Hello from CodeForge!\")\n }\n println(\"\")\n\n // 列表操作\n val fruits = listOf(\"苹果\", \"香蕉\", \"橙子\", \"葡萄\")\n println(\"🍎 水果列表 (Fruit list):\")\n fruits.forEachIndexed { index, fruit ->\n println(\"${index + 1}. $fruit\")\n }\n println(\"\")\n\n // 条件判断\n val score = 85\n println(\"📊 成绩评估 (Score evaluation):\")\n when {\n score >= 90 -> println(\"优秀! (Excellent!)\")\n score >= 80 -> println(\"良好! (Good!)\")\n score >= 60 -> println(\"及格 (Pass)\")\n else -> println(\"需要努力 (Need improvement)\")\n }\n\n // 可空类型示例\n var nullableValue: Int? = 42\n println(\"\")\n println(\"🔍 可空类型示例 (Nullable example):\")\n nullableValue?.let { value ->\n println(\"可空值: $value (Nullable value: $value)\")\n } ?: println(\"值为空 (Value is null)\")\n\n // 函数示例\n fun greetUser(name: String): String {\n return \"Hello, $name! 👋\"\n }\n\n println(\"\")\n println(\"🎭 函数示例 (Function example):\")\n val greeting = greetUser(\"CodeForge用户\")\n println(greeting)\n\n // 扩展函数示例\n fun String.addEmoji(): String = \"✨ $this ✨\"\n \n println(\"\")\n println(\"⚡ 扩展函数示例 (Extension function):\")\n val decoratedText = \"Kotlin很棒\".addEmoji()\n println(decoratedText)\n\n // 数据类示例\n data class Person(val name: String, val age: Int)\n val person = Person(\"张三\", 25)\n \n println(\"\")\n println(\"👤 数据类示例 (Data class example):\")\n println(\"姓名: ${person.name}, 年龄: ${person.age}\")\n \n // 解构声明\n val (personName, personAge) = person\n println(\"解构后 (Destructured): $personName 今年 $personAge 岁\")\n\n // 高阶函数示例\n println(\"\")\n println(\"🔧 高阶函数示例 (Higher-order function):\")\n val numbers = (1..10).toList()\n val evenNumbers = numbers.filter { it % 2 == 0 }\n val doubled = numbers.map { it * 2 }\n \n println(\"原始数字 (Original): ${numbers.joinToString(\", \")}\")\n println(\"偶数 (Even numbers): ${evenNumbers.joinToString(\", \")}\")\n println(\"翻倍 (Doubled): ${doubled.joinToString(\", \")}\")\n\n // Lambda 表达式示例\n println(\"\")\n println(\"🎯 Lambda 表达式 (Lambda expression):\")\n val calculate: (Int, Int) -> Int = { a, b -> a * b }\n val product = calculate(6, 7)\n println(\"6 × 7 = $product\")\n\n // 集合操作链式调用\n println(\"\")\n println(\"⛓️ 集合链式操作 (Collection chaining):\")\n val result2 = (1..20)\n .filter { it % 3 == 0 }\n .map { \"数字: $it\" }\n .take(3)\n .joinToString(\" | \")\n println(\"3的倍数前3个: $result2\")\n\n // 字符串模板高级用法\n println(\"\")\n println(\"📝 字符串模板 (String template):\")\n val items = listOf(\"代码\", \"测试\", \"部署\")\n val status = \"进行中\"\n println(\"任务状态: ${items.joinToString(\", \")} - $status\")\n \n println(\"\")\n println(\"🎯 CodeForge Kotlin 代码执行完成!\")\n println(\"🎯 CodeForge Kotlin execution completed!\")\n println(\"\")\n println(\"感谢使用 CodeForge 代码执行环境! 🚀\")\n println(\"Thank you for using CodeForge! 🚀\")\n}",
71+
)),
72+
timeout: Some(60),
73+
}
74+
}
75+
76+
fn get_default_command(&self) -> String {
77+
self.get_config()
78+
.and_then(|config| config.run_command.clone())
79+
.unwrap_or_else(|| "kotlin".to_string())
80+
}
81+
}

src-tauri/src/plugins/manager.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use super::{
33
python3::Python3Plugin,
44
};
55
use crate::plugins::java::JavaPlugin;
6+
use crate::plugins::kotlin::KotlinPlugin;
67
use crate::plugins::rust::RustPlugin;
78
use crate::plugins::scala::ScalaPlugin;
89
use crate::plugins::shell::ShellPlugin;
@@ -26,6 +27,7 @@ impl PluginManager {
2627
plugins.insert("rust".to_string(), Box::new(RustPlugin));
2728
plugins.insert("swift".to_string(), Box::new(SwiftPlugin));
2829
plugins.insert("scala".to_string(), Box::new(ScalaPlugin));
30+
plugins.insert("kotlin".to_string(), Box::new(KotlinPlugin));
2931

3032
Self { plugins }
3133
}

src-tauri/src/plugins/mod.rs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -175,25 +175,14 @@ pub trait LanguagePlugin: Send + Sync {
175175
fn get_default_command(&self) -> String;
176176

177177
// 预执行钩子
178-
fn pre_execute_hook(&self, code: &str) -> Result<String, String> {
178+
fn pre_execute_hook(&self, code: &str, file_path: &str) -> Result<String, String> {
179179
info!(
180180
"执行代码 -> 插件 [ {} ] 处理 pre_execute_hook 开始",
181181
self.get_language_key()
182182
);
183183

184184
if let Some(config) = self.get_config() {
185-
// 1. 处理 before_compile 命令(直接在 Rust 中处理)
186-
if let Some(before_cmd) = &config.before_compile {
187-
info!(
188-
"执行代码 -> 插件 [ {} ] 处理 pre_execute_hook 处理环境变量: {}",
189-
self.get_language_key(),
190-
before_cmd
191-
);
192-
193-
self.handle_environment_setup(before_cmd)?;
194-
}
195-
196-
// 2. 切换到 execute_home 目录
185+
// 1. 切换到 execute_home 目录
197186
if let Some(execute_home) = self.get_execute_home() {
198187
info!(
199188
"执行代码 -> 插件 [ {} ] 处理 pre_execute_hook 切换到执行目录 {}",
@@ -203,6 +192,27 @@ pub trait LanguagePlugin: Send + Sync {
203192
std::env::set_current_dir(&execute_home)
204193
.map_err(|e| format!("切换目录失败: {}", e))?;
205194
}
195+
196+
// 2. 处理 before_compile 命令(直接在 Rust 中处理)
197+
if let Some(before_cmd) = &config.before_compile {
198+
info!(
199+
"执行代码 -> 插件 [ {} ] 处理 pre_execute_hook 处理环境变量: {}",
200+
self.get_language_key(),
201+
before_cmd
202+
);
203+
204+
// 如果命令包含 $filename 但没有提供 filename,跳过编译步骤
205+
if before_cmd.contains("$filename") && file_path.is_empty() {
206+
info!(
207+
"执行代码 -> 插件 [ {} ] 处理 pre_execute_hook 跳过编译步骤,因为没有提供文件名",
208+
self.get_language_key()
209+
);
210+
return Ok(code.to_string());
211+
}
212+
213+
let processed_cmd = before_cmd.replace("$filename", file_path);
214+
self.handle_environment_setup(&processed_cmd)?;
215+
}
206216
}
207217

208218
info!(
@@ -332,6 +342,7 @@ pub trait LanguagePlugin: Send + Sync {
332342
// 重新导出子模块
333343
pub mod go;
334344
pub mod java;
345+
pub mod kotlin;
335346
pub mod manager;
336347
pub mod nodejs;
337348
pub mod python2;

0 commit comments

Comments
 (0)