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
2 changes: 1 addition & 1 deletion src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ async fn get_info(
#[tauri::command]
async fn get_supported_languages(
plugin_manager: State<'_, PluginManagerState>,
) -> Result<Vec<String>, String> {
) -> Result<Vec<serde_json::Value>, String> {
let manager = plugin_manager.lock().await;
Ok(manager.get_supported_languages())
}
Expand Down
12 changes: 10 additions & 2 deletions src-tauri/src/plugins/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,16 @@ impl PluginManager {
self.plugins.get(language).map(|plugin| plugin.as_ref())
}

pub fn get_supported_languages(&self) -> Vec<String> {
self.plugins.keys().cloned().collect()
pub fn get_supported_languages(&self) -> Vec<serde_json::Value> {
self.plugins
.iter()
.map(|(key, plugin)| {
serde_json::json!({
"name": plugin.get_language_name(),
"value": key
})
})
.collect()
}

#[allow(dead_code)]
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/plugins/python2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl LanguagePlugin for Python2Plugin {
fn post_execute_hook(&self, result: &mut ExecutionResult) -> Result<(), String> {
// Python 特定的后处理
if result.success && result.stdout.is_empty() && result.stderr.is_empty() {
result.stdout = "Code executed successfully (no output)".to_string();
result.stdout = "代码执行成功 (无输出)".to_string();
}

// 清理 Python 特定的错误信息
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/plugins/python3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl LanguagePlugin for Python3Plugin {
fn post_execute_hook(&self, result: &mut ExecutionResult) -> Result<(), String> {
// Python 特定的后处理
if result.success && result.stdout.is_empty() && result.stderr.is_empty() {
result.stdout = "Code executed successfully (no output)".to_string();
result.stdout = "代码执行成功 (无输出)".to_string();
}

// 清理 Python 特定的错误信息
Expand Down
3 changes: 2 additions & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
{
"title": "CodeForge",
"width": 1800,
"height": 1200
"height": 1200,
"additionalBrowserArgs": "--disable-context-menu"
}
],
"security": {
Expand Down
129 changes: 112 additions & 17 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@
<div class="h-screen flex flex-col bg-gray-50">
<AppHeader :is-running="isRunning"
:env-installed="envInfo.installed"
:supported-languages="supportedLanguages"
:current-language="currentLanguage"
@run-code="runCode"
@clear-output="clearOutput"
@language-change="handleLanguageChange"
@show-settings="showSettings = true">
</AppHeader>

<div class="flex-1 flex overflow-hidden">
<!-- 代码编辑器 -->
<div class="flex-1 flex flex-col">
<div class="bg-gray-100 px-4 py-2 border-b border-gray-200 flex items-center justify-between">
<h2 class="text-sm font-medium text-gray-700">Python 代码编辑器</h2>
<h2 class="text-sm font-medium text-gray-700">{{ getLanguageDisplayName(currentLanguage) }} 代码编辑器</h2>
<div class="text-xs text-gray-500">
<strong>{{ code.length }}</strong> 字符, <strong>{{ code.split('\n').length }}</strong> 行
</div>
</div>
<CodeEditor v-model="code"
language="python"
class="flex-1">
</CodeEditor>
<CodeEditor v-model="code" class="flex-1" :language="currentLanguage"/>
</div>

<!-- 输出 -->
Expand All @@ -35,10 +35,7 @@
</div>

<!-- 状态栏 -->
<StatusBar :env-info="envInfo"
:execution-time="lastExecutionTime"
:code-length="code.length">
</StatusBar>
<StatusBar :env-info="envInfo" :execution-time="lastExecutionTime" :code-length="code.length"/>

<!-- 通知信息 -->
<Toast v-if="toast.show"
Expand Down Expand Up @@ -87,7 +84,15 @@ interface EnvInfo
language: string
}

const code = ref(`# Welcome to CodeForge!
interface Language
{
name: string
value: string
}

// 代码模板
const codeTemplates: Record<string, string> = {
python: `# Welcome to CodeForge!
# Write your Python code here and click Run to execute

print("Hello, CodeForge!")
Expand All @@ -102,14 +107,52 @@ print(f"The result of {x} + {y} = {result}")
numbers = [1, 2, 3, 4, 5]
squared = [n**2 for n in numbers]
print(f"Original: {numbers}")
print(f"Squared: {squared}")`)
print(f"Squared: {squared}")`,

python2: `# Welcome to CodeForge - Python 2!
# Write your Python 2 code here and click Run to execute

print "Hello, CodeForge from Python 2!"

# Example: Simple calculation
x = 10
y = 20
result = x + y
print "The result of %d + %d = %d" % (x, y, result)

# Example: List operations
numbers = [1, 2, 3, 4, 5]
squared = [n**2 for n in numbers]
print "Original:", numbers
print "Squared:", squared`,

python3: `# Welcome to CodeForge - Python 3!
# Write your Python 3 code here and click Run to execute

print("Hello, CodeForge from Python 3!")

# Example: Simple calculation
x = 10
y = 20
result = x + y
print(f"The result of {x} + {y} = {result}")

# Example: List operations
numbers = [1, 2, 3, 4, 5]
squared = [n**2 for n in numbers]
print(f"Original: {numbers}")
print(f"Squared: {squared}")`
}

const code = ref('')
const currentLanguage = ref('python')
const output = ref('')
const isRunning = ref(false)
const isSuccess = ref(false)
const lastExecutionTime = ref(0)
const activeTab = ref('output')
const showSettings = ref(false)
const supportedLanguages = ref<Language[]>([])

const envInfo = ref<EnvInfo>({
installed: false,
Expand All @@ -126,15 +169,17 @@ const toast = ref({

const showToast = (message: string, type: 'success' | 'error' | 'info' = 'success') => {
toast.value = { show: true, message, type }
setTimeout(() => {
toast.value.show = false
}, 3000)
}

const getLanguageDisplayName = (languageValue: string) => {
const language = supportedLanguages.value.find(lang => lang.value === languageValue)
return language ? language.name : languageValue
}

const refreshEnvInfo = async () => {
try {
const info: LanguageInfo = await invoke('get_info', {
language: 'python2'
language: currentLanguage.value
})

envInfo.value = {
Expand All @@ -150,11 +195,48 @@ const refreshEnvInfo = async () => {
installed: false,
version: 'Error',
path: 'Error',
language: 'python2'
language: currentLanguage.value
}
}
}

const getSupportedLanguages = async () => {
try {
const languages = await invoke<Language[]>('get_supported_languages')
supportedLanguages.value = languages.map((language) => ({
name: language.name,
value: language.value
}))

// 设置默认语言
if (supportedLanguages.value.length > 0 && !currentLanguage.value) {
currentLanguage.value = supportedLanguages.value[0].value
}
}
catch (error) {
console.error('Error getting supported languages:', error)
supportedLanguages.value = []
}
}

const handleLanguageChange = async (newLanguage: string) => {
currentLanguage.value = newLanguage

// 更新代码模板
code.value = codeTemplates[newLanguage] || `# ${ getLanguageDisplayName(newLanguage) } Code
# Write your code here...

print("Hello from ${ getLanguageDisplayName(newLanguage) }!")`

// 清空输出
output.value = ''

// 刷新环境信息
await refreshEnvInfo()

showToast(`已切换到 ${ getLanguageDisplayName(newLanguage) }`, 'info')
}

const runCode = async () => {
if (!envInfo.value.installed) {
showToast(`${ envInfo.value.language } 环境未安装`, 'error')
Expand All @@ -168,7 +250,7 @@ const runCode = async () => {
const result: ExecutionResult = await invoke('execute_code', {
request: {
code: code.value,
language: 'python2'
language: currentLanguage.value
}
})

Expand Down Expand Up @@ -201,7 +283,20 @@ const clearOutput = () => {
showToast('输出已清空', 'info')
}

window.addEventListener("contextmenu", (e) => e.preventDefault(), false);

onMounted(async () => {
await getSupportedLanguages()

// 设置初始代码模板
if (supportedLanguages.value.length > 0) {
currentLanguage.value = supportedLanguages.value[0].value
code.value = codeTemplates[currentLanguage.value] || codeTemplates.python
}
else {
code.value = codeTemplates.python
}

await refreshEnvInfo()
})
</script>
49 changes: 40 additions & 9 deletions src/components/AppHeader.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
<template>
<div class="bg-white border-b border-gray-200 px-4 py-3 flex items-center justify-between">
<div class="flex items-center space-x-3">
<div class="w-12 h-12 bg-gradient-to-br rounded-lg flex items-center justify-center">
<img src="/codeforge.svg" alt="CodeForge">
</div>
<div>
<h1 class="text-lg font-bold text-gray-800">CodeForge</h1>
<p class="text-xs text-gray-500">轻量级、高性能的桌面代码执行器,专为开发者、学生和编程爱好者设计。</p>
<div class="relative">
<!-- 自定义下拉选择器 -->
<div class="relative">
<select v-model="selectedLanguage"
class="w-32 h-10 backdrop-blur-sm appearance-none bg-white/90 text-gray-800 text-sm font-medium border border-gray-200 rounded-lg px-2.5 pr-8 cursor-pointer focus:outline-none hover:bg-white/95 transition-all duration-200"
:class="{ 'opacity-50 cursor-not-allowed': isRunning }"
:disabled="isRunning"
@change="handleLanguageChange">
<option v-for="language in supportedLanguages"
class="text-gray-800 bg-white py-3 px-3 text-sm font-medium hover:bg-blue-50 hover:text-blue-800 focus:bg-blue-100 focus:text-blue-900 border-b border-gray-100 last:border-b-0"
:key="language.value"
:value="language.value">
{{ language.name }}
</option>
</select>
</div>
</div>
</div>

Expand All @@ -33,16 +43,37 @@
</template>

<script setup lang="ts">
import { ref, watch } from 'vue'
import { Play, Square, Trash2 } from 'lucide-vue-next'

defineProps<{
interface Language
{
name: string
value: string
}

const props = defineProps<{
isRunning: boolean
envInstalled: boolean
supportedLanguages: Language[]
currentLanguage: string
}>()

defineEmits<{
const emit = defineEmits<{
'run-code': []
'clear-output': []
'show-settings': []
'language-change': [language: string]
}>()
</script>

const selectedLanguage = ref(props.currentLanguage)

// 监听外部语言变化
watch(() => props.currentLanguage, (newLanguage) => {
selectedLanguage.value = newLanguage
})

const handleLanguageChange = () => {
emit('language-change', selectedLanguage.value)
}
</script>
5 changes: 3 additions & 2 deletions src/components/StatusBar.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<template>
<div class="bg-blue-600 text-white px-4 py-2 text-sm flex items-center justify-between">
<div class="text-white px-3.5 py-1 text-sm flex items-center justify-between"
:class="[envInfo.installed ? 'bg-green-500' : 'bg-red-500']">
<div class="flex items-center space-x-6">
<div class="flex items-center space-x-2">
<component :is="envInfo.installed ? CheckCircle : XCircle"
:class="envInfo.installed ? 'text-green-300' : 'text-red-300'"
:class="envInfo.installed ? 'text-green-300' : 'text-white'"
class="w-4 h-4"/>
<span>{{ envInfo.installed ? `${ envInfo.language }: ${ envInfo.version }` : `${ envInfo.language } 环境未安装` }}</span>
</div>
Expand Down
Loading