Files
window-axis-innovators-box/javascript/CCodeEditor.html
tzdwindows 7 adf659853d feat(browser): 实现Java字体和主题动态同步到HTML界面
- 添加javaFontsLoaded和javaThemeChanged事件监听机制
- 在BrowserWindow和BrowserWindowJDialog中实现字体信息获取和注入
- 前端HTML文件增加对应的字体应用逻辑和样式更新
- 创建WindowRegistry统一管理窗口主题更新
- 更新README文档说明HTML事件使用方法- 支持Monaco和CodeMirror编辑器的字体动态调整
-优化CEF浏览器与Java UI的字体和主题同步流程
2025-10-05 19:49:53 +08:00

419 lines
15 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);
}
});
});
// 监听Java字体加载事件
document.addEventListener('javaFontsLoaded', function(event) {
const fontInfo = event.detail;
console.log('接收到Java字体信息:', fontInfo);
// 应用Java字体到编辑器
applyJavaFonts(fontInfo);
});
// 应用Java字体的函数
function applyJavaFonts(fontInfo) {
const uiFonts = fontInfo.uiFonts || {};
const defaultFont = fontInfo.defaultFont || uiFonts['Label.font'] || {};
if (defaultFont && defaultFont.family) {
const fontFamily = defaultFont.family;
const fontSize = defaultFont.size || 14;
const fontWeight = defaultFont.bold ? 'bold' : 'normal';
const fontStyle = defaultFont.italic ? 'italic' : 'normal';
// 创建字体样式
const style = document.createElement('style');
style.textContent = `
body, html {
font-family: '${fontFamily}', 'JetBrains Mono', 'Consolas', monospace !important;
}
#output {
font-family: '${fontFamily}', 'JetBrains Mono', monospace !important;
font-size: ${fontSize}px !important;
}
#executeBtn {
font-family: '${fontFamily}', 'JetBrains Mono', monospace !important;
}
`;
// 添加到文档头
document.head.appendChild(style);
// 更新Monaco编辑器字体
if (window.editor) {
editor.updateOptions({
fontFamily: fontFamily,
fontSize: fontSize
});
}
console.log('Java字体已应用到编辑器:', fontFamily, fontSize + 'px');
}
}
// 如果字体信息已经存在,立即应用
if (typeof window.javaFontInfo !== 'undefined') {
applyJavaFonts(window.javaFontInfo);
}
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>