diff --git a/.gitignore b/.gitignore index df87552..87c437b 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ pnpm-lock.yaml go.mod .RData .Rhistory +program diff --git a/README.md b/README.md index 9a2bbe2..ba0117c 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,8 @@ CodeForge 是一款轻量级、高性能的桌面代码执行器,专为开发 Kotlin Lua Node.js + Objective-C + Objective-C++ PHP Python 2 Python 3 diff --git a/public/icons/objective-c.svg b/public/icons/objective-c.svg new file mode 100644 index 0000000..0af8491 --- /dev/null +++ b/public/icons/objective-c.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/public/icons/objective-cpp.svg b/public/icons/objective-cpp.svg new file mode 100644 index 0000000..7bfb08d --- /dev/null +++ b/public/icons/objective-cpp.svg @@ -0,0 +1,9 @@ + + + file_type_objectivecpp + + + + + + \ No newline at end of file diff --git a/src-tauri/src/examples/objective-c.m b/src-tauri/src/examples/objective-c.m new file mode 100644 index 0000000..9c42492 --- /dev/null +++ b/src-tauri/src/examples/objective-c.m @@ -0,0 +1,73 @@ +#import + +int main(int argc, const char * argv[]) { + @autoreleasepool { + printf("🎉 欢迎使用 CodeForge!\n"); + printf("Welcome to CodeForge!\n"); + printf("\n"); + + printf("=========================================\n"); + printf(" CodeForge Objective-C \n"); + printf("=========================================\n"); + printf("\n"); + + printf("✅ Objective-C运行成功! (Objective-C is working!)\n"); + printf("⚡ 这是Objective-C程序 (This is Objective-C program)\n"); + printf("\n"); + + int number1 = 10; + int number2 = 20; + int result = number1 + number2; + + printf("🔢 简单计算 (Simple calculation):\n"); + printf("%d + %d = %d\n", number1, number2, result); + printf("\n"); + + printf("📝 字符串操作 (String operations):\n"); + printf("平台名称 (Platform): CodeForge\n"); + printf("语言版本 (Language): Objective-C\n"); + printf("完整信息 (Full info): CodeForge - Objective-C\n"); + printf("\n"); + + printf("🍎 数组示例 (Array example):\n"); + NSArray *fruits = @[@"苹果", @"香蕉", @"橙子", @"葡萄"]; + for (int i = 0; i < fruits.count; i++) { + printf("%d. %s\n", i + 1, [fruits[i] UTF8String]); + } + printf("\n"); + + int score = 85; + printf("📊 成绩评估 (Score evaluation):\n"); + if (score >= 90) { + printf("优秀! (Excellent!)\n"); + } else if (score >= 80) { + printf("良好! (Good!)\n"); + } else if (score >= 60) { + printf("及格 (Pass)\n"); + } else { + printf("需要努力 (Need improvement)\n"); + } + printf("\n"); + + printf("🔄 循环输出 (Loop output):\n"); + for (int i = 1; i <= 5; i++) { + printf("第 %d 次输出 (Output #%d): Hello from CodeForge!\n", i, i); + } + printf("\n"); + + printf("🔁 While循环示例 (While loop example):\n"); + int counter = 1; + while (counter <= 3) { + printf("While循环: 第 %d 次\n", counter); + counter++; + } + printf("\n"); + + printf("🎯 CodeForge Objective-C代码执行完成!\n"); + printf("🎯 CodeForge Objective-C execution completed!\n"); + printf("\n"); + printf("感谢使用 CodeForge 代码执行环境! 🚀\n"); + printf("Thank you for using CodeForge! 🚀\n"); + } + return 0; +} \ No newline at end of file diff --git a/src-tauri/src/examples/objective-cpp.mm b/src-tauri/src/examples/objective-cpp.mm new file mode 100644 index 0000000..c4420cb --- /dev/null +++ b/src-tauri/src/examples/objective-cpp.mm @@ -0,0 +1,85 @@ +#import +#include +#include +#include + +int main(int argc, const char * argv[]) { + @autoreleasepool { + printf("🎉 欢迎使用 CodeForge!\n"); + printf("Welcome to CodeForge!\n"); + printf("\n"); + + printf("=========================================\n"); + printf(" CodeForge Objective-C++ \n"); + printf("=========================================\n"); + printf("\n"); + + printf("✅ Objective-C++运行成功! (Objective-C++ is working!)\n"); + printf("⚡ 这是Objective-C++程序 (This is Objective-C++ program)\n"); + printf("\n"); + + int number1 = 10; + int number2 = 20; + int result = number1 + number2; + + printf("🔢 简单计算 (Simple calculation):\n"); + printf("%d + %d = %d\n", number1, number2, result); + printf("\n"); + + printf("📝 字符串操作 (String operations):\n"); + std::string cppName = "CodeForge"; + std::string cppVersion = "Objective-C++"; + printf("平台名称 (Platform): %s\n", cppName.c_str()); + printf("语言版本 (Language): %s\n", cppVersion.c_str()); + printf("完整信息 (Full info): %s - %s\n", cppName.c_str(), cppVersion.c_str()); + printf("\n"); + + printf("🍎 数组示例 (Array example - Objective-C):\n"); + NSArray *fruits = @[@"苹果", @"香蕉", @"橙子", @"葡萄"]; + for (int i = 0; i < fruits.count; i++) { + printf("%d. %s\n", i + 1, [fruits[i] UTF8String]); + } + printf("\n"); + + printf("🍇 Vector示例 (Vector example - C++):\n"); + std::vector colors = {"红色", "蓝色", "绿色", "黄色"}; + for (size_t i = 0; i < colors.size(); i++) { + printf("%zu. %s\n", i + 1, colors[i].c_str()); + } + printf("\n"); + + int score = 85; + printf("📊 成绩评估 (Score evaluation):\n"); + if (score >= 90) { + printf("优秀! (Excellent!)\n"); + } else if (score >= 80) { + printf("良好! (Good!)\n"); + } else if (score >= 60) { + printf("及格 (Pass)\n"); + } else { + printf("需要努力 (Need improvement)\n"); + } + printf("\n"); + + printf("🔄 循环输出 (Loop output):\n"); + for (int i = 1; i <= 5; i++) { + printf("第 %d 次输出 (Output #%d): Hello from CodeForge!\n", i, i); + } + printf("\n"); + + printf("🔁 While循环示例 (While loop example):\n"); + int counter = 1; + while (counter <= 3) { + printf("While循环: 第 %d 次\n", counter); + counter++; + } + printf("\n"); + + printf("🎯 CodeForge Objective-C++代码执行完成!\n"); + printf("🎯 CodeForge Objective-C++ execution completed!\n"); + printf("\n"); + printf("感谢使用 CodeForge 代码执行环境! 🚀\n"); + printf("Thank you for using CodeForge! 🚀\n"); + } + return 0; +} \ No newline at end of file diff --git a/src-tauri/src/plugin.rs b/src-tauri/src/plugin.rs index 9c7431a..bf51bab 100644 --- a/src-tauri/src/plugin.rs +++ b/src-tauri/src/plugin.rs @@ -1,12 +1,42 @@ use crate::plugins::{LanguageInfo, PluginManager}; use log::{debug, error, info}; +use regex::Regex; use std::process::Command; use tauri::State; use tokio::sync::Mutex; pub type PluginManagerState = Mutex; -// 通用的环境信息获取函数 +fn extract_version(output: &str) -> String { + let output = output.trim(); + + let version_patterns = vec![ + r"(?i)version\s+([0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9]+)?)", + r"(?i)version\s+([0-9]+\.[0-9]+(?:\.[0-9]+)?)", + r"\bv?([0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9]+)?)\b", + r"\bv?([0-9]+\.[0-9]+(?:\.[0-9]+)?)\b", + r#""([0-9]+\.[0-9]+\.[0-9]+)""#, + ]; + + for pattern in version_patterns { + if let Ok(re) = Regex::new(pattern) { + if let Some(cap) = re.captures(output) { + if let Some(version) = cap.get(1) { + return version.as_str().to_string(); + } + } + } + } + + if let Some(first_line) = output.lines().next() { + if !first_line.is_empty() { + return first_line.to_string(); + } + } + + output.to_string() +} + #[tauri::command] pub async fn get_info( language: String, @@ -44,20 +74,27 @@ pub async fn get_info( .arg(plugin.get_path_command()) .output(); - let mut version = String::from_utf8_lossy(&version_out.stdout) + let mut raw_version = String::from_utf8_lossy(&version_out.stdout) .trim() .to_string(); - if version.is_empty() { + if raw_version.is_empty() { info!( "获取环境 -> 调用插件 [ {} ] 版本为空,通过 stderr 获取", language ); - version = String::from_utf8_lossy(&version_out.stderr) + raw_version = String::from_utf8_lossy(&version_out.stderr) .trim() .to_string(); } + let version = extract_version(&raw_version); + let final_version = if version.is_empty() { + raw_version + } else { + version + }; + let path = if let Ok(path_out) = path_result { if path_out.status.success() { String::from_utf8_lossy(&path_out.stdout).trim().to_string() @@ -71,7 +108,7 @@ pub async fn get_info( info!("获取环境 -> 调用插件 [ {} ] 完成", language); return Ok(LanguageInfo { installed: true, - version, + version: final_version, path, language: plugin.get_language_name().to_string(), }); @@ -90,7 +127,6 @@ pub async fn get_info( }) } -// 获取支持的语言列表 #[tauri::command] pub async fn get_supported_languages( plugin_manager: State<'_, PluginManagerState>, diff --git a/src-tauri/src/plugins/manager.rs b/src-tauri/src/plugins/manager.rs index 111cdf6..933e565 100644 --- a/src-tauri/src/plugins/manager.rs +++ b/src-tauri/src/plugins/manager.rs @@ -16,6 +16,8 @@ use crate::plugins::javascript_nodejs::JavaScriptNodeJsPlugin; use crate::plugins::kotlin::KotlinPlugin; use crate::plugins::lua::LuaPlugin; use crate::plugins::nodejs::NodeJSPlugin; +use crate::plugins::objective_c::ObjectiveCPlugin; +use crate::plugins::objective_cpp::ObjectiveCppPlugin; use crate::plugins::php::PHPPlugin; use crate::plugins::python2::Python2Plugin; use crate::plugins::python3::Python3Plugin; @@ -64,6 +66,8 @@ impl PluginManager { plugins.insert("cangjie".to_string(), Box::new(CangjiePlugin)); plugins.insert("haskell".to_string(), Box::new(HaskellPlugin)); plugins.insert("lua".to_string(), Box::new(LuaPlugin)); + plugins.insert("objective-c".to_string(), Box::new(ObjectiveCPlugin)); + plugins.insert("objective-cpp".to_string(), Box::new(ObjectiveCppPlugin)); plugins.insert( "javascript-nodejs".to_string(), Box::new(JavaScriptNodeJsPlugin), diff --git a/src-tauri/src/plugins/mod.rs b/src-tauri/src/plugins/mod.rs index 1715f53..61159c8 100644 --- a/src-tauri/src/plugins/mod.rs +++ b/src-tauri/src/plugins/mod.rs @@ -387,6 +387,8 @@ pub mod kotlin; pub mod lua; pub mod manager; pub mod nodejs; +pub mod objective_c; +pub mod objective_cpp; pub mod php; pub mod python2; pub mod python3; diff --git a/src-tauri/src/plugins/objective_c.rs b/src-tauri/src/plugins/objective_c.rs new file mode 100644 index 0000000..d37a17b --- /dev/null +++ b/src-tauri/src/plugins/objective_c.rs @@ -0,0 +1,85 @@ +use super::{LanguagePlugin, PluginConfig}; +use std::vec; + +pub struct ObjectiveCPlugin; + +impl LanguagePlugin for ObjectiveCPlugin { + fn get_order(&self) -> i32 { + 27 + } + + fn get_language_name(&self) -> &'static str { + "Objective-C" + } + + fn get_language_key(&self) -> &'static str { + "objective-c" + } + + fn get_file_extension(&self) -> String { + self.get_config() + .map(|config| config.extension.clone()) + .unwrap_or_else(|| "m".to_string()) + } + + fn get_version_args(&self) -> Vec<&'static str> { + vec!["--version"] + } + + fn get_path_command(&self) -> String { + "which clang".to_string() + } + + fn get_command( + &self, + _file_path: Option<&str>, + _is_version: bool, + _file_name: Option, + ) -> String { + if _is_version { + let clang_command = if self.get_execute_home().is_some() { + "./clang" + } else { + "clang" + }; + + return clang_command.to_string(); + } + + if let Some(config) = self.get_config() { + if let Some(run_cmd) = &config.run_command { + return if let Some(file_name) = _file_name { + run_cmd.replace("$filename", &file_name) + } else { + run_cmd.clone() + }; + } + } + self.get_default_command() + } + + fn get_default_config(&self) -> PluginConfig { + PluginConfig { + enabled: true, + language: String::from("objective-c"), + before_compile: Some(String::from( + "clang -framework Foundation $filename -o program", + )), + extension: String::from("m"), + execute_home: None, + run_command: Some(String::from("./program")), + after_compile: Some(String::from("rm -f program")), + template: Some(String::from( + "// Objective-C 示例代码 - CodeForge 代码执行环境\n\n", + )), + timeout: Some(30), + console_type: Some(String::from("console")), + } + } + + fn get_default_command(&self) -> String { + self.get_config() + .and_then(|config| config.run_command.clone()) + .unwrap_or_else(|| "./program".to_string()) + } +} diff --git a/src-tauri/src/plugins/objective_cpp.rs b/src-tauri/src/plugins/objective_cpp.rs new file mode 100644 index 0000000..231af12 --- /dev/null +++ b/src-tauri/src/plugins/objective_cpp.rs @@ -0,0 +1,85 @@ +use super::{LanguagePlugin, PluginConfig}; +use std::vec; + +pub struct ObjectiveCppPlugin; + +impl LanguagePlugin for ObjectiveCppPlugin { + fn get_order(&self) -> i32 { + 28 + } + + fn get_language_name(&self) -> &'static str { + "Objective-C++" + } + + fn get_language_key(&self) -> &'static str { + "objective-cpp" + } + + fn get_file_extension(&self) -> String { + self.get_config() + .map(|config| config.extension.clone()) + .unwrap_or_else(|| "mm".to_string()) + } + + fn get_version_args(&self) -> Vec<&'static str> { + vec!["--version"] + } + + fn get_path_command(&self) -> String { + "which clang++".to_string() + } + + fn get_command( + &self, + _file_path: Option<&str>, + _is_version: bool, + _file_name: Option, + ) -> String { + if _is_version { + let clang_command = if self.get_execute_home().is_some() { + "./clang++" + } else { + "clang++" + }; + + return clang_command.to_string(); + } + + if let Some(config) = self.get_config() { + if let Some(run_cmd) = &config.run_command { + return if let Some(file_name) = _file_name { + run_cmd.replace("$filename", &file_name) + } else { + run_cmd.clone() + }; + } + } + self.get_default_command() + } + + fn get_default_config(&self) -> PluginConfig { + PluginConfig { + enabled: true, + language: String::from("objective-cpp"), + before_compile: Some(String::from( + "clang++ -framework Foundation $filename -o program", + )), + extension: String::from("mm"), + execute_home: None, + run_command: Some(String::from("./program")), + after_compile: Some(String::from("rm -f program")), + template: Some(String::from( + "// Objective-C++ 示例代码 - CodeForge 代码执行环境\n\n", + )), + timeout: Some(30), + console_type: Some(String::from("console")), + } + } + + fn get_default_command(&self) -> String { + self.get_config() + .and_then(|config| config.run_command.clone()) + .unwrap_or_else(|| "./program".to_string()) + } +} diff --git a/src/composables/useCodeMirrorEditor.ts b/src/composables/useCodeMirrorEditor.ts index f6dfb07..1971fa7 100644 --- a/src/composables/useCodeMirrorEditor.ts +++ b/src/composables/useCodeMirrorEditor.ts @@ -11,7 +11,7 @@ import {xml} from '@codemirror/lang-xml' import {php} from '@codemirror/lang-php' import {shell} from '@codemirror/legacy-modes/mode/shell' import {swift} from '@codemirror/legacy-modes/mode/swift' -import {kotlin, scala} from '@codemirror/legacy-modes/mode/clike' +import {kotlin, objectiveC, objectiveCpp, scala} from '@codemirror/legacy-modes/mode/clike' import {clojure} from '@codemirror/legacy-modes/mode/clojure' import {ruby} from '@codemirror/legacy-modes/mode/ruby' import {groovy} from '@codemirror/legacy-modes/mode/groovy' @@ -219,6 +219,10 @@ export function useCodeMirrorEditor(props: Props) return StreamLanguage.define(haskell) case 'lua': return StreamLanguage.define(lua) + case 'objective-c': + return StreamLanguage.define(objectiveC) + case 'objective-cpp': + return StreamLanguage.define(objectiveCpp) default: return null } @@ -287,7 +291,6 @@ export function useCodeMirrorEditor(props: Props) } } - // 其余代码完全保持不变... const loadEditorConfig = async () => { try { const globalConfig = await invoke('get_app_config') diff --git a/src/composables/useStatusBar.ts b/src/composables/useStatusBar.ts index 4f6e256..63244ba 100644 --- a/src/composables/useStatusBar.ts +++ b/src/composables/useStatusBar.ts @@ -1,6 +1,6 @@ -import { type Ref } from 'vue' -import { CheckCircle, Loader2, XCircle } from 'lucide-vue-next' -import { EnvInfo } from '../types/app.ts' +import {type Ref} from 'vue' +import {CheckCircle, Loader2, XCircle} from 'lucide-vue-next' +import {EnvInfo} from '../types/app.ts' export function useStatusBar(envInfo: Ref, isLoading: Ref) { @@ -31,14 +31,14 @@ export function useStatusBar(envInfo: Ref, isLoading: Ref) // 计算状态文本 const getStatusText = () => { if (isLoading.value) { - return `${ envInfo.value.language }: 检查环境中...` + return `${envInfo.value.language}: 检查环境中...` } if (envInfo.value.installed) { - return `${ envInfo.value.language }: ${ envInfo.value.version }` + return `${envInfo.value.language}: ${envInfo.value.version || '--'}` } else { - return `${ envInfo.value.language }: 环境未安装` + return `${envInfo.value.language}: 环境未安装` } }