smart-code-editor 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +155 -0
  2. package/lib/adapters/vanilla/index.d.ts +3 -0
  3. package/lib/adapters/vanilla/index.d.ts.map +1 -0
  4. package/lib/config/languages.d.ts +21 -0
  5. package/lib/config/languages.d.ts.map +1 -0
  6. package/lib/config/runnerStrategies.d.ts +12 -0
  7. package/lib/config/runnerStrategies.d.ts.map +1 -0
  8. package/lib/config/runnerStrategies_v2.d.ts +31 -0
  9. package/lib/config/runnerStrategies_v2.d.ts.map +1 -0
  10. package/lib/config/themes.d.ts +54 -0
  11. package/lib/config/themes.d.ts.map +1 -0
  12. package/lib/core/BackendRunner.d.ts +78 -0
  13. package/lib/core/BackendRunner.d.ts.map +1 -0
  14. package/lib/core/CodeRunner.d.ts +32 -0
  15. package/lib/core/CodeRunner.d.ts.map +1 -0
  16. package/lib/core/LanguageManager.d.ts +41 -0
  17. package/lib/core/LanguageManager.d.ts.map +1 -0
  18. package/lib/core/LayoutManager.d.ts +59 -0
  19. package/lib/core/LayoutManager.d.ts.map +1 -0
  20. package/lib/core/MonacoWrapper.d.ts +63 -0
  21. package/lib/core/MonacoWrapper.d.ts.map +1 -0
  22. package/lib/core/SmartCodeEditor.d.ts +140 -0
  23. package/lib/core/SmartCodeEditor.d.ts.map +1 -0
  24. package/lib/dev-main.d.ts +2 -0
  25. package/lib/dev-main.d.ts.map +1 -0
  26. package/lib/index.cjs +242 -0
  27. package/lib/index.d.ts +5 -0
  28. package/lib/index.d.ts.map +1 -0
  29. package/lib/index.js +1369 -0
  30. package/lib/index.umd.cjs +242 -0
  31. package/lib/shims-vue.d.ts +4 -0
  32. package/lib/types/index.d.ts +101 -0
  33. package/lib/types/index.d.ts.map +1 -0
  34. package/lib/types/language.d.ts +37 -0
  35. package/lib/types/language.d.ts.map +1 -0
  36. package/lib/types/question.d.ts +75 -0
  37. package/lib/types/question.d.ts.map +1 -0
  38. package/lib/utils/loader.d.ts +9 -0
  39. package/lib/utils/loader.d.ts.map +1 -0
  40. package/lib/utils/markdown.d.ts +2 -0
  41. package/lib/utils/markdown.d.ts.map +1 -0
  42. package/package.json +72 -0
  43. package/src/adapters/vanilla/index.ts +7 -0
  44. package/src/adapters/vue/SmartCodeEditor.vue +1190 -0
  45. package/src/config/languages.ts +273 -0
  46. package/src/config/runnerStrategies.ts +261 -0
  47. package/src/config/runnerStrategies_v2.ts +182 -0
  48. package/src/config/themes.ts +37 -0
  49. package/src/core/BackendRunner.ts +329 -0
  50. package/src/core/CodeRunner.ts +107 -0
  51. package/src/core/LanguageManager.ts +108 -0
  52. package/src/core/LayoutManager.ts +268 -0
  53. package/src/core/MonacoWrapper.ts +173 -0
  54. package/src/core/SmartCodeEditor.ts +1015 -0
  55. package/src/dev-app.vue +488 -0
  56. package/src/dev-main.ts +7 -0
  57. package/src/index.ts +19 -0
  58. package/src/shims-vue.d.ts +4 -0
  59. package/src/types/index.ts +129 -0
  60. package/src/types/language.ts +44 -0
  61. package/src/types/question.ts +98 -0
  62. package/src/utils/loader.ts +69 -0
  63. package/src/utils/markdown.ts +89 -0
