From adafb303f4473c09f552ecee3968823763c52450 Mon Sep 17 00:00:00 2001 From: qianmoQ Date: Thu, 4 Sep 2025 13:07:01 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat=20(language):=20=E6=94=AF=E6=8C=81=20H?= =?UTF-8?q?askell=20=E8=AF=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/src/examples/haskell.hs | 80 +++++++++++++++++++++++++ src-tauri/src/plugins/haskell.rs | 99 +++++++++++++++++++++++++++++++ src-tauri/src/plugins/manager.rs | 2 + src-tauri/src/plugins/mod.rs | 1 + src-tauri/tauri.conf.json | 2 +- 8 files changed, 186 insertions(+), 4 deletions(-) create mode 100644 src-tauri/src/examples/haskell.hs create mode 100644 src-tauri/src/plugins/haskell.rs diff --git a/package.json b/package.json index c888947..bcd126a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "codeforge", "private": true, - "version": "25.0.3", + "version": "25.0.4", "type": "module", "scripts": { "dev": "vite", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 3c2974f..42589f1 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "CodeForge" -version = "25.0.3" +version = "25.0.4" dependencies = [ "chrono", "dirs", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 1659971..6d65b0b 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "CodeForge" -version = "25.0.3" +version = "25.0.4" description = "CodeForge 是一款轻量级、高性能的桌面代码执行器,专为开发者、学生和编程爱好者设计。" authors = ["devlive-community"] edition = "2024" diff --git a/src-tauri/src/examples/haskell.hs b/src-tauri/src/examples/haskell.hs new file mode 100644 index 0000000..c8b7914 --- /dev/null +++ b/src-tauri/src/examples/haskell.hs @@ -0,0 +1,80 @@ +-- Haskell示例代码 - CodeForge 代码执行环境 + +import Data.List (intercalate) + +main :: IO () +main = do + putStrLn "🎉 欢迎使用 CodeForge!" + putStrLn "Welcome to CodeForge!" + putStrLn "" + + putStrLn "=========================================" + putStrLn " CodeForge Haskell " + putStrLn "=========================================" + putStrLn "" + + -- 基本输出示例 + putStrLn "✅ Haskell运行成功! (Haskell is working!)" + putStrLn "⚡ 这是Haskell程序 (This is Haskell program)" + putStrLn "" + + -- 变量操作 + let name = "CodeForge" + version = "Haskell" + number1 = 10 + number2 = 20 + result = number1 + number2 + + putStrLn "🔢 简单计算 (Simple calculation):" + putStrLn $ show number1 ++ " + " ++ show number2 ++ " = " ++ show result + putStrLn "" + + -- 字符串操作 + putStrLn "📝 字符串操作 (String operations):" + putStrLn $ "平台名称 (Platform): " ++ name + putStrLn $ "语言版本 (Language): " ++ version + putStrLn $ "完整信息 (Full info): " ++ name ++ " - " ++ version + putStrLn "" + + -- 列表操作 + putStrLn "🍎 列表示例 (List example):" + let fruits = ["苹果", "香蕉", "橙子", "葡萄"] + mapM_ (\(i, fruit) -> putStrLn $ show (i + 1) ++ ". " ++ fruit) (zip [0..] fruits) + putStrLn "" + + -- 条件判断 + let score = 85 + putStrLn "📊 成绩评估 (Score evaluation):" + putStrLn $ evaluateScore score + putStrLn "" + + -- 循环示例 + putStrLn "🔄 循环输出 (Loop output):" + mapM_ (\i -> putStrLn $ "第 " ++ show i ++ " 次输出 (Output #" ++ show i ++ "): Hello from CodeForge!") [1..5] + putStrLn "" + + -- 递归示例 (模拟while循环) + putStrLn "🔁 递归示例 (Recursion example):" + countDown 3 + putStrLn "" + + putStrLn "🎯 CodeForge Haskell代码执行完成!" + putStrLn "🎯 CodeForge Haskell execution completed!" + putStrLn "" + putStrLn "感谢使用 CodeForge 代码执行环境! 🚀" + putStrLn "Thank you for using CodeForge! 🚀" + +-- 评估分数的函数 +evaluateScore :: Int -> String +evaluateScore score + | score >= 90 = "优秀! (Excellent!)" + | score >= 80 = "良好! (Good!)" + | score >= 60 = "及格 (Pass)" + | otherwise = "需要努力 (Need improvement)" + +-- 递归倒计数函数 (模拟while循环) +countDown :: Int -> IO () +countDown 0 = return () +countDown n = do + putStrLn $ "递归循环: 第 " ++ show (4 - n) ++ " 次" + countDown (n - 1) \ No newline at end of file diff --git a/src-tauri/src/plugins/haskell.rs b/src-tauri/src/plugins/haskell.rs new file mode 100644 index 0000000..561a5b5 --- /dev/null +++ b/src-tauri/src/plugins/haskell.rs @@ -0,0 +1,99 @@ +use super::{LanguagePlugin, PluginConfig}; +use std::vec; + +pub struct HaskellPlugin; + +impl LanguagePlugin for HaskellPlugin { + fn get_order(&self) -> i32 { + 25 + } + + fn get_language_name(&self) -> &'static str { + "Haskell" + } + + fn get_language_key(&self) -> &'static str { + "haskell" + } + + fn get_file_extension(&self) -> String { + self.get_config() + .map(|config| config.extension.clone()) + .unwrap_or_else(|| "hs".to_string()) + } + + fn get_version_args(&self) -> Vec<&'static str> { + vec!["--version"] + } + + fn get_path_command(&self) -> String { + "which ghc".to_string() + } + + fn get_command( + &self, + _file_path: Option<&str>, + _is_version: bool, + _file_name: Option, + ) -> String { + if _is_version { + let ghc_command = if self.get_execute_home().is_some() { + "./ghc" + } else { + "ghc" + }; + + return ghc_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 { + // 执行代码但没有文件名时,返回原始命令让框架处理 $filename 替换 + run_cmd.clone() + }; + } + } + self.get_default_command() + } + + fn get_execute_args(&self, file_path: &str) -> Vec { + let ghc_command = if self.get_execute_home().is_some() { + "./ghc" + } else { + "ghc" + }; + + // 对于 Haskell,通常先编译再运行 + // 这里假设编译后的可执行文件名为 main + let cmd = format!("{} {} -o main && ./main", ghc_command, file_path); + + vec!["-c".to_string(), cmd] + } + + fn get_default_config(&self) -> PluginConfig { + PluginConfig { + enabled: true, + language: String::from("haskell"), + before_compile: Some(String::from("ghc $filename -o /tmp/main")), + extension: String::from("hs"), + execute_home: None, + run_command: Some(String::from("/tmp/main")), + after_compile: Some(String::from("rm -f /tmp/main /tmp/main.hi /tmp/main.o")), + template: Some(String::from( + "-- 在这里输入 Haskell 代码\n-- Haskell - 纯函数式编程语言\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(|| "./main".to_string()) + } +} diff --git a/src-tauri/src/plugins/manager.rs b/src-tauri/src/plugins/manager.rs index 6344962..64271a4 100644 --- a/src-tauri/src/plugins/manager.rs +++ b/src-tauri/src/plugins/manager.rs @@ -7,6 +7,7 @@ use crate::plugins::cpp::CppPlugin; use crate::plugins::css::CssPlugin; use crate::plugins::go::GoPlugin; use crate::plugins::groovy::GroovyPlugin; +use crate::plugins::haskell::HaskellPlugin; use crate::plugins::html::HtmlPlugin; use crate::plugins::java::JavaPlugin; use crate::plugins::javascript_browser::JavaScriptBrowserPlugin; @@ -60,6 +61,7 @@ impl PluginManager { plugins.insert("php".to_string(), Box::new(PHPPlugin)); plugins.insert("r".to_string(), Box::new(RPlugin)); plugins.insert("cangjie".to_string(), Box::new(CangjiePlugin)); + plugins.insert("haskell".to_string(), Box::new(HaskellPlugin)); 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 a845ae6..8253379 100644 --- a/src-tauri/src/plugins/mod.rs +++ b/src-tauri/src/plugins/mod.rs @@ -377,6 +377,7 @@ pub mod cpp; pub mod css; pub mod go; pub mod groovy; +pub mod haskell; pub mod html; pub mod java; pub mod javascript_browser; diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index e2b3416..ded4215 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "CodeForge", - "version": "25.0.3", + "version": "25.0.4", "identifier": "org.devlive.codeforge", "build": { "beforeDevCommand": "pnpm dev", From 3eab0f4312b9ee8e9e871d9394c41a25300cdb3f Mon Sep 17 00:00:00 2001 From: qianmoQ Date: Thu, 4 Sep 2025 13:13:21 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat=20(language):=20=E6=B7=BB=E5=8A=A0=20H?= =?UTF-8?q?askell=20=E8=AF=AD=E8=A8=80=E7=9B=B8=E5=85=B3=E8=B5=84=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + public/icons/haskell.svg | 5 +++++ src/composables/useCodeMirrorEditor.ts | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 public/icons/haskell.svg diff --git a/README.md b/README.md index c7a6368..391a3f2 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ CodeForge 是一款轻量级、高性能的桌面代码执行器,专为开发 CSS Go Groovy + Haskell HTML Java JavaScript (Browser) diff --git a/public/icons/haskell.svg b/public/icons/haskell.svg new file mode 100644 index 0000000..af16d5f --- /dev/null +++ b/public/icons/haskell.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/composables/useCodeMirrorEditor.ts b/src/composables/useCodeMirrorEditor.ts index 3cfb0c0..78e6ced 100644 --- a/src/composables/useCodeMirrorEditor.ts +++ b/src/composables/useCodeMirrorEditor.ts @@ -16,6 +16,7 @@ import {clojure} from '@codemirror/legacy-modes/mode/clojure' import {ruby} from '@codemirror/legacy-modes/mode/ruby' import {groovy} from '@codemirror/legacy-modes/mode/groovy' import {r} from "@codemirror/legacy-modes/mode/r" +import {haskell} from "@codemirror/legacy-modes/mode/haskell" import { abcdef, abyss, @@ -213,6 +214,8 @@ export function useCodeMirrorEditor(props: Props) return php() case 'r': return StreamLanguage.define(r) + case 'haskell': + return StreamLanguage.define(haskell) default: return null }