wasm-idle 0.3.2 → 0.4.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.
- package/README.md +4 -2
- package/dist/clang/app.d.ts +2 -1
- package/dist/clang/app.js +149 -132
- package/dist/clang/index.js +2 -2
- package/dist/debug/expression.js +135 -19
- package/dist/debug/index.d.ts +1 -1
- package/dist/debug/index.js +1 -1
- package/dist/debug/language/index.d.ts +1 -0
- package/dist/debug/language/index.js +1 -0
- package/dist/debug/language/python.d.ts +2 -0
- package/dist/debug/language/python.js +14 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/playground/clang.d.ts +5 -2
- package/dist/playground/clang.js +44 -18
- package/dist/playground/index.d.ts +2 -1
- package/dist/playground/index.js +7 -1
- package/dist/playground/java.d.ts +28 -0
- package/dist/playground/java.js +135 -0
- package/dist/playground/javaStdin.d.ts +8 -0
- package/dist/playground/javaStdin.js +90 -0
- package/dist/playground/options.d.ts +10 -0
- package/dist/playground/python.d.ts +15 -5
- package/dist/playground/python.js +98 -21
- package/dist/playground/sandbox.d.ts +3 -1
- package/dist/playground/stdinBuffer.d.ts +7 -0
- package/dist/playground/stdinBuffer.js +100 -0
- package/dist/playground/teavmConfig.d.ts +3 -0
- package/dist/playground/teavmConfig.js +14 -0
- package/dist/playground/worker/clang.js +2 -20
- package/dist/playground/worker/java.d.ts +1 -0
- package/dist/playground/worker/java.js +248 -0
- package/dist/playground/worker/python.js +253 -27
- package/dist/terminal/Terminal.svelte +41 -11
- package/dist/terminal/Terminal.svelte.d.ts +2 -1
- package/dist/terminal/types.d.ts +3 -2
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { flushQueuedStdin, readBufferedStdin, waitForBufferedStdin } from '../stdinBuffer';
|
|
1
2
|
self.document = {
|
|
2
3
|
querySelector() {
|
|
3
4
|
return null;
|
|
@@ -6,7 +7,7 @@ self.document = {
|
|
|
6
7
|
return [];
|
|
7
8
|
}
|
|
8
9
|
};
|
|
9
|
-
let stdinBufferPyodide, interruptBufferPyodide, pyodide, path = '', packageBaseUrl = '';
|
|
10
|
+
let stdinBufferPyodide, debugBufferPyodide, watchBufferPyodide, watchResultBufferPyodide, interruptBufferPyodide, pyodide, path = '', packageBaseUrl = '';
|
|
10
11
|
let jungolRobotReady = false;
|
|
11
12
|
const imageHook = `
|
|
12
13
|
if not globals().get("__wasm_idle_img_inited__", False):
|
|
@@ -202,7 +203,7 @@ async function loadPackages(code) {
|
|
|
202
203
|
}
|
|
203
204
|
}
|
|
204
205
|
self.onmessage = async (event) => {
|
|
205
|
-
const { code, buffer, load, interrupt, path: _p, prepare } = event.data;
|
|
206
|
+
const { code, buffer, debugBuffer, watchBuffer, watchResultBuffer, load, interrupt, path: _p, prepare, debug = false, breakpoints = [], pauseOnEntry = false } = event.data;
|
|
206
207
|
if (load) {
|
|
207
208
|
path = _p;
|
|
208
209
|
postMessage({ output: 'Loading Pyodide...' });
|
|
@@ -230,6 +231,9 @@ self.onmessage = async (event) => {
|
|
|
230
231
|
await loadPackages(code);
|
|
231
232
|
const ts = Date.now();
|
|
232
233
|
stdinBufferPyodide = new Int32Array(buffer);
|
|
234
|
+
debugBufferPyodide = new Int32Array(debugBuffer);
|
|
235
|
+
watchBufferPyodide = new Int32Array(watchBuffer);
|
|
236
|
+
watchResultBufferPyodide = new Int32Array(watchResultBuffer);
|
|
233
237
|
interruptBufferPyodide = new Uint8Array(interrupt);
|
|
234
238
|
pyodide.setInterruptBuffer(interruptBufferPyodide);
|
|
235
239
|
const toPythonStr = (obj) => {
|
|
@@ -246,23 +250,7 @@ self.onmessage = async (event) => {
|
|
|
246
250
|
self.prompt = self['__pyodide__input_' + ts] = (output) => {
|
|
247
251
|
if (output)
|
|
248
252
|
postMessage({ output });
|
|
249
|
-
|
|
250
|
-
postMessage({ buffer: true });
|
|
251
|
-
const res = Atomics.wait(stdinBufferPyodide, 0, 0, 100);
|
|
252
|
-
if (res === 'not-equal') {
|
|
253
|
-
try {
|
|
254
|
-
const cpy = new Int32Array(stdinBufferPyodide.byteLength);
|
|
255
|
-
cpy.set(stdinBufferPyodide);
|
|
256
|
-
stdinBufferPyodide.fill(0);
|
|
257
|
-
const dec = new TextDecoder();
|
|
258
|
-
const strInfo = dec.decode(cpy).replace(/\x00/g, ''), padding = parseInt(strInfo.slice(-1));
|
|
259
|
-
return strInfo.slice(0, -padding);
|
|
260
|
-
}
|
|
261
|
-
catch (e) {
|
|
262
|
-
postMessage({ log: { e } });
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
253
|
+
return waitForBufferedStdin(stdinBufferPyodide, () => postMessage({ buffer: true }));
|
|
266
254
|
};
|
|
267
255
|
self['__pyodide__output_' + ts] = (...data) => {
|
|
268
256
|
let sep = ' ', end = '\r\n', output = '', clear = [];
|
|
@@ -284,24 +272,262 @@ self.onmessage = async (event) => {
|
|
|
284
272
|
output += end;
|
|
285
273
|
postMessage({ output });
|
|
286
274
|
};
|
|
275
|
+
const debugPauseName = `__wasm_idle_python_debug_pause_${ts}`;
|
|
276
|
+
const debugWaitName = `__wasm_idle_python_debug_wait_${ts}`;
|
|
277
|
+
const debugReadWatchName = `__wasm_idle_python_debug_watch_read_${ts}`;
|
|
278
|
+
const debugWriteWatchName = `__wasm_idle_python_debug_watch_write_${ts}`;
|
|
279
|
+
self[debugPauseName] = (line, reason, localsJson, callStackJson) => {
|
|
280
|
+
let locals = [];
|
|
281
|
+
let callStack = [];
|
|
282
|
+
try {
|
|
283
|
+
locals = JSON.parse(localsJson);
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
locals = [];
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
callStack = JSON.parse(callStackJson);
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
callStack = [];
|
|
293
|
+
}
|
|
294
|
+
postMessage({
|
|
295
|
+
debugEvent: {
|
|
296
|
+
type: 'pause',
|
|
297
|
+
line: Number(line),
|
|
298
|
+
reason,
|
|
299
|
+
locals,
|
|
300
|
+
callStack
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
};
|
|
304
|
+
self[debugWaitName] = () => {
|
|
305
|
+
const sequence = Atomics.load(debugBufferPyodide, 0);
|
|
306
|
+
while (true) {
|
|
307
|
+
if (interruptBufferPyodide?.[0] === 2)
|
|
308
|
+
return -1;
|
|
309
|
+
Atomics.wait(debugBufferPyodide, 0, sequence, 100);
|
|
310
|
+
if (interruptBufferPyodide?.[0] === 2)
|
|
311
|
+
return -1;
|
|
312
|
+
const command = Atomics.exchange(debugBufferPyodide, 1, 0);
|
|
313
|
+
if (command)
|
|
314
|
+
return command;
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
self[debugReadWatchName] = () => readBufferedStdin(watchBufferPyodide) || '';
|
|
318
|
+
self[debugWriteWatchName] = (value) => {
|
|
319
|
+
flushQueuedStdin([value], watchResultBufferPyodide);
|
|
320
|
+
};
|
|
321
|
+
const userFilename = '__wasm_idle_user__.py';
|
|
322
|
+
const normalizedBreakpoints = JSON.stringify([...(Array.isArray(breakpoints) ? breakpoints : [])]
|
|
323
|
+
.map((value) => Number(value))
|
|
324
|
+
.filter((value) => Number.isInteger(value) && value > 0));
|
|
287
325
|
try {
|
|
288
|
-
await pyodide.runPythonAsync(`import
|
|
326
|
+
await pyodide.runPythonAsync(`import ast
|
|
327
|
+
import builtins
|
|
328
|
+
import inspect
|
|
329
|
+
import json
|
|
330
|
+
import sys
|
|
289
331
|
from js import __pyodide__input_${ts}, __pyodide__output_${ts}
|
|
332
|
+
${debug ? `from js import ${debugPauseName}, ${debugWaitName}` : ''}
|
|
333
|
+
${debug ? `from js import ${debugReadWatchName}, ${debugWriteWatchName}` : ''}
|
|
290
334
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
335
|
+
__wasm_idle_input = __pyodide__input_${ts}
|
|
336
|
+
def __wasm_idle_input_wrapper(prompt = ""):
|
|
337
|
+
value = __wasm_idle_input(prompt)
|
|
338
|
+
if value is None:
|
|
339
|
+
raise EOFError
|
|
340
|
+
return value
|
|
341
|
+
__wasm_idle_output = __pyodide__output_${ts}
|
|
342
|
+
builtins.input = __wasm_idle_input_wrapper
|
|
343
|
+
builtins.print = __wasm_idle_output
|
|
296
344
|
|
|
297
345
|
${imageHook}
|
|
298
346
|
|
|
299
|
-
${
|
|
347
|
+
${debug
|
|
348
|
+
? `
|
|
349
|
+
__wasm_idle_debug_breakpoints = set(${normalizedBreakpoints})
|
|
350
|
+
__wasm_idle_debug_pause_on_entry = ${pauseOnEntry ? 'True' : 'False'}
|
|
351
|
+
__wasm_idle_debug_step_mode = None
|
|
352
|
+
__wasm_idle_debug_resume_skip = None
|
|
353
|
+
__wasm_idle_debug_next_depth = None
|
|
354
|
+
__wasm_idle_debug_next_line = None
|
|
355
|
+
__wasm_idle_debug_step_out_depth = None
|
|
356
|
+
|
|
357
|
+
def __wasm_idle_debug_depth(frame):
|
|
358
|
+
depth = 0
|
|
359
|
+
current = frame
|
|
360
|
+
while current is not None:
|
|
361
|
+
if current.f_code.co_filename == "${userFilename}":
|
|
362
|
+
depth += 1
|
|
363
|
+
current = current.f_back
|
|
364
|
+
return depth
|
|
365
|
+
|
|
366
|
+
def __wasm_idle_debug_preview(value, depth = 0):
|
|
367
|
+
if depth >= 2:
|
|
368
|
+
return "..."
|
|
369
|
+
if value is None:
|
|
370
|
+
return "None"
|
|
371
|
+
if isinstance(value, bool):
|
|
372
|
+
return "True" if value else "False"
|
|
373
|
+
if isinstance(value, (int, float)):
|
|
374
|
+
return repr(value)
|
|
375
|
+
if isinstance(value, (bytes, bytearray)):
|
|
376
|
+
text = repr(bytes(value))
|
|
377
|
+
return text if len(text) <= 80 else text[:77] + "..."
|
|
378
|
+
if isinstance(value, str):
|
|
379
|
+
text = repr(value)
|
|
380
|
+
return text if len(text) <= 80 else text[:77] + "..."
|
|
381
|
+
if isinstance(value, list):
|
|
382
|
+
items = [__wasm_idle_debug_preview(item, depth + 1) for item in value[:8]]
|
|
383
|
+
if len(value) > 8:
|
|
384
|
+
items.append("...")
|
|
385
|
+
return "[" + ", ".join(items) + "]"
|
|
386
|
+
if isinstance(value, tuple):
|
|
387
|
+
items = [__wasm_idle_debug_preview(item, depth + 1) for item in value[:8]]
|
|
388
|
+
if len(value) > 8:
|
|
389
|
+
items.append("...")
|
|
390
|
+
if len(value) == 1 and items:
|
|
391
|
+
return "(" + items[0] + ",)"
|
|
392
|
+
return "(" + ", ".join(items) + ")"
|
|
393
|
+
if isinstance(value, dict):
|
|
394
|
+
items = []
|
|
395
|
+
for index, (key, item) in enumerate(value.items()):
|
|
396
|
+
if index >= 6:
|
|
397
|
+
items.append("...")
|
|
398
|
+
break
|
|
399
|
+
items.append(__wasm_idle_debug_preview(key, depth + 1) + ": " + __wasm_idle_debug_preview(item, depth + 1))
|
|
400
|
+
return "{" + ", ".join(items) + "}"
|
|
401
|
+
if isinstance(value, set):
|
|
402
|
+
items = [__wasm_idle_debug_preview(item, depth + 1) for item in sorted(list(value), key = repr)[:6]]
|
|
403
|
+
if len(value) > 6:
|
|
404
|
+
items.append("...")
|
|
405
|
+
return "{" + ", ".join(items) + "}"
|
|
406
|
+
try:
|
|
407
|
+
text = repr(value)
|
|
408
|
+
return text if len(text) <= 80 else text[:77] + "..."
|
|
409
|
+
except Exception:
|
|
410
|
+
return "?"
|
|
411
|
+
|
|
412
|
+
def __wasm_idle_debug_locals(frame):
|
|
413
|
+
locals_preview = []
|
|
414
|
+
for name, value in frame.f_locals.items():
|
|
415
|
+
if name == "__builtins__" or name.startswith("__wasm_idle_") or name.startswith("."):
|
|
416
|
+
continue
|
|
417
|
+
locals_preview.append({"name": name, "value": __wasm_idle_debug_preview(value)})
|
|
418
|
+
locals_preview.sort(key = lambda item: item["name"])
|
|
419
|
+
return locals_preview
|
|
420
|
+
|
|
421
|
+
def __wasm_idle_debug_stack(frame):
|
|
422
|
+
stack = []
|
|
423
|
+
current = frame
|
|
424
|
+
while current is not None:
|
|
425
|
+
if current.f_code.co_filename == "${userFilename}":
|
|
426
|
+
stack.append({"functionName": current.f_code.co_name, "line": current.f_lineno})
|
|
427
|
+
current = current.f_back
|
|
428
|
+
return stack
|
|
429
|
+
|
|
430
|
+
def __wasm_idle_debug_trace(frame, event, arg):
|
|
431
|
+
global __wasm_idle_debug_pause_on_entry
|
|
432
|
+
global __wasm_idle_debug_step_mode
|
|
433
|
+
global __wasm_idle_debug_resume_skip
|
|
434
|
+
global __wasm_idle_debug_next_depth
|
|
435
|
+
global __wasm_idle_debug_next_line
|
|
436
|
+
global __wasm_idle_debug_step_out_depth
|
|
437
|
+
|
|
438
|
+
if frame.f_code.co_filename != "${userFilename}":
|
|
439
|
+
return None
|
|
440
|
+
if event != "line":
|
|
441
|
+
return __wasm_idle_debug_trace
|
|
442
|
+
|
|
443
|
+
depth = __wasm_idle_debug_depth(frame)
|
|
444
|
+
line = frame.f_lineno
|
|
445
|
+
if __wasm_idle_debug_resume_skip == (depth, line):
|
|
446
|
+
return __wasm_idle_debug_trace
|
|
447
|
+
if __wasm_idle_debug_resume_skip is not None:
|
|
448
|
+
__wasm_idle_debug_resume_skip = None
|
|
449
|
+
|
|
450
|
+
reason = None
|
|
451
|
+
if __wasm_idle_debug_pause_on_entry:
|
|
452
|
+
reason = "entry"
|
|
453
|
+
elif line in __wasm_idle_debug_breakpoints:
|
|
454
|
+
reason = "breakpoint"
|
|
455
|
+
elif __wasm_idle_debug_step_mode == "step":
|
|
456
|
+
reason = "step"
|
|
457
|
+
elif __wasm_idle_debug_step_mode == "next" and __wasm_idle_debug_next_depth is not None and depth <= __wasm_idle_debug_next_depth and line != __wasm_idle_debug_next_line:
|
|
458
|
+
reason = "nextLine"
|
|
459
|
+
elif __wasm_idle_debug_step_mode == "out" and __wasm_idle_debug_step_out_depth is not None and depth <= __wasm_idle_debug_step_out_depth:
|
|
460
|
+
reason = "stepOut"
|
|
461
|
+
|
|
462
|
+
if reason is None:
|
|
463
|
+
return __wasm_idle_debug_trace
|
|
464
|
+
|
|
465
|
+
__wasm_idle_debug_pause_on_entry = False
|
|
466
|
+
__wasm_idle_debug_step_mode = None
|
|
467
|
+
__wasm_idle_debug_next_depth = None
|
|
468
|
+
__wasm_idle_debug_next_line = None
|
|
469
|
+
__wasm_idle_debug_step_out_depth = None
|
|
470
|
+
|
|
471
|
+
${debugPauseName}(line, reason, json.dumps(__wasm_idle_debug_locals(frame)), json.dumps(__wasm_idle_debug_stack(frame)))
|
|
472
|
+
while True:
|
|
473
|
+
command = ${debugWaitName}()
|
|
474
|
+
if command < 0:
|
|
475
|
+
raise KeyboardInterrupt()
|
|
476
|
+
if command != 5:
|
|
477
|
+
break
|
|
478
|
+
try:
|
|
479
|
+
expression = ${debugReadWatchName}()
|
|
480
|
+
result = __wasm_idle_debug_preview(eval(expression, frame.f_globals, frame.f_locals))
|
|
481
|
+
except Exception as error:
|
|
482
|
+
result = "?" if error.__class__.__name__ == "NameError" else "error"
|
|
483
|
+
${debugWriteWatchName}(result)
|
|
484
|
+
__wasm_idle_debug_resume_skip = (depth, line)
|
|
485
|
+
if command == 2:
|
|
486
|
+
__wasm_idle_debug_step_mode = "step"
|
|
487
|
+
elif command == 3:
|
|
488
|
+
__wasm_idle_debug_step_mode = "next"
|
|
489
|
+
__wasm_idle_debug_next_depth = depth
|
|
490
|
+
__wasm_idle_debug_next_line = line
|
|
491
|
+
elif command == 4:
|
|
492
|
+
__wasm_idle_debug_step_mode = "out"
|
|
493
|
+
__wasm_idle_debug_step_out_depth = max(0, depth - 1)
|
|
494
|
+
return __wasm_idle_debug_trace
|
|
495
|
+
|
|
496
|
+
sys.settrace(__wasm_idle_debug_trace)
|
|
497
|
+
`
|
|
498
|
+
: ''}
|
|
499
|
+
|
|
500
|
+
try:
|
|
501
|
+
__wasm_idle_globals = {"__name__": "__main__"}
|
|
502
|
+
__wasm_idle_result = eval(
|
|
503
|
+
compile(${JSON.stringify(code)}, "${userFilename}", "exec", flags = ast.PyCF_ALLOW_TOP_LEVEL_AWAIT),
|
|
504
|
+
__wasm_idle_globals,
|
|
505
|
+
__wasm_idle_globals,
|
|
506
|
+
)
|
|
507
|
+
if inspect.isawaitable(__wasm_idle_result):
|
|
508
|
+
await __wasm_idle_result
|
|
509
|
+
finally:
|
|
510
|
+
sys.settrace(None)
|
|
511
|
+
${debug
|
|
512
|
+
? `
|
|
513
|
+
__wasm_idle_debug_step_mode = None
|
|
514
|
+
__wasm_idle_debug_resume_skip = None
|
|
515
|
+
__wasm_idle_debug_next_depth = None
|
|
516
|
+
__wasm_idle_debug_next_line = None
|
|
517
|
+
__wasm_idle_debug_step_out_depth = None
|
|
518
|
+
`
|
|
519
|
+
: ''}
|
|
520
|
+
`);
|
|
300
521
|
self.postMessage({ results: true });
|
|
301
522
|
}
|
|
302
523
|
catch (e) {
|
|
303
524
|
self.postMessage({ error: e.message || 'Unknown error' });
|
|
304
525
|
}
|
|
526
|
+
finally {
|
|
527
|
+
delete self[debugPauseName];
|
|
528
|
+
delete self[debugWaitName];
|
|
529
|
+
delete self[debugReadWatchName];
|
|
530
|
+
delete self[debugWriteWatchName];
|
|
531
|
+
}
|
|
305
532
|
}
|
|
306
533
|
};
|
|
307
|
-
export {};
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
CompilerDiagnostic,
|
|
4
|
+
DebugCommand,
|
|
5
|
+
DebugSessionEvent,
|
|
6
|
+
SandboxExecutionOptions
|
|
7
|
+
} from '../playground/options';
|
|
3
8
|
import type { Sandbox } from '../playground/sandbox';
|
|
4
9
|
import type { TerminalControl } from './types';
|
|
5
10
|
import { Theme, registerAllPlugins } from './';
|
|
@@ -17,6 +22,7 @@
|
|
|
17
22
|
onfinish?: () => void;
|
|
18
23
|
onkey?: (e: KeyboardEvent) => void;
|
|
19
24
|
ondebug?: (event: DebugSessionEvent) => void;
|
|
25
|
+
oncompilediagnostic?: (diagnostic: CompilerDiagnostic) => void;
|
|
20
26
|
onimage?: (payload: { mime: string; b64: string; ts?: number }) => void;
|
|
21
27
|
terminal?: TerminalControl;
|
|
22
28
|
}
|
|
@@ -29,6 +35,7 @@
|
|
|
29
35
|
onfinish,
|
|
30
36
|
onkey,
|
|
31
37
|
ondebug,
|
|
38
|
+
oncompilediagnostic,
|
|
32
39
|
onimage,
|
|
33
40
|
terminal = $bindable()
|
|
34
41
|
}: Props = $props();
|
|
@@ -69,6 +76,7 @@
|
|
|
69
76
|
}
|
|
70
77
|
sandbox.image = onimage;
|
|
71
78
|
sandbox.ondebug = ondebug;
|
|
79
|
+
sandbox.oncompilerdiagnostic = oncompilediagnostic;
|
|
72
80
|
sandbox.output = (output: string) =>
|
|
73
81
|
_tc === tc && term && term.write(output.replaceAll('\n', '\r\n'));
|
|
74
82
|
}
|
|
@@ -100,12 +108,33 @@
|
|
|
100
108
|
first = false;
|
|
101
109
|
}
|
|
102
110
|
|
|
111
|
+
function appendInputText(text: string) {
|
|
112
|
+
if (!text) return;
|
|
113
|
+
input += text;
|
|
114
|
+
term?.write(text);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function submitCurrentInput() {
|
|
118
|
+
term?.write('\r\n');
|
|
119
|
+
sandbox.write?.(input + '\n');
|
|
120
|
+
input = '';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function applyPastedText(text: string) {
|
|
124
|
+
const lines = text.replaceAll('\r\n', '\n').replaceAll('\r', '\n').split('\n');
|
|
125
|
+
for (let i = 0; i < lines.length; i++) {
|
|
126
|
+
appendInputText(lines[i]);
|
|
127
|
+
if (i < lines.length - 1) submitCurrentInput();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
103
131
|
const terminalControl: TerminalControl = {
|
|
104
132
|
async clear() {
|
|
105
133
|
await wait();
|
|
106
134
|
term?.reset();
|
|
107
135
|
term?.write(`\u001B[?25l\x1b[0m\x1b[?25h`);
|
|
108
136
|
if (term) term.options.cursorBlink = false;
|
|
137
|
+
input = '';
|
|
109
138
|
first = true;
|
|
110
139
|
await new Promise((r) => setTimeout(r, 100));
|
|
111
140
|
},
|
|
@@ -146,10 +175,14 @@
|
|
|
146
175
|
await wait();
|
|
147
176
|
sandbox.debugCommand?.(command);
|
|
148
177
|
},
|
|
178
|
+
async debugEvaluate(expression: string) {
|
|
179
|
+
await wait();
|
|
180
|
+
return (await sandbox.debugEvaluate?.(expression)) || '?';
|
|
181
|
+
},
|
|
149
182
|
async write(input: string) {
|
|
150
183
|
await wait();
|
|
151
|
-
|
|
152
|
-
|
|
184
|
+
applyPastedText(input);
|
|
185
|
+
if (!input.endsWith('\n') && !input.endsWith('\r')) submitCurrentInput();
|
|
153
186
|
}
|
|
154
187
|
};
|
|
155
188
|
|
|
@@ -186,9 +219,7 @@
|
|
|
186
219
|
const printable = !ev.altKey && !ev.ctrlKey && !ev.metaKey;
|
|
187
220
|
onkey?.(ev);
|
|
188
221
|
if (ev.key === 'Enter') {
|
|
189
|
-
|
|
190
|
-
sandbox.write?.(input + '\n');
|
|
191
|
-
input = '';
|
|
222
|
+
submitCurrentInput();
|
|
192
223
|
} else if (ev.key === 'Backspace') {
|
|
193
224
|
if (term.buffer.active.cursorX > 0) {
|
|
194
225
|
term.write('\b \b');
|
|
@@ -200,17 +231,16 @@
|
|
|
200
231
|
e.key <= String.fromCharCode(0x7e)) ||
|
|
201
232
|
e.key >= '\u00a0'
|
|
202
233
|
) {
|
|
203
|
-
|
|
204
|
-
term.write(e.key);
|
|
234
|
+
appendInputText(e.key);
|
|
205
235
|
}
|
|
206
236
|
} else if ((ev.ctrlKey || ev.metaKey) && ev.key === 'c') {
|
|
207
237
|
sandbox.kill?.();
|
|
208
238
|
} else if ((ev.ctrlKey || ev.metaKey) && ev.key === 'd') {
|
|
209
|
-
|
|
239
|
+
if (input.length > 0) submitCurrentInput();
|
|
240
|
+
else sandbox.eof?.();
|
|
210
241
|
} else if ((ev.ctrlKey || ev.metaKey) && ev.key === 'v') {
|
|
211
242
|
navigator.clipboard.readText().then((text) => {
|
|
212
|
-
|
|
213
|
-
sandbox.write?.(text);
|
|
243
|
+
applyPastedText(text);
|
|
214
244
|
});
|
|
215
245
|
}
|
|
216
246
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DebugSessionEvent } from '../playground/options';
|
|
1
|
+
import type { CompilerDiagnostic, DebugSessionEvent } from '../playground/options';
|
|
2
2
|
import type { TerminalControl } from './types';
|
|
3
3
|
import '@xterm/xterm/css/xterm.css';
|
|
4
4
|
interface Props {
|
|
@@ -9,6 +9,7 @@ interface Props {
|
|
|
9
9
|
onfinish?: () => void;
|
|
10
10
|
onkey?: (e: KeyboardEvent) => void;
|
|
11
11
|
ondebug?: (event: DebugSessionEvent) => void;
|
|
12
|
+
oncompilediagnostic?: (diagnostic: CompilerDiagnostic) => void;
|
|
12
13
|
onimage?: (payload: {
|
|
13
14
|
mime: string;
|
|
14
15
|
b64: string;
|
package/dist/terminal/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DebugCommand, DebugFrame, DebugSessionEvent, DebugVariable, SandboxExecutionOptions } from '../playground/options';
|
|
1
|
+
import type { CompilerDiagnostic, DebugCommand, DebugFrame, DebugSessionEvent, DebugVariable, SandboxExecutionOptions } from '../playground/options';
|
|
2
2
|
export interface ProgressLike {
|
|
3
3
|
set?: (value: number) => void;
|
|
4
4
|
}
|
|
@@ -8,6 +8,7 @@ export interface TerminalControl {
|
|
|
8
8
|
run: (language: string, code: string, log?: boolean, prog?: ProgressLike, args?: string[], options?: SandboxExecutionOptions) => Promise<boolean | string>;
|
|
9
9
|
destroy: () => Promise<void>;
|
|
10
10
|
debugCommand: (command: DebugCommand) => Promise<void>;
|
|
11
|
+
debugEvaluate?: (expression: string) => Promise<string>;
|
|
11
12
|
write: (input: string) => Promise<void>;
|
|
12
13
|
}
|
|
13
|
-
export type { DebugCommand, DebugFrame, DebugSessionEvent, DebugVariable, SandboxExecutionOptions };
|
|
14
|
+
export type { CompilerDiagnostic, DebugCommand, DebugFrame, DebugSessionEvent, DebugVariable, SandboxExecutionOptions };
|