package/lib/index.js ADDED
@@ -0,0 +1,1369 @@
1
+ function _() {
2
+ return typeof window.monaco < "u" ? Promise.resolve(window.monaco) : new Promise((h, e) => {
3
+ const t = window, n = t.__SCE_MONACO_LOADER_URL__, i = t.__SCE_MONACO_BASE_PATH__, s = n ? [n] : i ? [`${String(i).replace(/\/$/, "")}/loader.js`] : ["/package/min/vs/loader.js", "/package/vs/loader.js"], l = (r) => {
4
+ if (r >= s.length) {
5
+ e(new Error("Monaco loader not found"));
6
+ return;
7
+ }
8
+ const c = s[r], u = document.createElement("script");
9
+ u.src = c, u.onload = () => {
10
+ const p = c.replace(/\/loader\.js(\?.*)?$/, "");
11
+ window.require.config({
12
+ paths: {
13
+ vs: p
14
+ }
15
+ }), window.require(["vs/editor/editor.main"], () => {
16
+ h(window.monaco);
17
+ });
18
+ }, u.onerror = () => {
19
+ u.remove(), l(r + 1);
20
+ }, document.body.appendChild(u);
21
+ };
22
+ l(0);
23
+ });
24
+ }
25
+ function T(h, e) {
26
+ let t;
27
+ return function(...n) {
28
+ clearTimeout(t), t = setTimeout(() => {
29
+ h.apply(this, n);
30
+ }, e);
31
+ };
32
+ }
33
+ class M {
34
+ constructor(e) {
35
+ this.editor = null, this.monaco = null, this.container = e;
36
+ }
37
+ /**
38
+ * 初始化编辑器
39
+ */
40
+ async initialize(e = {}) {
41
+ this.monaco = await _(), this.editor = this.monaco.editor.create(this.container, {
42
+ value: e.value || "",
43
+ language: e.language || "javascript",
44
+ theme: e.theme || "vs-dark",
45
+ readOnly: e.readOnly || !1,
46
+ fontSize: e.fontSize || 14,
47
+ minimap: e.minimap || { enabled: !0 },
48
+ lineNumbers: e.lineNumbers || "on",
49
+ automaticLayout: e.automaticLayout !== !1,
50
+ scrollBeyondLastLine: !1,
51
+ roundedSelection: !0,
52
+ padding: { top: 16 },
53
+ suggestOnTriggerCharacters: e.suggestOnTriggerCharacters !== void 0 ? e.suggestOnTriggerCharacters : !0,
54
+ quickSuggestions: e.quickSuggestions !== void 0 ? e.quickSuggestions : !0,
55
+ tabSize: 2
56
+ });
57
+ }
58
+ /**
59
+ * 设置值
60
+ */
61
+ setValue(e) {
62
+ this.editor && this.editor.setValue(e);
63
+ }
64
+ /**
65
+ * 获取值
66
+ */
67
+ getValue() {
68
+ return this.editor ? this.editor.getValue() : "";
69
+ }
70
+ /**
71
+ * 设置语言
72
+ */
73
+ /**
74
+ * 更新模型(切换语言时重建模型以确保语法提示正确)
75
+ */
76
+ updateModel(e, t, n = "", i = "default") {
77
+ if (this.editor && this.monaco) {
78
+ const a = this.editor.getModel(), s = n.startsWith(".") ? n : `.${n}`, l = this.monaco.Uri.parse(`file:///${i}/main${s}`);
79
+ let r = this.monaco.editor.getModel(l);
80
+ r ? (r.setValue(e), this.monaco.editor.setModelLanguage(r, t)) : r = this.monaco.editor.createModel(e, t, l), this.editor.setModel(r), a && a !== r && a.dispose();
81
+ }
82
+ }
83
+ /**
84
+ * 设置主题
85
+ */
86
+ setTheme(e) {
87
+ this.editor && this.monaco && this.monaco.editor.setTheme(e);
88
+ }
89
+ /**
90
+ * 设置只读
91
+ */
92
+ setReadOnly(e) {
93
+ this.editor && this.editor.updateOptions({ readOnly: e });
94
+ }
95
+ /**
96
+ * 更新配置
97
+ */
98
+ updateOptions(e) {
99
+ this.editor && this.editor.updateOptions(e);
100
+ }
101
+ /**
102
+ * 监听内容变化
103
+ */
104
+ onDidChangeContent(e) {
105
+ this.editor && this.editor.onDidChangeModelContent(() => {
106
+ e(this.getValue());
107
+ });
108
+ }
109
+ /**
110
+ * 调整布局
111
+ */
112
+ layout() {
113
+ this.editor && this.editor.layout();
114
+ }
115
+ /**
116
+ * 获取 Monaco 实例
117
+ */
118
+ getMonaco() {
119
+ return this.monaco;
120
+ }
121
+ /**
122
+ * 获取编辑器实例
123
+ */
124
+ getEditor() {
125
+ return this.editor;
126
+ }
127
+ /**
128
+ * 销毁
129
+ */
130
+ dispose() {
131
+ this.editor && (this.editor.dispose(), this.editor = null);
132
+ }
133
+ }
134
+ class $ {
135
+ constructor(e, t = 0.48, n = "vs-dark") {
136
+ this.isDragging = !1, this.startX = 0, this.startLeftWidth = 0, this.handleMouseDown = (i) => {
137
+ this.isDragging = !0, this.startX = i.clientX, this.startLeftWidth = this.leftPanel.offsetWidth, this.splitter.style.background = "#4CAF50", document.body.style.cursor = "col-resize", document.body.style.userSelect = "none", i.preventDefault();
138
+ }, this.handleMouseMove = (i) => {
139
+ if (!this.isDragging) return;
140
+ const a = i.clientX - this.startX, s = this.startLeftWidth + a, l = this.container.offsetWidth, r = 200, c = l - 400 - 8;
141
+ if (s >= r && s <= c) {
142
+ const u = s / l;
143
+ this.leftPanel.style.width = `${u * 100}%`;
144
+ }
145
+ }, this.handleMouseUp = () => {
146
+ this.isDragging && (this.isDragging = !1, this.splitter.style.background = "#f5f5f5", document.body.style.cursor = "", document.body.style.userSelect = "");
147
+ }, this.container = e, this.leftPanel = document.createElement("div"), this.splitter = document.createElement("div"), this.rightPanel = document.createElement("div"), this.initLayout(t, n), this.initResizable();
148
+ }
149
+ /**
150
+ * 初始化布局
151
+ */
152
+ initLayout(e, t) {
153
+ this.container.style.display = "flex", this.container.style.height = "100%", this.container.style.position = "relative";
154
+ const n = document.createElement("div");
155
+ n.className = "sce-editor-wrapper", n.style.display = "flex", n.style.height = "100%", n.style.width = "100%", n.style.overflow = "hidden", this.leftPanel.className = "sce-question-panel", this.leftPanel.style.width = `${e * 100}%`, this.leftPanel.style.minWidth = "200px", this.leftPanel.style.overflow = "auto", this.leftPanel.style.padding = "14px 6px 14px 14px", this.leftPanel.style.boxSizing = "border-box", this.splitter.className = "sce-splitter", this.splitter.style.width = "2px", this.splitter.style.cursor = "col-resize", this.splitter.style.flexShrink = "0", this.splitter.style.userSelect = "none", this.splitter.style.margin = "0 6px";
156
+ const i = document.createElement("div");
157
+ i.className = "sce-right-container", i.style.flex = "1", i.style.minWidth = "400px", i.style.minHeight = "0", i.style.display = "flex", i.style.flexDirection = "column", i.style.overflow = "hidden", this.rightPanel.className = "sce-editor-panel", this.rightPanel.style.flex = "1", this.rightPanel.style.minHeight = "0", this.rightPanel.style.overflow = "hidden", this.rightPanel.style.position = "relative", this.rightPanel.style.display = "flex", this.rightPanel.style.flexDirection = "column", this.setTheme(t), i.appendChild(this.rightPanel), n.appendChild(this.leftPanel), n.appendChild(this.splitter), n.appendChild(i), this.container.appendChild(n);
158
+ }
159
+ /**
160
+ * 初始化拖拽功能
161
+ */
162
+ initResizable() {
163
+ this.splitter.addEventListener("mousedown", this.handleMouseDown), document.addEventListener("mousemove", this.handleMouseMove), document.addEventListener("mouseup", this.handleMouseUp);
164
+ }
165
+ /**
166
+ * 设置左侧内容
167
+ */
168
+ setLeftContent(e) {
169
+ typeof e == "string" ? (this.leftPanel.innerHTML = e, this.leftPanel.style.overflow = "auto") : (this.leftPanel.innerHTML = "", this.leftPanel.appendChild(e), e.classList.contains("sce-question-markdown") ? this.leftPanel.style.overflow = "hidden" : this.leftPanel.style.overflow = "auto");
170
+ }
171
+ /**
172
+ * 获取右侧容器(用于放置编辑器)
173
+ */
174
+ getRightContainer() {
175
+ return this.rightPanel;
176
+ }
177
+ /**
178
+ * 显示/隐藏左侧面板
179
+ */
180
+ setQuestionPanelVisible(e) {
181
+ e ? (this.leftPanel.style.display = "block", this.splitter.style.display = "block") : (this.leftPanel.style.display = "none", this.splitter.style.display = "none");
182
+ }
183
+ /**
184
+ * 设置分割比例
185
+ */
186
+ setSplitRatio(e) {
187
+ this.leftPanel.style.width = `${e * 100}%`;
188
+ }
189
+ /**
190
+ * 设置主题
191
+ */
192
+ setTheme(e) {
193
+ const t = e === "vs-dark";
194
+ t ? (this.leftPanel.style.background = "#1e1e1e", this.leftPanel.style.color = "#d4d4d4", this.splitter.style.background = "#252526") : (this.leftPanel.style.background = "#ffffff", this.leftPanel.style.color = "#333333", this.splitter.style.background = "#f5f5f5");
195
+ const n = this.leftPanel.querySelector(
196
+ ".sce-markdown-editor"
197
+ ), i = this.leftPanel.querySelector(
198
+ ".sce-markdown-preview"
199
+ ), a = this.leftPanel.querySelectorAll(".sce-markdown-label"), s = this.leftPanel.querySelectorAll(".sce-markdown-tab");
200
+ n && (n.style.background = t ? "#1e1e1e" : "#ffffff", n.style.color = t ? "#d4d4d4" : "#333333", n.style.border = t ? "1px solid #333" : "1px solid #ddd"), i && (i.style.background = t ? "#1b1b1b" : "#ffffff", i.style.color = t ? "#d4d4d4" : "#333333"), a.forEach((l) => {
201
+ l.style.color = t ? "#c5c5c5" : "#666666";
202
+ }), s.forEach((l) => {
203
+ const r = l, c = r.classList.contains("active");
204
+ r.style.border = t ? "1px solid #3a3a3a" : "1px solid #ddd", r.style.background = c ? t ? "#2d2d30" : "#f3f3f3" : t ? "#1f1f1f" : "#ffffff", r.style.color = t ? "#d4d4d4" : "#333333", r.style.borderRadius = "6px", r.style.padding = "4px 10px", r.style.fontSize = "12px", r.style.cursor = "pointer";
205
+ });
206
+ }
207
+ /**
208
+ * 销毁
209
+ */
210
+ destroy() {
211
+ document.removeEventListener("mousemove", this.handleMouseMove), document.removeEventListener("mouseup", this.handleMouseUp), this.container.innerHTML = "";
212
+ }
213
+ }
214
+ const L = [
215
+ {
216
+ id: "javascript",
217
+ name: "JavaScript",
218
+ monacoId: "javascript",
219
+ extensions: [".js"],
220
+ fallbackTemplate: `// JavaScript 示例
221
+ console.log("Hello, World!");
222
+
223
+ // 定义一个函数
224
+ function fibonacci(n) {
225
+ if (n <= 1) return n;
226
+ return fibonacci(n - 1) + fibonacci(n - 2);
227
+ }
228
+
229
+ console.log("斐波那契数列前10项:");
230
+ for (let i = 0; i < 10; i++) {
231
+ console.log(\`F(\${i}) = \${fibonacci(i)}\`);
232
+ }`,
233
+ canRun: !0
234
+ },
235
+ {
236
+ id: "typescript",
237
+ name: "TypeScript",
238
+ monacoId: "typescript",
239
+ extensions: [".ts"],
240
+ fallbackTemplate: `// TypeScript 示例
241
+ interface User {
242
+ name: string;
243
+ age: number;
244
+ }
245
+
246
+ const user: User = {
247
+ name: "张三",
248
+ age: 25
249
+ };
250
+
251
+ console.log(\`用户: \${user.name}, 年龄: \${user.age}\`);`,
252
+ canRun: !0
253
+ },
254
+ {
255
+ id: "python",
256
+ name: "Python",
257
+ monacoId: "python",
258
+ extensions: [".py"],
259
+ fallbackTemplate: `# Python 示例
260
+ print("Hello, World!")
261
+
262
+ # 列表推导式
263
+ squares = [x**2 for x in range(10)]
264
+ print("前10个平方数:", squares)
265
+
266
+ # 定义一个类
267
+ class Person:
268
+ def __init__(self, name, age):
269
+ self.name = name
270
+ self.age = age
271
+
272
+ def greet(self):
273
+ return f"你好,我是{self.name},今年{self.age}岁"
274
+
275
+ person = Person("李四", 30)
276
+ print(person.greet())`,
277
+ canRun: !0
278
+ },
279
+ {
280
+ id: "html",
281
+ name: "HTML",
282
+ monacoId: "html",
283
+ fallbackTemplate: `<!DOCTYPE html>
284
+ <html lang="zh-CN">
285
+ <head>
286
+ <meta charset="UTF-8">
287
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
288
+ <title>Hello HTML</title>
289
+ </head>
290
+ <body>
291
+ <h1>欢迎使用智能代码编辑器</h1>
292
+ <p>这是一个 HTML 示例</p>
293
+ </body>
294
+ </html>`,
295
+ canRun: !1,
296
+ extensions: [".html"]
297
+ },
298
+ {
299
+ id: "css",
300
+ name: "CSS",
301
+ monacoId: "css",
302
+ fallbackTemplate: `/* CSS 示例 */
303
+ body {
304
+ font-family: 'Arial', sans-serif;
305
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
306
+ color: white;
307
+ padding: 20px;
308
+ }
309
+
310
+ .container {
311
+ max-width: 1200px;
312
+ margin: 0 auto;
313
+ background: rgba(255, 255, 255, 0.1);
314
+ border-radius: 10px;
315
+ padding: 30px;
316
+ }
317
+
318
+ h1 {
319
+ font-size: 2.5rem;
320
+ margin-bottom: 20px;
321
+ }`,
322
+ canRun: !1,
323
+ extensions: [".css"]
324
+ },
325
+ {
326
+ id: "java",
327
+ name: "Java",
328
+ monacoId: "java",
329
+ fallbackTemplate: `public class HelloWorld {
330
+ public static void main(String[] args) {
331
+ System.out.println("Hello, World!");
332
+
333
+ // 数组示例
334
+ int[] numbers = {1, 2, 3, 4, 5};
335
+ int sum = 0;
336
+ for (int num : numbers) {
337
+ sum += num;
338
+ }
339
+ System.out.println("数组总和: " + sum);
340
+ }
341
+ }`,
342
+ canRun: !0,
343
+ // 需要远程编译服务
344
+ extensions: [".java"]
345
+ },
346
+ {
347
+ id: "cpp",
348
+ name: "C++",
349
+ monacoId: "cpp",
350
+ fallbackTemplate: `#include <iostream>
351
+ #include <vector>
352
+ using namespace std;
353
+
354
+ int main() {
355
+ cout << "Hello, World!" << endl;
356
+
357
+ // 向量示例
358
+ vector<int> vec = {1, 2, 3, 4, 5};
359
+ int sum = 0;
360
+ for(int num : vec) {
361
+ sum += num;
362
+ }
363
+ cout << "向量总和: " << sum << endl;
364
+
365
+ return 0;
366
+ }`,
367
+ canRun: !0,
368
+ extensions: [".cpp", ".cc", ".cxx"]
369
+ },
370
+ {
371
+ id: "go",
372
+ name: "Go",
373
+ monacoId: "go",
374
+ fallbackTemplate: `package main
375
+
376
+ import "fmt"
377
+
378
+ func main() {
379
+ fmt.Println("Hello, World!")
380
+
381
+ // 切片示例
382
+ numbers := []int{1, 2, 3, 4, 5}
383
+ sum := 0
384
+ for _, num := range numbers {
385
+ sum += num
386
+ }
387
+ fmt.Printf("切片总和: %d\\n", sum)
388
+ }`,
389
+ canRun: !0,
390
+ extensions: [".go"]
391
+ },
392
+ {
393
+ id: "rust",
394
+ name: "Rust",
395
+ monacoId: "rust",
396
+ fallbackTemplate: `fn main() {
397
+ println!("Hello, World!");
398
+
399
+ // 向量示例
400
+ let numbers = vec![1, 2, 3, 4, 5];
401
+ let sum: i32 = numbers.iter().sum();
402
+ println!("总和: {}", sum);
403
+ }`,
404
+ canRun: !0,
405
+ extensions: [".rs"]
406
+ },
407
+ {
408
+ id: "c",
409
+ name: "C",
410
+ monacoId: "c",
411
+ fallbackTemplate: `#include <stdio.h>
412
+
413
+ int main() {
414
+ printf("Hello, World!\\n");
415
+
416
+ // 数组示例
417
+ int numbers[] = {1, 2, 3, 4, 5};
418
+ int sum = 0;
419
+ int size = sizeof(numbers) / sizeof(numbers[0]);
420
+
421
+ for(int i = 0; i < size; i++) {
422
+ sum += numbers[i];
423
+ }
424
+
425
+ printf("数组总和: %d\\n", sum);
426
+ return 0;
427
+ }`,
428
+ canRun: !0,
429
+ extensions: [".c"]
430
+ },
431
+ {
432
+ id: "sql",
433
+ name: "SQL",
434
+ monacoId: "sql",
435
+ fallbackTemplate: `-- SQL 示例
436
+ SELECT
437
+ users.name,
438
+ users.email,
439
+ COUNT(orders.id) as order_count,
440
+ SUM(orders.amount) as total_amount
441
+ FROM users
442
+ LEFT JOIN orders ON users.id = orders.user_id
443
+ WHERE users.created_at >= '2024-01-01'
444
+ GROUP BY users.id, users.name, users.email
445
+ HAVING COUNT(orders.id) > 0
446
+ ORDER BY total_amount DESC
447
+ LIMIT 10;`,
448
+ canRun: !1,
449
+ extensions: [".sql"]
450
+ }
451
+ ];
452
+ function A(h) {
453
+ return L.find((e) => e.id === h);
454
+ }
455
+ function D() {
456
+ return L;
457
+ }
458
+ class W {
459
+ constructor(e = "javascript") {
460
+ this.languages = /* @__PURE__ */ new Map(), L.forEach((n) => {
461
+ this.languages.set(n.id, n);
462
+ });
463
+ const t = this.languages.get(e);
464
+ if (!t)
465
+ throw new Error(`Language "${e}" not found in config`);
466
+ this.currentLanguage = t;
467
+ }
468
+ /**
469
+ * 获取指定语言配置
470
+ */
471
+ getLanguage(e) {
472
+ return this.languages.get(e);
473
+ }
474
+ /**
475
+ * 获取所有语言
476
+ */
477
+ getAllLanguages() {
478
+ return Array.from(this.languages.values());
479
+ }
480
+ /**
481
+ * 切换语言
482
+ */
483
+ switchLanguage(e) {
484
+ const t = this.languages.get(e);
485
+ if (!t)
486
+ throw new Error(`Language "${e}" not supported`);
487
+ return this.currentLanguage = t, this.currentLanguage;
488
+ }
489
+ /**
490
+ * 获取当前语言
491
+ */
492
+ getCurrentLanguage() {
493
+ return this.currentLanguage;
494
+ }
495
+ /**
496
+ * 检查语言是否支持
497
+ */
498
+ isSupported(e) {
499
+ return this.languages.has(e);
500
+ }
501
+ /**
502
+ * 获取可运行的语言列表
503
+ */
504
+ getRunnableLanguages() {
505
+ return Array.from(this.languages.values()).filter((e) => e.canRun);
506
+ }
507
+ /**
508
+ * 获取语言的代码模板(支持外部配置)
509
+ * 优先级: languageTemplates > questionConfig > fallbackTemplate > 空字符串
510
+ */
511
+ getTemplate(e, t, n) {
512
+ var a, s;
513
+ if (n && n[e] !== void 0 && n[e] !== null)
514
+ return n[e];
515
+ if (((a = t == null ? void 0 : t.languageTemplates) == null ? void 0 : a[e]) !== void 0 && ((s = t == null ? void 0 : t.languageTemplates) == null ? void 0 : s[e]) !== null)
516
+ return t.languageTemplates[e];
517
+ const i = this.languages.get(e);
518
+ return i && i.fallbackTemplate ? i.fallbackTemplate : "";
519
+ }
520
+ }
521
+ async function E(h, e) {
522
+ const t = performance.now();
523
+ try {
524
+ if (!e || e.length === 0) {
525
+ const d = [], o = {
526
+ log: (...m) => {
527
+ d.push(
528
+ m.map(
529
+ (v) => typeof v == "object" ? JSON.stringify(v, null, 2) : String(v)
530
+ ).join(" ")
531
+ );
532
+ },
533
+ error: (...m) => {
534
+ d.push("ERROR: " + m.join(" "));
535
+ },
536
+ warn: (...m) => {
537
+ d.push("WARN: " + m.join(" "));
538
+ }
539
+ };
540
+ new Function("console", h)(o);
541
+ const g = performance.now() - t;
542
+ return {
543
+ output: d.join(`
544
+ `) || "(无输出)",
545
+ executionTime: g,
546
+ status: "success"
547
+ };
548
+ }
549
+ const n = [], i = [], a = `
550
+ ${h}
551
+
552
+ // 尝试找到入口函数
553
+ let mainFn = null;
554
+ // 优先级 1: solution 函数
555
+ if (typeof solution === 'function') mainFn = solution;
556
+ // 优先级 2: twoSum (针对示例)
557
+ else if (typeof twoSum === 'function') mainFn = twoSum;
558
+ // 优先级 3: 寻找最后一个定义的函数 (简单启发式,可能不准确)
559
+
560
+ if (!mainFn) {
561
+ // 如果没找到具名函数,尝试返回一个错误
562
+ throw new Error("未找到入口函数 (请定义 solution 或 twoSum 函数)");
563
+ }
564
+
565
+ return mainFn;
566
+ `;
567
+ let s = (d, o) => {
568
+ const y = o.map(
569
+ (g) => typeof g == "object" ? JSON.stringify(g, null, 2) : String(g)
570
+ ).join(" ");
571
+ n.push(y);
572
+ };
573
+ const l = {
574
+ log: (...d) => s("log", d),
575
+ error: (...d) => s("error", d),
576
+ warn: (...d) => s("warn", d)
577
+ }, c = new Function("console", a)(l);
578
+ for (const d of e) {
579
+ const o = [], y = performance.now();
580
+ let g = "error", m, v;
581
+ s = (b, w) => {
582
+ const S = w.map(
583
+ (x) => typeof x == "object" ? JSON.stringify(x, null, 2) : String(x)
584
+ ).join(" ");
585
+ o.push(S);
586
+ };
587
+ try {
588
+ let b;
589
+ Array.isArray(d.input) ? b = c(...d.input) : b = c(d.input), m = b;
590
+ let w = !1;
591
+ if (d.expected !== void 0)
592
+ try {
593
+ w = JSON.stringify(b) === JSON.stringify(d.expected);
594
+ } catch {
595
+ w = b === d.expected;
596
+ }
597
+ else
598
+ w = !0;
599
+ g = w ? "passed" : "failed";
600
+ } catch (b) {
601
+ g = "error", v = b.message, m = void 0;
602
+ }
603
+ const O = performance.now();
604
+ i.push({
605
+ id: d.id,
606
+ status: g,
607
+ input: d.input,
608
+ output: m,
609
+ expected: d.expected,
610
+ log: o.join(`
611
+ `),
612
+ error: v,
613
+ executionTime: O - y
614
+ });
615
+ }
616
+ const u = performance.now() - t, p = i.some((d) => d.status === "error"), f = i.some((d) => d.status === "failed");
617
+ return {
618
+ output: n.join(`
619
+ `),
620
+ executionTime: u,
621
+ status: p || f ? "error" : "success",
622
+ // 这里只代表是否全部通过
623
+ testResults: i
624
+ };
625
+ } catch (n) {
626
+ const i = performance.now() - t;
627
+ return {
628
+ output: "",
629
+ error: n.message || String(n),
630
+ executionTime: i,
631
+ status: "error"
632
+ };
633
+ }
634
+ }
635
+ async function N(h) {
636
+ const e = performance.now();
637
+ try {
638
+ return {
639
+ output: "Python 运行功能需要加载 Pyodide (暂未实现)",
640
+ executionTime: performance.now() - e,
641
+ status: "error",
642
+ error: "Pyodide 未加载"
643
+ };
644
+ } catch (t) {
645
+ return {
646
+ output: "",
647
+ error: t.message,
648
+ executionTime: performance.now() - e,
649
+ status: "error"
650
+ };
651
+ }
652
+ }
653
+ async function k(h, e) {
654
+ const t = performance.now();
655
+ try {
656
+ return {
657
+ output: `${e} 远程运行功能需要配置编译服务 (暂未实现)`,
658
+ executionTime: performance.now() - t,
659
+ status: "error",
660
+ error: "远程编译服务未配置"
661
+ };
662
+ } catch (n) {
663
+ return {
664
+ output: "",
665
+ error: n.message,
666
+ executionTime: performance.now() - t,
667
+ status: "error"
668
+ };
669
+ }
670
+ }
671
+ const H = {
672
+ javascript: E,
673
+ typescript: E,
674
+ // TypeScript 可以直接当 JS 运行(简化版)
675
+ python: N,
676
+ java: (h) => k(h, "Java"),
677
+ cpp: (h) => k(h, "C++"),
678
+ go: (h) => k(h, "Go")
679
+ };
680
+ function z(h) {
681
+ return H[h];
682
+ }
683
+ class V {
684
+ constructor(e = 5e3) {
685
+ this.abortController = null, this.timeout = e;
686
+ }
687
+ /**
688
+ * 运行代码
689
+ */
690
+ async run(e, t, n) {
691
+ const i = z(t);
692
+ if (!i)
693
+ return {
694
+ output: "",
695
+ error: `语言 "${t}" 不支持运行`,
696
+ executionTime: 0,
697
+ status: "error"
698
+ };
699
+ this.abortController = new AbortController();
700
+ const a = setTimeout(() => {
701
+ var s;
702
+ (s = this.abortController) == null || s.abort();
703
+ }, this.timeout);
704
+ try {
705
+ const s = await Promise.race([
706
+ i(e, n),
707
+ this.createTimeoutPromise()
708
+ ]);
709
+ return clearTimeout(a), s;
710
+ } catch (s) {
711
+ return clearTimeout(a), s.name === "AbortError" ? {
712
+ output: "",
713
+ error: `执行超时(${this.timeout}ms)`,
714
+ executionTime: this.timeout,
715
+ status: "timeout"
716
+ } : {
717
+ output: "",
718
+ error: s.message || String(s),
719
+ executionTime: 0,
720
+ status: "error"
721
+ };
722
+ } finally {
723
+ this.abortController = null;
724
+ }
725
+ }
726
+ /**
727
+ * 创建超时 Promise
728
+ */
729
+ createTimeoutPromise() {
730
+ return new Promise((e, t) => {
731
+ var n;
732
+ (n = this.abortController) == null || n.signal.addEventListener("abort", () => {
733
+ const i = new Error("Execution timeout");
734
+ i.name = "AbortError", t(i);
735
+ });
736
+ });
737
+ }
738
+ /**
739
+ * 取消运行
740
+ */
741
+ cancel() {
742
+ var e;
743
+ (e = this.abortController) == null || e.abort();
744
+ }
745
+ /**
746
+ * 设置超时时间
747
+ */
748
+ setTimeout(e) {
749
+ this.timeout = e;
750
+ }
751
+ /**
752
+ * 销毁
753
+ */
754
+ destroy() {
755
+ this.cancel();
756
+ }
757
+ }
758
+ function P(h) {
759
+ return h.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
760
+ }
761
+ function C(h) {
762
+ let e = h;
763
+ return e = e.replace(/`([^`]+)`/g, "<code>$1</code>"), e = e.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>"), e = e.replace(/\*([^*]+)\*/g, "<em>$1</em>"), e = e.replace(/_([^_]+)_/g, "<em>$1</em>"), e = e.replace(
764
+ /\[([^\]]+)\]\(([^)]+)\)/g,
765
+ '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'
766
+ ), e;
767
+ }
768
+ function j(h) {
769
+ const e = h || "", t = [];
770
+ let n = e.replace(
771
+ /```(?:[\w-]+)?\n([\s\S]*?)```/g,
772
+ (c, u) => {
773
+ const p = P(u.trimEnd()), f = `@@CODEBLOCK_${t.length}@@`;
774
+ return t.push(`<pre><code>${p}</code></pre>`), f;
775
+ }
776
+ );
777
+ n = P(n);
778
+ const i = n.split(/\r?\n/), a = [];
779
+ let s = !1;
780
+ const l = () => {
781
+ s && (a.push("</ul>"), s = !1);
782
+ };
783
+ for (const c of i) {
784
+ const u = c.trim();
785
+ if (!u) {
786
+ l();
787
+ continue;
788
+ }
789
+ const p = u.match(/^(#{1,6})\s+(.*)$/);
790
+ if (p) {
791
+ l();
792
+ const d = p[1].length;
793
+ a.push(
794
+ `<h${d}>${C(p[2])}</h${d}>`
795
+ );
796
+ continue;
797
+ }
798
+ const f = u.match(/^[-*+]\s+(.*)$/);
799
+ if (f) {
800
+ s || (a.push("<ul>"), s = !0), a.push(`<li>${C(f[1])}</li>`);
801
+ continue;
802
+ }
803
+ l(), a.push(`<p>${C(u)}</p>`);
804
+ }
805
+ l();
806
+ let r = a.join(`
807
+ `);
808
+ return t.forEach((c, u) => {
809
+ r = r.replace(`@@CODEBLOCK_${u}@@`, c);
810
+ }), r;
811
+ }
812
+ class q {
813
+ constructor(e) {
814
+ if (this.monacoWrapper = null, this.layoutManager = null, this.initialized = !1, this._pendingLanguage = null, this._pendingValue = null, this.resizeObserver = null, this.loadingMask = null, this.toolbar = null, this.langSelect = null, this.markdownEditor = null, this.markdownPreview = null, this.testCases = [], this.id = `sce_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, this.options = e, typeof e.container == "string") {
815
+ const t = document.querySelector(e.container);
816
+ if (!t)
817
+ throw new Error(`Container "${e.container}" not found`);
818
+ this.container = t;
819
+ } else
820
+ this.container = e.container;
821
+ this.languageManager = new W(
822
+ e.language || "javascript"
823
+ ), this.codeRunner = new V(e.runTimeout || 5e3), this.init();
824
+ }
825
+ /**
826
+ * 显示加载遮罩
827
+ */
828
+ showLoading() {
829
+ if (this.loadingMask) return;
830
+ this.loadingMask = document.createElement("div"), this.loadingMask.className = "sce-loading-mask", this.loadingMask.style.cssText = `
831
+ position: absolute;
832
+ top: 0;
833
+ left: 0;
834
+ width: 100%;
835
+ height: 100%;
836
+ background: ${this.options.theme === "vs-dark" ? "#1e1e1e" : "#ffffff"};
837
+ display: flex;
838
+ align-items: center;
839
+ justify-content: center;
840
+ z-index: 1000;
841
+ color: ${this.options.theme === "vs-dark" ? "#d4d4d4" : "#333333"};
842
+ font-size: 14px;
843
+ font-family: -apple-system, system-ui, sans-serif;
844
+ `;
845
+ const e = document.createElement("div");
846
+ e.className = "sce-spinner", e.textContent = "Loading...", this.loadingMask.appendChild(e), this.container.style.position = "relative", this.container.appendChild(this.loadingMask);
847
+ }
848
+ /**
849
+ * 隐藏加载遮罩
850
+ */
851
+ hideLoading() {
852
+ this.loadingMask && this.loadingMask.parentNode && (this.loadingMask.parentNode.removeChild(this.loadingMask), this.loadingMask = null);
853
+ }
854
+ /**
855
+ * 创建 Markdown 题目面板
856
+ */
857
+ createMarkdownPanel(e) {
858
+ const t = document.createElement("div");
859
+ t.className = "sce-question-markdown", t.style.display = "flex", t.style.flexDirection = "column", t.style.height = "100%", t.style.minHeight = "0", t.style.gap = "12px", t.style.overflow = "hidden";
860
+ const n = e.editable !== !1, i = n && e.showEditor !== !1, a = n ? e.showPreview !== !1 : !0, s = e.value || "";
861
+ let l = null, r = null, c = null, u = null, p = null;
862
+ const f = () => {
863
+ if (r && u) {
864
+ const o = r.style.display !== "none";
865
+ u.classList.toggle("active", o);
866
+ }
867
+ if (c && p) {
868
+ const o = c.style.display !== "none";
869
+ p.classList.toggle("active", o);
870
+ }
871
+ }, d = (o) => {
872
+ r && (r.style.display = o === r ? "flex" : "none"), c && (c.style.display = o === c ? "flex" : "none"), f();
873
+ };
874
+ if (n && i && a) {
875
+ const o = document.createElement("div");
876
+ o.className = "sce-markdown-tabs", o.style.display = "flex", o.style.gap = "8px", u = document.createElement("button"), u.type = "button", u.className = "sce-markdown-tab active", u.textContent = "编辑", p = document.createElement("button"), p.type = "button", p.className = "sce-markdown-tab active", p.textContent = "预览", o.appendChild(u), o.appendChild(p), t.appendChild(o);
877
+ }
878
+ if (i) {
879
+ r = document.createElement("div"), r.className = "sce-markdown-editor-section", r.style.display = "flex", r.style.flexDirection = "column", r.style.flex = "1", r.style.minHeight = "0";
880
+ const o = document.createElement("textarea");
881
+ o.className = "sce-markdown-editor", o.value = s, o.placeholder = e.placeholder || "在此编辑 Markdown...", o.readOnly = e.editable === !1, o.style.width = "100%", o.style.flex = "1", o.style.minHeight = "120px", o.style.resize = "none", o.style.boxSizing = "border-box", o.style.padding = "10px", o.style.borderRadius = "6px", o.style.fontFamily = "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace", o.style.fontSize = "12px", o.style.lineHeight = "1.5", r.appendChild(o), t.appendChild(r), this.markdownEditor = o;
882
+ const y = T((g) => {
883
+ l && l(g), e.onChange && e.onChange(g);
884
+ }, 150);
885
+ o.addEventListener("input", () => {
886
+ y(o.value);
887
+ });
888
+ }
889
+ if (a) {
890
+ c = document.createElement("div"), c.className = "sce-markdown-preview-section", c.style.display = "flex", c.style.flexDirection = "column", c.style.flex = "1", c.style.minHeight = "0";
891
+ const o = document.createElement("div");
892
+ o.className = "sce-markdown-preview", o.style.flex = "1", o.style.minHeight = "0", o.style.overflow = "auto", o.style.padding = "10px", o.style.borderRadius = "6px", o.style.fontFamily = "-apple-system, system-ui, sans-serif", o.style.fontSize = "13px", o.style.lineHeight = "1.6", l = (y) => {
893
+ o.innerHTML = j(y);
894
+ }, l(s), c.appendChild(o), t.appendChild(c), this.markdownPreview = o;
895
+ }
896
+ if (u && p && (u.addEventListener("click", () => {
897
+ d(r);
898
+ }), p.addEventListener("click", () => {
899
+ d(c);
900
+ }), d(r)), !i && !a) {
901
+ const o = document.createElement("div");
902
+ o.textContent = "未启用 Markdown 编辑/预览", t.appendChild(o);
903
+ }
904
+ return t;
905
+ }
906
+ /**
907
+ * 初始化
908
+ */
909
+ async init() {
910
+ var e;
911
+ try {
912
+ if (this.showLoading(), this.options.showQuestionPanel !== !1) {
913
+ if (this.layoutManager = new $(
914
+ this.container,
915
+ this.options.defaultSplitRatio || 0.5,
916
+ this.options.theme || "vs-dark"
917
+ ), this.options.questionMarkdown) {
918
+ const r = this.createMarkdownPanel(
919
+ this.options.questionMarkdown
920
+ );
921
+ this.layoutManager.setLeftContent(r), this.layoutManager.setTheme(this.options.theme || "vs-dark");
922
+ } else this.options.questionContent && this.layoutManager.setLeftContent(this.options.questionContent);
923
+ const s = this.layoutManager.getRightContainer(), l = document.createElement("div");
924
+ l.className = "sce-monaco-container", l.style.flex = "1", l.style.minHeight = "0", l.style.overflow = "hidden", l.style.position = "relative", s.appendChild(l), this.monacoWrapper = new M(l);
925
+ } else {
926
+ this.container.style.display = "flex", this.container.style.flexDirection = "column";
927
+ const s = document.createElement("div");
928
+ s.className = "sce-monaco-container", s.style.flex = "1", s.style.minHeight = "0", s.style.overflow = "hidden", s.style.position = "relative", this.container.appendChild(s), this.monacoWrapper = new M(s);
929
+ }
930
+ const t = this.languageManager.getCurrentLanguage(), n = this.options.value !== void 0 && this.options.value !== null ? this.options.value : this.languageManager.getTemplate(
931
+ t.id,
932
+ this.options.questionConfig,
933
+ this.options.languageTemplates
934
+ );
935
+ console.log("🎨 SmartCodeEditor 初始化:", {
936
+ hasValue: this.options.value !== void 0,
937
+ valueLength: (e = this.options.value) == null ? void 0 : e.length,
938
+ hasQuestionConfig: !!this.options.questionConfig,
939
+ hasLanguageTemplates: !!this.options.languageTemplates,
940
+ initialValuePreview: (n == null ? void 0 : n.substring(0, 50)) + "..."
941
+ }), await this.monacoWrapper.initialize({
942
+ value: n,
943
+ language: t.monacoId,
944
+ theme: this.options.theme || "vs-dark",
945
+ readOnly: this.options.readOnly || !1,
946
+ automaticLayout: !1,
947
+ // Explicitly disable to avoid ResizeObserver loops with our own observer
948
+ suggestOnTriggerCharacters: this.options.suggestOnTriggerCharacters,
949
+ quickSuggestions: this.options.quickSuggestions
950
+ });
951
+ const i = t.extensions ? t.extensions[0] : "";
952
+ this.monacoWrapper.updateModel(
953
+ n,
954
+ t.monacoId,
955
+ i,
956
+ this.id
957
+ );
958
+ const a = this.languageManager.getCurrentLanguage();
959
+ if (a.id !== t.id) {
960
+ const s = a.extensions ? a.extensions[0] : "";
961
+ this.monacoWrapper.updateModel(
962
+ this.getValue(),
963
+ a.monacoId,
964
+ s,
965
+ this.id
966
+ );
967
+ }
968
+ if (this._pendingValue !== null && (this.monacoWrapper.setValue(this._pendingValue), this._pendingValue = null), this.options.onChange) {
969
+ const s = T(this.options.onChange, 300);
970
+ this.monacoWrapper.onDidChangeContent(s);
971
+ }
972
+ this.initialized = !0, this._pendingLanguage && (this.setLanguage(this._pendingLanguage), this._pendingLanguage = null), this._pendingValue !== null && (this.monacoWrapper.setValue(this._pendingValue), this._pendingValue = null), this.createToolbar(), typeof ResizeObserver < "u" && (this.resizeObserver = new ResizeObserver(() => {
973
+ requestAnimationFrame(() => {
974
+ this.layout();
975
+ });
976
+ }), this.resizeObserver.observe(this.container)), this.layout();
977
+ } catch (t) {
978
+ throw console.error("Failed to initialize SmartCodeEditor:", t), t;
979
+ } finally {
980
+ this.hideLoading();
981
+ }
982
+ }
983
+ /**
984
+ * 创建工具栏
985
+ */
986
+ createToolbar() {
987
+ if (!this.monacoWrapper) return;
988
+ const e = this.layoutManager ? this.layoutManager.getRightContainer() : this.container, t = document.createElement("div");
989
+ this.toolbar = t, t.className = "sce-toolbar";
990
+ const n = this.options.theme === "vs-dark", i = n ? "#2d2d30" : "#fff", a = n ? "#454545" : "#f3f3f3";
991
+ if (t.style.cssText = `
992
+ display: flex;
993
+ align-items: center;
994
+ gap: 12px;
995
+ padding: 8px 16px;
996
+ background: ${i};
997
+ border-bottom: 1px solid ${a};
998
+ transition: all 0.2s;
999
+ flex-shrink: 0;
1000
+ `, this.options.enableLanguageSwitch !== !1) {
1001
+ const s = this.createLanguageSelector();
1002
+ t.appendChild(s);
1003
+ }
1004
+ if (this.options.enableRun !== !1) {
1005
+ const s = this.createRunButton();
1006
+ t.appendChild(s);
1007
+ }
1008
+ if (this.options.enableSubmit !== !1) {
1009
+ const s = this.createSubmitButton();
1010
+ t.appendChild(s);
1011
+ }
1012
+ e.insertBefore(t, e.firstChild);
1013
+ }
1014
+ /**
1015
+ * 创建语言选择器
1016
+ */
1017
+ createLanguageSelector() {
1018
+ const e = document.createElement("div");
1019
+ e.style.display = "flex", e.style.alignItems = "center", e.style.gap = "8px";
1020
+ const t = document.createElement("span");
1021
+ t.textContent = "语言:", t.style.color = this.options.theme === "vs-dark" ? "#ccc" : "#666", t.style.fontSize = "13px";
1022
+ const n = document.createElement("select");
1023
+ this.langSelect = n;
1024
+ const i = this.options.theme === "vs-dark", a = i ? "#3c3c3c" : "#ffffff", s = i ? "#ccc" : "#333", l = i ? "#454545" : "#ccc";
1025
+ n.style.cssText = `
1026
+ padding: 4px 8px;
1027
+ border: 1px solid ${l};
1028
+ background: ${a};
1029
+ color: ${s};
1030
+ border-radius: 4px;
1031
+ cursor: pointer;
1032
+ font-size: 13px;
1033
+ `;
1034
+ let r = this.languageManager.getAllLanguages();
1035
+ return this.options.supportedLanguages && this.options.supportedLanguages.length > 0 && (r = r.filter(
1036
+ (c) => this.options.supportedLanguages.includes(c.id)
1037
+ )), r.forEach((c) => {
1038
+ const u = document.createElement("option");
1039
+ u.value = c.id, u.textContent = `${c.icon || ""} ${c.name}`.trim(), c.id === this.languageManager.getCurrentLanguage().id && (u.selected = !0), n.appendChild(u);
1040
+ }), n.addEventListener("change", () => {
1041
+ this.setLanguage(n.value);
1042
+ }), e.appendChild(t), e.appendChild(n), e;
1043
+ }
1044
+ /**
1045
+ * 创建运行按钮
1046
+ */
1047
+ createRunButton() {
1048
+ const e = document.createElement("button");
1049
+ return e.innerHTML = "<span>▶</span> 运行", e.style.cssText = `
1050
+ padding: 6px 16px;
1051
+ border: none;
1052
+ background: #0e639c;
1053
+ color: white;
1054
+ border-radius: 4px;
1055
+ cursor: pointer;
1056
+ font-size: 13px;
1057
+ font-weight: 500;
1058
+ margin-left: auto;
1059
+ display: flex;
1060
+ align-items: center;
1061
+ gap: 6px;
1062
+ transition: background 0.2s;
1063
+ `, e.addEventListener("click", async () => {
1064
+ const t = e.innerHTML;
1065
+ try {
1066
+ e.disabled = !0, e.style.background = "#0e639c80", e.style.cursor = "not-allowed", e.innerHTML = '<span class="sce-btn-spinner"></span> 运行中...', await this.run();
1067
+ } finally {
1068
+ e.disabled = !1, e.style.background = "#0e639c", e.style.cursor = "pointer", e.innerHTML = t;
1069
+ }
1070
+ }), e.addEventListener("mouseenter", () => {
1071
+ e.disabled || (e.style.background = "#1177bb");
1072
+ }), e.addEventListener("mouseleave", () => {
1073
+ e.disabled || (e.style.background = "#0e639c");
1074
+ }), this.injectSpinnerStyle(), e;
1075
+ }
1076
+ /**
1077
+ * 创建提交按钮
1078
+ */
1079
+ createSubmitButton() {
1080
+ const e = document.createElement("button");
1081
+ return e.textContent = "提交", e.title = "提交代码进行评测", e.style.cssText = `
1082
+ padding: 6px 16px;
1083
+ border: none;
1084
+ background: #4caf50;
1085
+ color: white;
1086
+ border-radius: 4px;
1087
+ cursor: pointer;
1088
+ font-size: 13px;
1089
+ font-weight: 500;
1090
+ margin-left: 8px;
1091
+ display: flex;
1092
+ align-items: center;
1093
+ gap: 6px;
1094
+ transition: background 0.2s;
1095
+ `, e.addEventListener("click", async () => {
1096
+ if (this.options.onSubmit) {
1097
+ const t = e.textContent || "提交";
1098
+ try {
1099
+ e.disabled = !0, e.style.background = "#4caf5080", e.style.cursor = "not-allowed", e.innerHTML = '<span class="sce-btn-spinner"></span> 提交中...', await this.options.onSubmit(this.getValue(), this.getLanguage());
1100
+ } finally {
1101
+ e.disabled = !1, e.style.background = "#4caf50", e.style.cursor = "pointer", e.textContent = t;
1102
+ }
1103
+ }
1104
+ }), e.addEventListener("mouseenter", () => {
1105
+ e.disabled || (e.style.background = "#43a047");
1106
+ }), e.addEventListener("mouseleave", () => {
1107
+ e.disabled || (e.style.background = "#4caf50");
1108
+ }), e;
1109
+ }
1110
+ injectSpinnerStyle() {
1111
+ if (document.getElementById("sce-btn-spinner-style")) return;
1112
+ const e = document.createElement("style");
1113
+ e.id = "sce-btn-spinner-style", e.innerHTML = `
1114
+ @keyframes sce-spin {
1115
+ 0% { transform: rotate(0deg); }
1116
+ 100% { transform: rotate(360deg); }
1117
+ }
1118
+ .sce-btn-spinner {
1119
+ display: inline-block;
1120
+ width: 12px;
1121
+ height: 12px;
1122
+ border: 2px solid rgba(255,255,255,0.3);
1123
+ border-radius: 50%;
1124
+ border-top-color: #fff;
1125
+ animation: sce-spin 1s ease-in-out infinite;
1126
+ }
1127
+ `, document.head.appendChild(e);
1128
+ }
1129
+ /**
1130
+ * 获取代码
1131
+ */
1132
+ getValue() {
1133
+ var e;
1134
+ return ((e = this.monacoWrapper) == null ? void 0 : e.getValue()) || "";
1135
+ }
1136
+ /**
1137
+ * 设置代码
1138
+ */
1139
+ setValue(e) {
1140
+ if (!this.monacoWrapper || !this.initialized) {
1141
+ this._pendingValue = e;
1142
+ return;
1143
+ }
1144
+ this.monacoWrapper.setValue(e);
1145
+ }
1146
+ /**
1147
+ * 获取当前语言
1148
+ */
1149
+ getLanguage() {
1150
+ return this.languageManager.getCurrentLanguage().id;
1151
+ }
1152
+ /**
1153
+ * 设置语言
1154
+ */
1155
+ setLanguage(e) {
1156
+ var s;
1157
+ if (!this.monacoWrapper || !this.initialized) {
1158
+ this._pendingLanguage = e;
1159
+ return;
1160
+ }
1161
+ const t = this.languageManager.switchLanguage(e), n = this.getValue(), i = t.extensions ? t.extensions[0] : "";
1162
+ (s = this.monacoWrapper) == null || s.updateModel(n, t.monacoId, i, this.id);
1163
+ const a = this.languageManager.getTemplate(
1164
+ e,
1165
+ this.options.questionConfig,
1166
+ this.options.languageTemplates
1167
+ );
1168
+ this.setValue(a), this.options.onLanguageChange && this.options.onLanguageChange(e);
1169
+ }
1170
+ /**
1171
+ * 获取支持的语言列表
1172
+ */
1173
+ getSupportedLanguages() {
1174
+ return this.languageManager.getAllLanguages();
1175
+ }
1176
+ /**
1177
+ * 设置主题
1178
+ */
1179
+ setTheme(e) {
1180
+ var t, n;
1181
+ if ((t = this.monacoWrapper) == null || t.setTheme(e), (n = this.layoutManager) == null || n.setTheme(e), this.options.theme = e, this.toolbar) {
1182
+ const i = e === "vs-dark";
1183
+ this.toolbar.style.background = i ? "#2d2d30" : "#f3f3f3", this.toolbar.style.borderBottom = i ? "1px solid #454545" : "1px solid #e0e0e0";
1184
+ }
1185
+ if (this.langSelect) {
1186
+ const i = e === "vs-dark";
1187
+ this.langSelect.style.background = i ? "#3c3c3c" : "#ffffff", this.langSelect.style.color = i ? "#ccc" : "#333", this.langSelect.style.borderColor = i ? "#454545" : "#ccc", this.langSelect.previousElementSibling instanceof HTMLElement && (this.langSelect.previousElementSibling.style.color = i ? "#ccc" : "#666");
1188
+ }
1189
+ }
1190
+ /**
1191
+ * 获取主题
1192
+ */
1193
+ getTheme() {
1194
+ return this.options.theme || "vs-dark";
1195
+ }
1196
+ /**
1197
+ * 设置试题内容
1198
+ */
1199
+ setQuestionContent(e) {
1200
+ var t;
1201
+ (t = this.layoutManager) == null || t.setLeftContent(e), this.markdownEditor = null, this.markdownPreview = null;
1202
+ }
1203
+ /**
1204
+ * 设置 Markdown 题目内容
1205
+ */
1206
+ setQuestionMarkdown(e, t) {
1207
+ if (!this.layoutManager) return;
1208
+ const n = {
1209
+ ...this.options.questionMarkdown || {},
1210
+ ...t || {},
1211
+ value: e
1212
+ }, i = this.createMarkdownPanel(n);
1213
+ this.layoutManager.setLeftContent(i), this.options.questionMarkdown = n, this.layoutManager.setTheme(this.options.theme || "vs-dark");
1214
+ }
1215
+ /**
1216
+ * 显示试题面板
1217
+ */
1218
+ showQuestionPanel() {
1219
+ var e;
1220
+ (e = this.layoutManager) == null || e.setQuestionPanelVisible(!0);
1221
+ }
1222
+ /**
1223
+ * 隐藏试题面板
1224
+ */
1225
+ hideQuestionPanel() {
1226
+ var e;
1227
+ (e = this.layoutManager) == null || e.setQuestionPanelVisible(!1);
1228
+ }
1229
+ /**
1230
+ * 设置测试用例
1231
+ */
1232
+ setTestCases(e) {
1233
+ this.testCases = e;
1234
+ }
1235
+ /**
1236
+ * 运行代码
1237
+ */
1238
+ async run(e) {
1239
+ const t = this.getValue(), n = this.getLanguage(), i = this.languageManager.getCurrentLanguage();
1240
+ if (!i.canRun) {
1241
+ const a = {
1242
+ output: "",
1243
+ error: `语言 "${i.name}" 不支持运行`,
1244
+ executionTime: 0,
1245
+ status: "error"
1246
+ };
1247
+ return this.options.onRun && this.options.onRun(a), a;
1248
+ }
1249
+ if (this.options.customRunner) {
1250
+ const a = e || this.testCases;
1251
+ try {
1252
+ const s = await this.options.customRunner(
1253
+ t,
1254
+ n,
1255
+ a
1256
+ );
1257
+ return this.options.onRun && this.options.onRun(s), s;
1258
+ } catch (s) {
1259
+ const l = {
1260
+ output: "",
1261
+ error: s.message || "自定义运行器执行失败",
1262
+ executionTime: 0,
1263
+ status: "error"
1264
+ };
1265
+ return this.options.onRun && this.options.onRun(l), l;
1266
+ }
1267
+ }
1268
+ try {
1269
+ const a = e || this.testCases, s = await this.codeRunner.run(t, n, a);
1270
+ return this.options.onRun && this.options.onRun(s), s;
1271
+ } catch (a) {
1272
+ const s = {
1273
+ output: "",
1274
+ error: a.message,
1275
+ executionTime: 0,
1276
+ status: "error"
1277
+ };
1278
+ return this.options.onRun && this.options.onRun(s), s;
1279
+ }
1280
+ }
1281
+ /**
1282
+ * 取消运行
1283
+ */
1284
+ cancelRun() {
1285
+ this.codeRunner.cancel();
1286
+ }
1287
+ /**
1288
+ * 调整布局
1289
+ */
1290
+ resize() {
1291
+ var e;
1292
+ (e = this.monacoWrapper) == null || e.layout();
1293
+ }
1294
+ /**
1295
+ * 设置分割比例
1296
+ */
1297
+ setSplitRatio(e) {
1298
+ var t, n;
1299
+ (t = this.layoutManager) == null || t.setSplitRatio(e), (n = this.monacoWrapper) == null || n.layout();
1300
+ }
1301
+ /**
1302
+ * 重新布局
1303
+ */
1304
+ layout() {
1305
+ var e;
1306
+ (e = this.monacoWrapper) == null || e.layout();
1307
+ }
1308
+ /**
1309
+ * 更新配置
1310
+ */
1311
+ updateConfig(e) {
1312
+ var n;
1313
+ const t = {};
1314
+ e.questionConfig && (this.options.questionConfig = e.questionConfig), e.languageTemplates && (this.options.languageTemplates = e.languageTemplates), e.supportedLanguages && (this.options.supportedLanguages = e.supportedLanguages, this.refreshLanguageSelector()), e.suggestOnTriggerCharacters !== void 0 && (this.options.suggestOnTriggerCharacters = e.suggestOnTriggerCharacters, t.suggestOnTriggerCharacters = e.suggestOnTriggerCharacters), e.quickSuggestions !== void 0 && (this.options.quickSuggestions = e.quickSuggestions, t.quickSuggestions = e.quickSuggestions), Object.keys(t).length > 0 && ((n = this.monacoWrapper) == null || n.updateOptions(t));
1315
+ }
1316
+ /**
1317
+ * 刷新语言选择器
1318
+ */
1319
+ refreshLanguageSelector() {
1320
+ if (!this.langSelect) return;
1321
+ this.langSelect.innerHTML = "";
1322
+ let e = this.languageManager.getAllLanguages();
1323
+ this.options.supportedLanguages && this.options.supportedLanguages.length > 0 && (e = e.filter(
1324
+ (t) => this.options.supportedLanguages.includes(t.id)
1325
+ )), e.forEach((t) => {
1326
+ const n = document.createElement("option");
1327
+ n.value = t.id, n.textContent = `${t.icon || ""} ${t.name}`.trim(), t.id === this.languageManager.getCurrentLanguage().id && (n.selected = !0), this.langSelect.appendChild(n);
1328
+ });
1329
+ }
1330
+ /**
1331
+ * 销毁
1332
+ */
1333
+ destroy() {
1334
+ var e, t, n;
1335
+ (e = this.resizeObserver) == null || e.disconnect(), (t = this.monacoWrapper) == null || t.dispose(), (n = this.layoutManager) == null || n.destroy(), this.codeRunner.destroy();
1336
+ }
1337
+ }
1338
+ const R = {
1339
+ light: {
1340
+ id: "vs",
1341
+ name: "VS Light",
1342
+ displayName: "浅色主题"
1343
+ },
1344
+ dark: {
1345
+ id: "vs-dark",
1346
+ name: "VS Dark",
1347
+ displayName: "深色主题"
1348
+ },
1349
+ "high-contrast": {
1350
+ id: "hc-black",
1351
+ name: "High Contrast",
1352
+ displayName: "高对比度"
1353
+ }
1354
+ };
1355
+ function F() {
1356
+ return Object.values(R);
1357
+ }
1358
+ function U(h) {
1359
+ return R[h];
1360
+ }
1361
+ export {
1362
+ L as LANGUAGE_CONFIGS,
1363
+ q as SmartCodeEditor,
1364
+ R as THEME_CONFIGS,
1365
+ D as getAllLanguages,
1366
+ F as getAllThemes,
1367
+ A as getLanguageConfig,
1368
+ U as getThemeConfig
1369
+ };