omni_tool/resources/sqleditor.html

226 lines
9.7 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SQL Editor</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; }
#container { width: 100%; height: 100%; }
</style>
</head>
<body>
<div id="container"></div>
<!-- 使用 CDN 加载 Monaco Editor -->
<script src="https://cdn.jsdelivr.net/npm/monaco-editor@0.50.0/min/vs/loader.js"></script>
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script>
// SQL 关键字补全词库
var sqlKeywords = [
"SELECT", "FROM", "WHERE", "AND", "OR", "NOT", "IN", "IS", "NULL",
"INSERT", "INTO", "VALUES", "UPDATE", "SET", "DELETE",
"CREATE", "TABLE", "DROP", "ALTER", "ADD", "COLUMN", "INDEX", "VIEW",
"JOIN", "LEFT", "RIGHT", "INNER", "OUTER", "CROSS", "ON",
"UNION", "ALL", "DISTINCT", "GROUP", "BY", "HAVING",
"ORDER", "ASC", "DESC", "LIMIT", "OFFSET",
"AS", "CASE", "WHEN", "THEN", "ELSE", "END", "IF", "EXISTS",
"BETWEEN", "LIKE", "ESCAPE", "RLIKE", "REGEXP",
"PRIMARY", "KEY", "FOREIGN", "REFERENCES", "CONSTRAINT",
"DEFAULT", "AUTO_INCREMENT", "IDENTITY", "UNIQUE", "CHECK",
"BEGIN", "COMMIT", "ROLLBACK", "TRANSACTION", "SAVEPOINT",
"GRANT", "REVOKE", "PRIVILEGES", "DATABASE", "SCHEMA",
"USE", "SHOW", "DESCRIBE", "EXPLAIN", "ANALYZE"
];
var sqlFunctions = [
"COUNT()", "SUM()", "AVG()", "MIN()", "MAX()",
"CONCAT()", "SUBSTRING()", "LENGTH()", "TRIM()", "LTRIM()", "RTRIM()",
"UPPER()", "LOWER()", "REPLACE()", "LEFT()", "RIGHT()", "LOCATE()",
"NOW()", "CURDATE()", "CURTIME()", "DATE()", "TIME()", "TIMESTAMP()",
"DATE_FORMAT()", "DATE_ADD()", "DATE_SUB()", "DATEDIFF()",
"COALESCE()", "IFNULL()", "NULLIF()", "CAST()", "CONVERT()",
"ROUND()", "CEIL()", "FLOOR()", "ABS()", "MOD()", "POWER()",
"RAND()", "UUID()", "MD5()", "SHA1()", "SHA2()"
];
var editor = null;
var cppBridge = null;
require.config({ paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.50.0/min/vs' } });
require(['vs/editor/editor.main'], function () {
// 注册 SQL 语言
monaco.languages.register({ id: 'sql' });
// 定义 SQL 语法的 Tokenizer
monaco.languages.setMonarchTokensProvider('sql', {
keywords: sqlKeywords,
functions: sqlFunctions.map(function(f) { return f.replace('(', '').replace(')', ''); }),
tokenizer: {
root: [
[/--.*$/, 'comment'],
[/\/\*/, 'comment', '@comment'],
[/\b(?:SELECT|FROM|WHERE|AND|OR|NOT|IN|IS|NULL|INSERT|INTO|VALUES|UPDATE|SET|DELETE|CREATE|TABLE|DROP|ALTER|ADD|COLUMN|INDEX|VIEW|JOIN|LEFT|RIGHT|INNER|OUTER|CROSS|ON|UNION|ALL|DISTINCT|GROUP|BY|HAVING|ORDER|ASC|DESC|LIMIT|OFFSET|AS|CASE|WHEN|THEN|ELSE|END|IF|EXISTS|BETWEEN|LIKE|ESCAPE|PRIMARY|KEY|FOREIGN|REFERENCES|CONSTRAINT|DEFAULT|AUTO_INCREMENT|IDENTITY|UNIQUE|CHECK|BEGIN|COMMIT|ROLLBACK|TRANSACTION|SAVEPOINT|GRANT|REVOKE|PRIVILEGES|DATABASE|SCHEMA|USE|SHOW|DESCRIBE|EXPLAIN|ANALYZE)\b/, 'keyword'],
[/\b(?:COUNT|SUM|AVG|MIN|MAX|CONCAT|SUBSTRING|LENGTH|TRIM|LTRIM|RTRIM|UPPER|LOWER|REPLACE|LEFT|RIGHT|LOCATE|NOW|CURDATE|CURTIME|DATE|TIME|TIMESTAMP|DATE_FORMAT|DATE_ADD|DATE_SUB|DATEDIFF|COALESCE|IFNULL|NULLIF|CAST|CONVERT|ROUND|CEIL|FLOOR|ABS|MOD|POWER|RAND|UUID|MD5|SHA1|SHA2)\b(?=\s*\()/, 'type.identifier'],
[/'[^']*'/, 'string'],
/"[^"]*"/, 'string',
[/\b\d+\.?\d*\b/, 'number'],
],
comment: [
[/[^\/*]+/, 'comment'],
[/\*\//, 'comment', '@pop'],
[/[\/*]/, 'comment']
]
}
});
// 定义 SQL 主题(深色风格)
monaco.editor.defineTheme('sql-dark', {
base: 'vs-dark',
inherit: true,
rules: [
{ token: 'keyword', foreground: '569cd6', fontStyle: 'bold' },
{ token: 'type.identifier', foreground: 'dcdcaa' },
{ token: 'string', foreground: 'ce9178' },
{ token: 'number', foreground: 'b5cea8' },
{ token: 'comment', foreground: '6a9955', fontStyle: 'italic' },
],
colors: {
'editor.background': '#1e1e1e',
'editor.foreground': '#d4d4d4',
'editorLineNumber.foreground': '#858585',
'editor.selectionBackground': '#264f78',
'editor.lineHighlightBackground': '#2a2d2e',
}
});
// 创建编辑器实例
editor = monaco.editor.create(document.getElementById('container'), {
value: '-- 在这里编写你的SQL语句\n-- 按 Ctrl+Enter 执行SQL\n-- 输入关键字自动弹出补全建议',
language: 'sql',
theme: 'sql-dark',
fontSize: 14,
fontFamily: 'Consolas, "Courier New", monospace',
minimap: { enabled: false },
lineNumbers: 'on',
scrollBeyondLastLine: false,
automaticLayout: true,
tabSize: 4,
wordWrap: 'off',
suggestOnTriggerCharacters: true,
quickSuggestions: true,
parameterHints: { enabled: true },
formatOnPaste: true,
formatOnType: true,
bracketPairColorization: { enabled: true },
guides: { indentation: true, bracketPairs: true },
});
// 注册自动补全项
monaco.languages.registerCompletionItemProvider('sql', {
provideCompletionItems: function (model, position) {
var suggestions = [];
// 添加关键字
for (var i = 0; i < sqlKeywords.length; i++) {
suggestions.push({
label: sqlKeywords[i],
kind: monaco.languages.CompletionItemKind.Keyword,
insertText: sqlKeywords[i],
detail: 'SQL Keyword'
});
}
// 添加函数
for (var j = 0; j < sqlFunctions.length; j++) {
suggestions.push({
label: sqlFunctions[j],
kind: monaco.languages.CompletionItemKind.Function,
insertText: sqlFunctions[j],
detail: 'SQL Function'
});
}
return { suggestions: suggestions };
}
});
// Ctrl+Enter 快捷键执行 SQL
editor.addAction({
id: 'execute-sql',
label: 'Execute SQL',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter],
run: function () {
if (cppBridge && cppBridge.executeSql) {
cppBridge.executeSql(editor.getValue());
}
}
});
// Ctrl+S 快捷键保存/提交
editor.addAction({
id: 'submit-changes',
label: 'Submit Changes',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
run: function () {
if (cppBridge && cppBridge.submitChanges) {
cppBridge.submitChanges();
}
}
});
// 窗口大小变化时自适应
window.addEventListener('resize', function () {
editor.layout();
});
});
// 连接 Qt WebChannel
new QWebChannel(qt.webChannelTransport, function(channel) {
cppBridge = channel.objects.cppBridge;
// C++ 调用:获取编辑器内容
cppBridge.getEditorContent.connect(function() {
if (cppBridge.contentReady) {
cppBridge.contentReady(editor.getValue());
}
});
// C++ 调用:设置编辑器内容
cppBridge.setEditorContent.connect(function(content) {
if (editor) {
editor.setValue(content);
}
});
// C++ 调用:追加内容
cppBridge.appendContent.connect(function(content) {
if (editor) {
var pos = editor.getPosition();
editor.executeEdits('', [{
range: new monaco.Range(pos.lineNumber, pos.column, pos.lineNumber, pos.column),
text: content
}]);
editor.focus();
}
});
// C++ 调用:插入选中的表名
cppBridge.insertTableName.connect(function(tableName) {
if (editor) {
editor.trigger('source', 'editor.action.insertSnippet', { snippet: '`' + tableName + '`' });
}
});
// 通知 C++ 编辑器已就绪
if (cppBridge.editorReady) {
cppBridge.editorReady();
}
});
</script>
</body>
</html>