-将版本号从 0.0.2 修改为 0.1.2 - 移除了异常时抛出的 RuntimeException - 新增了 C 语言和 Java代码的执行功能 - 优化了 Python 代码的执行方式- 添加了代码编辑器的前端界面 - 新增了 QQ音乐文件解密工具的 UI 界面 - 添加了 C++ 解密库的框架
364 lines
13 KiB
HTML
364 lines
13 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>C语言编辑器</title>
|
|
<style>
|
|
body {
|
|
margin: 0;
|
|
height: 100vh;
|
|
background: #2B2B2B;
|
|
font-family: 'JetBrains Mono', 'Consolas', monospace;
|
|
}
|
|
#editor {
|
|
width: 100vw;
|
|
height: 100vh;
|
|
}
|
|
.mtk5.keyword { color: #CC7832; font-weight: bold; }
|
|
.mtk5.function { color: #FFC66D; }
|
|
.mtk5.variable { color: #9876AA; }
|
|
.mtk5.comment { color: #808080; }
|
|
.mtk5.string { color: #6A8759; }
|
|
.mtk5.number { color: #6897BB; }
|
|
.doxygen-tag { color: #CC7832; }
|
|
.doxygen-param { color: #9876AA; }
|
|
.monaco-editor.vs-dark .monaco-editor-background { background: #2B2B2B !important; }
|
|
.monaco-editor .margin { background: #313335 !important; }
|
|
|
|
#container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100vh;
|
|
}
|
|
|
|
#toolbar {
|
|
background: #1E1E1E;
|
|
padding: 8px;
|
|
border-bottom: 1px solid #333;
|
|
}
|
|
|
|
#executeBtn {
|
|
background: #3276B1;
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 16px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-family: 'JetBrains Mono';
|
|
}
|
|
|
|
#console {
|
|
height: 200px;
|
|
background: #1E1E1E;
|
|
border-top: 1px solid #333;
|
|
padding: 10px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
#output {
|
|
color: #B5B5B5;
|
|
margin: 0;
|
|
font-family: 'JetBrains Mono';
|
|
font-size: 14px;
|
|
white-space: pre-wrap;
|
|
}
|
|
</style>
|
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono&display=swap" rel="stylesheet">
|
|
</head>
|
|
|
|
<body>
|
|
<div id="container">
|
|
<div id="toolbar">
|
|
<button id="executeBtn">▶ 执行</button>
|
|
</div>
|
|
<div id="editor"></div>
|
|
<div id="console">
|
|
<pre id="output"></pre>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.49.0/min/vs/loader.min.js"></script>
|
|
<script>
|
|
require.config({
|
|
paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.49.0/min/vs' },
|
|
'vs/nls': {
|
|
availableLanguages: { '*': 'zh-cn' }
|
|
}
|
|
});
|
|
|
|
require(['vs/editor/editor.main'], function() {
|
|
|
|
// 输出内容到控制台
|
|
function appendOutput(text, isError = false) {
|
|
const output = document.getElementById('output');
|
|
const div = document.createElement('div');
|
|
div.style.color = isError ? '#FF6666' : '#B5B5B5';
|
|
div.textContent = text;
|
|
output.appendChild(div);
|
|
output.scrollTop = output.scrollHeight;
|
|
}
|
|
|
|
// 清空控制台
|
|
function clearOutput() {
|
|
document.getElementById('output').innerHTML = '';
|
|
}
|
|
|
|
document.getElementById('executeBtn').addEventListener('click', () => {
|
|
const code = editor.getValue();
|
|
|
|
// 发送执行请求到Java后端
|
|
window.cefQuery({
|
|
request: JSON.stringify({
|
|
type: "executeCode",
|
|
code: code,
|
|
language: "c"
|
|
}),
|
|
onSuccess: (response) => {
|
|
const result = JSON.parse(response);
|
|
appendOutput(result.output);
|
|
},
|
|
onFailure: (errorCode, errorMsg) => {
|
|
appendOutput(`执行错误 (${errorCode}): ${errorMsg}`, true);
|
|
}
|
|
});
|
|
});
|
|
|
|
monaco.languages.register({ id: 'c' });
|
|
|
|
// C语言关键字配置
|
|
const cKeywords = [
|
|
'auto', 'break', 'case', 'char', 'const', 'continue',
|
|
'default', 'do', 'double', 'else', 'enum', 'extern',
|
|
'float', 'for', 'goto', 'if', 'inline', 'int', 'long',
|
|
'register', 'return', 'short', 'signed', 'sizeof', 'static',
|
|
'struct', 'switch', 'typedef', 'union', 'unsigned', 'void',
|
|
'volatile', 'while', '_Alignas', '_Alignof', '_Atomic',
|
|
'_Bool', '_Complex', '_Generic', '_Imaginary', '_Noreturn',
|
|
'_Static_assert', '_Thread_local',"#include","#define"
|
|
];
|
|
|
|
// 语法高亮配置
|
|
monaco.languages.setMonarchTokensProvider('c', {
|
|
keywords: cKeywords,
|
|
tokenizer: {
|
|
root: [
|
|
[/for\s*\(/, {
|
|
cases: {
|
|
'@keywords': 'keyword',
|
|
'@default': 'keyword'
|
|
}
|
|
}],
|
|
[/if\s*\(/, 'keyword'],
|
|
[/\/\*\*/, 'comment.doxygen', '@doxygen'],
|
|
[/\/\*/, 'comment', '@comment'],
|
|
[/[a-zA-Z_]\w*(?=\s*\()/, 'function'],
|
|
[/[a-zA-Z_]\w*/, {
|
|
cases: {
|
|
'@keywords': 'keyword',
|
|
'@default': 'variable'
|
|
}
|
|
}],
|
|
{ include: '@whitespace' },
|
|
[/[{}()\[\]]/, '@brackets'],
|
|
[/[0-9]+/, 'number'],
|
|
[/"/, 'string', '@string'],
|
|
[/\/\/.*$/, 'comment'],
|
|
],
|
|
doxygen: [
|
|
[/\*\//, 'comment.doxygen', '@pop'],
|
|
[/@\w+/, 'doxygen-tag'],
|
|
[/\\[\w]+/, 'doxygen-param'],
|
|
[/[\s\S]/, 'comment.doxygen']
|
|
],
|
|
comment: [
|
|
[/\*\//, 'comment', '@pop'],
|
|
[/[\s\S]/, 'comment']
|
|
],
|
|
string: [
|
|
[/[^\\"]+/, 'string'],
|
|
[/\\["\\nrt]/, 'string.escape'],
|
|
[/"/, 'string', '@pop']
|
|
],
|
|
whitespace: [
|
|
[/[ \t\r\n]+/, 'white'],
|
|
],
|
|
}
|
|
});
|
|
|
|
// 定义跳转功能
|
|
monaco.languages.registerDefinitionProvider('c', {
|
|
provideDefinition: (model, position) => {
|
|
const word = model.getWordAtPosition(position);
|
|
if (!word) return [];
|
|
const funcMatches = model.findMatches(
|
|
`\\b(\\w+)\\s+${word.word}\\s*\\([^)]*\\)\\s*[;{]`,
|
|
true, true, false, null, true
|
|
);
|
|
const varMatches = model.findMatches(
|
|
`\\b(int|float|double|char|void|short|long|unsigned)\\s+${word.word}\\b`,
|
|
true, true, false, null, true
|
|
);
|
|
return [...funcMatches, ...varMatches].map(match => ({
|
|
uri: model.uri,
|
|
range: match.range
|
|
}));
|
|
}
|
|
});
|
|
|
|
// 自动补全配置
|
|
const systemFunctions = [
|
|
{
|
|
label: 'printf',
|
|
kind: monaco.languages.CompletionItemKind.Function,
|
|
insertText: 'printf("${1:format}", ${2:args});',
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
documentation: {
|
|
value: '**格式化输出函数**\n\n参数:\n- `format`: 格式字符串 (例: "%d")\n- `...`: 可变参数列表'
|
|
}
|
|
},
|
|
{
|
|
label: 'main',
|
|
kind: monaco.languages.CompletionItemKind.Function,
|
|
insertText: 'int main(int ${1:argc}, char* ${2:argv[]}){\n ${3://is code}\n}',
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
documentation: {
|
|
value: '**主函数**'
|
|
}
|
|
},
|
|
{
|
|
label: 'scanf',
|
|
kind: monaco.languages.CompletionItemKind.Function,
|
|
insertText: 'scanf("${1:format}", ${2:&var});',
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
documentation: {
|
|
value: '**格式化输入函数**\n\n参数:\n- `format`: 格式字符串\n- `...`: 变量地址列表'
|
|
}
|
|
}
|
|
];
|
|
|
|
const codeSnippets = [
|
|
{
|
|
label: 'if',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: 'if (${1:condition}) {\n\t${2:// code}\n}',
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
documentation: 'if条件语句'
|
|
},
|
|
{
|
|
label: 'for',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: 'for (int ${1:i} = 0; ${1:i} < ${2:count}; ${1:i}++) {\n\t${3:// code}\n}',
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
documentation: 'for循环语句'
|
|
},
|
|
{
|
|
label: 'while',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: 'while (${1:condition}) {\n\t${2:// code}\n}',
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
documentation: 'while循环语句'
|
|
},
|
|
{
|
|
label: 'switch',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: 'switch (${1:expression}) {\n\tcase ${2:value}:\n\t\t${3:// code}\n\t\tbreak;\n\tdefault:\n\t\t${4:// code}\n}',
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
documentation: 'switch语句'
|
|
}
|
|
];
|
|
|
|
monaco.languages.registerCompletionItemProvider('c', {
|
|
triggerCharacters: ['.', ':', '$', '/', '@', '*'],
|
|
provideCompletionItems: (model, position) => {
|
|
const word = model.getWordUntilPosition(position);
|
|
const range = new monaco.Range(
|
|
position.lineNumber,
|
|
word.startColumn,
|
|
position.lineNumber,
|
|
word.endColumn
|
|
);
|
|
|
|
return {
|
|
suggestions: [
|
|
...cKeywords.map(keyword => ({
|
|
label: keyword,
|
|
kind: monaco.languages.CompletionItemKind.Keyword,
|
|
insertText: keyword,
|
|
range: range
|
|
})),
|
|
...codeSnippets.map(snippet => ({
|
|
...snippet,
|
|
range: range
|
|
})),
|
|
...systemFunctions.map(func => ({
|
|
...func,
|
|
range: range
|
|
})),
|
|
...getCurrentVariables(model).map(v => ({
|
|
label: v.name,
|
|
kind: monaco.languages.CompletionItemKind.Variable,
|
|
detail: `类型: ${v.type}`,
|
|
insertText: v.name,
|
|
range: range
|
|
})),
|
|
...getCurrentFunctions(model).map(f => ({
|
|
label: f,
|
|
kind: monaco.languages.CompletionItemKind.Function,
|
|
detail: '用户定义函数',
|
|
insertText: f,
|
|
range: range
|
|
}))
|
|
]
|
|
};
|
|
}
|
|
});
|
|
|
|
// 创建编辑器实例
|
|
const editor = monaco.editor.create(document.getElementById('editor'), {
|
|
value: `#include <stdio.h>\n\nint main() {\n printf("Hello World\\n");\n return 0;\n}`,
|
|
language: 'c',
|
|
theme: 'vs-dark',
|
|
minimap: { enabled: true },
|
|
fontSize: 16,
|
|
lineNumbers: 'on',
|
|
roundedSelection: false,
|
|
scrollBeyondLastLine: false,
|
|
automaticLayout: true,
|
|
tabSize: 4,
|
|
suggest: {
|
|
showKeywords: true,
|
|
showSnippets: true
|
|
},
|
|
glyphMargin: true,
|
|
lightbulb: { enabled: true }
|
|
});
|
|
|
|
// 辅助函数
|
|
function getCurrentVariables(model) {
|
|
const varRegex = /\b(int|float|double|char|void|short|long|unsigned)\s+([a-zA-Z_][\w,\s*]*)/g;
|
|
const variables = [];
|
|
let match;
|
|
while ((match = varRegex.exec(model.getValue()))) {
|
|
const type = match[1];
|
|
const names = match[2].split(',').map(s => s.trim());
|
|
names.forEach(name => {
|
|
variables.push({
|
|
name: name.replace(/\*+/g, '').trim(),
|
|
type: type
|
|
});
|
|
});
|
|
}
|
|
return variables;
|
|
}
|
|
|
|
function getCurrentFunctions(model) {
|
|
const funcRegex = /(\w+)\s*\([^)]*\)\s*\{/g;
|
|
return Array.from(model.getValue().matchAll(funcRegex))
|
|
.map(m => m[1])
|
|
.filter(f => !['if','while','for','switch'].includes(f));
|
|
}
|
|
|
|
window.addEventListener('resize', () => editor.layout());
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |