Skip to content

Commit 36156cb

Browse files
authored
Merge pull request #38 from qianmoQ/dev-25.0.2
feat (language): 支持 C 语言
2 parents abd83da + d1a3c3c commit 36156cb

14 files changed

Lines changed: 282 additions & 90 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ CodeForge 是一款轻量级、高性能的桌面代码执行器,专为开发
2222

2323
## 支持的语言
2424

25+
- **C**
2526
- **Clojure**
2627
- **Go**
2728
- **Java**

docs/content/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ stats:
4747
description: 我们取得的成就
4848
items:
4949
- label: GitHub Stars
50-
value: 5+
50+
value: 10+
5151
- label: 跨平台性(Windows、macOS)
5252
value: 3+
5353
- label: 支持的语言
54-
value: 5+
54+
value: 10+
5555
- label: 客户满意度
5656
value: 100%
5757

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
},
1212
"dependencies": {
1313
"@babel/runtime": "^7.28.2",
14+
"@codemirror/lang-cpp": "^6.0.3",
1415
"@codemirror/lang-go": "^6.0.1",
1516
"@codemirror/lang-java": "^6.0.2",
1617
"@codemirror/lang-javascript": "^6.2.4",

public/icons/c.svg

Lines changed: 1 addition & 0 deletions
Loading

src-tauri/src/execution.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,12 @@ pub async fn execute_code(
8181
.ok_or_else(|| format!("Unsupported language: {}", request.language))?;
8282

8383
let temp_dir = std::env::temp_dir();
84-
let file_path = temp_dir.join(format!(
84+
let file_name = format!(
8585
"Codeforge_{}.{}",
8686
request.language,
8787
plugin.get_file_extension()
88-
));
88+
);
89+
let file_path = temp_dir.join(file_name.clone());
8990

9091
// 写入代码到临时文件
9192
fs::write(&file_path, &request.code)
@@ -103,7 +104,7 @@ pub async fn execute_code(
103104

104105
let start_time = std::time::Instant::now();
105106

106-
let cmd = plugin.get_command(None);
107+
let cmd = plugin.get_command(None, false, Some(file_path.to_string_lossy().to_string()));
107108
let args = plugin.get_execute_args(file_path.to_str().unwrap());
108109
info!(
109110
"执行代码 -> 调用插件 [ {} ] 执行命令 {} 携带参数 {}",

src-tauri/src/plugin.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub async fn get_info(
2828
format!("Pre-execution hook failed: {}", e)
2929
})?;
3030

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

3434
let version_output = Command::new(&cmd).args(plugin.get_version_args()).output();
@@ -82,7 +82,10 @@ pub async fn get_info(
8282
Ok(LanguageInfo {
8383
installed: false,
8484
version: "Not found".to_string(),
85-
path: format!("Not found - tried: {:?}", plugin.get_command(None)),
85+
path: format!(
86+
"Not found - tried: {:?}",
87+
plugin.get_command(None, true, None)
88+
),
8689
language: plugin.get_language_name().to_string(),
8790
})
8891
}

src-tauri/src/plugins/c.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use super::{LanguagePlugin, PluginConfig};
2+
use std::vec;
3+
4+
pub struct CPlugin;
5+
6+
impl LanguagePlugin for CPlugin {
7+
fn get_order(&self) -> i32 {
8+
12
9+
}
10+
11+
fn get_language_name(&self) -> &'static str {
12+
"C"
13+
}
14+
15+
fn get_language_key(&self) -> &'static str {
16+
"c"
17+
}
18+
19+
fn get_file_extension(&self) -> String {
20+
self.get_config()
21+
.map(|config| config.extension.clone())
22+
.unwrap_or_else(|| "c".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 gcc".to_string()
31+
}
32+
33+
fn get_command(
34+
&self,
35+
_file_path: Option<&str>,
36+
_is_version: bool,
37+
_file_name: Option<String>,
38+
) -> String {
39+
if _is_version {
40+
// 获取版本信息时,返回编译器命令
41+
return "gcc".to_string();
42+
}
43+
44+
// 执行代码时
45+
if let Some(config) = self.get_config() {
46+
if let Some(run_cmd) = &config.run_command {
47+
return if let Some(file_name) = _file_name {
48+
run_cmd.replace("$filename", &file_name)
49+
} else {
50+
// 执行代码但没有文件名时,返回原始命令让框架处理 $filename 替换
51+
run_cmd.clone()
52+
};
53+
}
54+
}
55+
self.get_default_command()
56+
}
57+
58+
fn get_default_config(&self) -> PluginConfig {
59+
PluginConfig {
60+
enabled: true,
61+
language: String::from("c"),
62+
before_compile: Some(String::from("gcc $filename -o $filename")),
63+
extension: String::from("c"),
64+
execute_home: None,
65+
run_command: Some(String::from("$filename")),
66+
after_compile: Some(String::from("rm -f $filename")),
67+
template: Some(String::from(
68+
"#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n\n// C 示例代码 - CodeForge 代码执行环境\n\n// 函数声明\nvoid greet_user(const char* name);\nint add_numbers(int a, int b);\nvoid print_array(int arr[], int size);\nint fibonacci(int n);\n\nint main() {\n printf(\"🎉 欢迎使用 CodeForge!\\n\");\n printf(\"Welcome to CodeForge!\\n\");\n printf(\"\\n\");\n\n printf(\"=========================================\\n\");\n printf(\" CodeForge C \\n\");\n printf(\"=========================================\\n\");\n printf(\"\\n\");\n\n // 基本输出示例\n printf(\"✅ C 运行成功! (C is working!)\\n\");\n printf(\"⚡ 这是 C 程序 (This is C program)\\n\");\n printf(\"\\n\");\n\n // 变量操作\n const char* name = \"CodeForge\";\n const char* version = \"C\";\n int number1 = 10;\n int number2 = 20;\n int result = add_numbers(number1, number2);\n\n printf(\"🔢 简单计算 (Simple calculation):\\n\");\n printf(\"%d + %d = %d\\n\", number1, number2, result);\n printf(\"\\n\");\n\n // 字符串操作\n printf(\"📝 字符串操作 (String operations):\\n\");\n printf(\"平台名称 (Platform): %s\\n\", name);\n printf(\"语言版本 (Language): %s\\n\", version);\n printf(\"完整信息 (Full info): %s - %s\\n\", name, version);\n printf(\"\\n\");\n\n // 循环示例\n printf(\"🔄 循环输出 (Loop output):\\n\");\n for (int i = 1; i <= 5; i++) {\n printf(\"第 %d 次输出 (Output #%d): Hello from CodeForge!\\n\", i, i);\n }\n printf(\"\\n\");\n\n // 数组操作\n printf(\"🍎 数组示例 (Array example):\\n\");\n char* fruits[] = {\"苹果\", \"香蕉\", \"橙子\", \"葡萄\"};\n int fruits_count = sizeof(fruits) / sizeof(fruits[0]);\n for (int i = 0; i < fruits_count; i++) {\n printf(\"%d. %s\\n\", i + 1, fruits[i]);\n }\n printf(\"\\n\");\n\n // 条件判断\n int score = 85;\n printf(\"📊 成绩评估 (Score evaluation):\\n\");\n if (score >= 90) {\n printf(\"优秀! (Excellent!)\\n\");\n } else if (score >= 80) {\n printf(\"良好! (Good!)\\n\");\n } else if (score >= 60) {\n printf(\"及格 (Pass)\\n\");\n } else {\n printf(\"需要努力 (Need improvement)\\n\");\n }\n printf(\"\\n\");\n\n // 指针示例\n printf(\"🔍 指针示例 (Pointer example):\\n\");\n int value = 42;\n int* ptr = &value;\n printf(\"值: %d (Value: %d)\\n\", value, value);\n printf(\"地址: %p (Address: %p)\\n\", (void*)ptr, (void*)ptr);\n printf(\"通过指针访问: %d (Access via pointer: %d)\\n\", *ptr, *ptr);\n printf(\"\\n\");\n\n // 函数示例\n printf(\"🎭 函数示例 (Function example):\\n\");\n greet_user(\"CodeForge用户\");\n printf(\"\\n\");\n\n // 内存分配示例\n printf(\"💾 动态内存分配 (Dynamic memory allocation):\\n\");\n int* dynamic_array = (int*)malloc(5 * sizeof(int));\n if (dynamic_array != NULL) {\n for (int i = 0; i < 5; i++) {\n dynamic_array[i] = (i + 1) * 10;\n }\n printf(\"动态数组: \");\n print_array(dynamic_array, 5);\n free(dynamic_array);\n printf(\"内存已释放\\n\");\n }\n printf(\"\\n\");\n\n // 结构体示例\n printf(\"👤 结构体示例 (Struct example):\\n\");\n struct Person {\n char name[50];\n int age;\n float height;\n };\n \n struct Person person;\n strcpy(person.name, \"张三\");\n person.age = 25;\n person.height = 175.5;\n \n printf(\"姓名: %s, 年龄: %d, 身高: %.1f cm\\n\", \n person.name, person.age, person.height);\n printf(\"\\n\");\n\n // 递归示例\n printf(\"🔄 递归示例 (Recursion example):\\n\");\n int fib_n = 7;\n int fib_result = fibonacci(fib_n);\n printf(\"斐波那契数列第%d项: %d\\n\", fib_n, fib_result);\n printf(\"\\n\");\n\n // 数学库示例\n printf(\"📐 数学库示例 (Math library example):\\n\");\n double angle = 45.0;\n double radians = angle * M_PI / 180.0;\n printf(\"sin(%.0f°) = %.4f\\n\", angle, sin(radians));\n printf(\"cos(%.0f°) = %.4f\\n\", angle, cos(radians));\n printf(\"sqrt(16) = %.2f\\n\", sqrt(16));\n printf(\"\\n\");\n\n // 位操作示例\n printf(\"🔧 位操作示例 (Bitwise operations):\\n\");\n int a = 12; // 1100 in binary\n int b = 10; // 1010 in binary\n printf(\"%d & %d = %d (AND)\\n\", a, b, a & b);\n printf(\"%d | %d = %d (OR)\\n\", a, b, a | b);\n printf(\"%d ^ %d = %d (XOR)\\n\", a, b, a ^ b);\n printf(\"~%d = %d (NOT)\\n\", a, ~a);\n printf(\"\\n\");\n\n // 枚举示例\n printf(\"📋 枚举示例 (Enum example):\\n\");\n enum Weekday {\n MONDAY = 1, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY\n };\n enum Weekday today = WEDNESDAY;\n printf(\"今天是星期%d\\n\", today);\n printf(\"\\n\");\n\n printf(\"🎯 CodeForge C 代码执行完成!\\n\");\n printf(\"🎯 CodeForge C execution completed!\\n\");\n printf(\"\\n\");\n printf(\"感谢使用 CodeForge 代码执行环境! 🚀\\n\");\n printf(\"Thank you for using CodeForge! 🚀\\n\");\n \n return 0;\n}\n\n// 函数实现\nvoid greet_user(const char* name) {\n printf(\"Hello, %s! 👋\\n\", name);\n}\n\nint add_numbers(int a, int b) {\n return a + b;\n}\n\nvoid print_array(int arr[], int size) {\n for (int i = 0; i < size; i++) {\n printf(\"%d \", arr[i]);\n }\n printf(\"\\n\");\n}\n\nint fibonacci(int n) {\n if (n <= 1) {\n return n;\n }\n return fibonacci(n - 1) + fibonacci(n - 2);\n}",
69+
)),
70+
timeout: Some(30),
71+
}
72+
}
73+
74+
fn get_default_command(&self) -> String {
75+
self.get_config()
76+
.and_then(|config| config.run_command.clone())
77+
.unwrap_or_else(|| "gcc".to_string())
78+
}
79+
}

src-tauri/src/plugins/manager.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::{LanguagePlugin, PluginConfig};
2+
use crate::plugins::c::CPlugin;
23
use crate::plugins::clojure::ClojurePlugin;
34
use crate::plugins::go::GoPlugin;
45
use crate::plugins::java::JavaPlugin;
@@ -31,6 +32,7 @@ impl PluginManager {
3132
plugins.insert("scala".to_string(), Box::new(ScalaPlugin));
3233
plugins.insert("kotlin".to_string(), Box::new(KotlinPlugin));
3334
plugins.insert("clojure".to_string(), Box::new(ClojurePlugin));
35+
plugins.insert("c".to_string(), Box::new(CPlugin));
3436

3537
Self { plugins }
3638
}
@@ -74,7 +76,7 @@ impl PluginManager {
7476
self.get_plugin(language).map(|plugin| PluginInfo {
7577
name: plugin.get_language_name().to_string(),
7678
file_extension: plugin.get_file_extension(),
77-
available_commands: vec![plugin.get_command(None).to_string()],
79+
available_commands: vec![plugin.get_command(None, true, None).to_string()],
7880
})
7981
}
8082

@@ -85,7 +87,7 @@ impl PluginManager {
8587
.map(|plugin| PluginInfo {
8688
name: plugin.get_language_name().to_string(),
8789
file_extension: plugin.get_file_extension(),
88-
available_commands: vec![plugin.get_command(None).to_string()],
90+
available_commands: vec![plugin.get_command(None, true, None).to_string()],
8991
})
9092
.collect()
9193
}

src-tauri/src/plugins/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,12 @@ pub trait LanguagePlugin: Send + Sync {
7676
}
7777

7878
// 获取插件支持的命令
79-
fn get_command(&self, file_path: Option<&str>) -> String {
79+
fn get_command(
80+
&self,
81+
file_path: Option<&str>,
82+
_is_version: bool,
83+
_file_name: Option<String>,
84+
) -> String {
8085
if let Some(config) = self.get_config() {
8186
if let Some(run_cmd) = &config.run_command {
8287
return if let Some(path) = file_path {
@@ -340,6 +345,7 @@ pub trait LanguagePlugin: Send + Sync {
340345
}
341346

342347
// 重新导出子模块
348+
pub mod c;
343349
pub mod clojure;
344350
pub mod go;
345351
pub mod java;

src/App.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
<!-- 代码编辑器 -->
1616
<div class="flex-1 flex flex-col overflow-hidden">
1717
<div class="bg-gray-100 px-4 py-2 border-b border-gray-200 flex items-center justify-between flex-shrink-0">
18-
<h2 class="text-sm font-medium text-gray-700">{{ getLanguageDisplayName(currentLanguage) }} 代码编辑器</h2>
18+
<div class="flex items-center space-x-3">
19+
<img :src="`/icons/${currentLanguage.replace(/\d+$/, '')}.svg`" class="w-5 h-5" :alt="currentLanguage"/>
20+
<h2 class="text-sm font-medium text-gray-700">{{ getLanguageDisplayName(currentLanguage) }} 代码编辑器</h2>
21+
</div>
22+
1923
<div class="flex items-center space-x-2 text-xs text-gray-500">
2024
<span><strong>{{ (code || '').length }}</strong> 字符</span>
2125
<span><strong>{{ (code || '').split('\n').length }}</strong> 行</span>

0 commit comments

Comments
 (0)