9
9
<div :class =" [$style.playgroundPaneRoot, $style.playgroundEditorPane]" >
10
10
<div :class =" $style.playgroundPaneHeader" >
11
11
<div :class =" $style.playgroundResultActionsLeft" >
12
- <button :class =" $style.playgroundButton" @click =" replaceWithFizzbuzz" >Fizzbuzz</button >
12
+ <button :class =" $style.playgroundButton" :disabled = " editorLoading " @click =" replaceWithFizzbuzz" >Fizzbuzz</button >
13
13
</div >
14
14
<div :class =" $style.playgroundResultActionsRight" >
15
15
<button :class =" $style.playgroundButton" :disabled =" !isRunning" @click =" abort" >Abort</button >
16
- <button :class =" [$style.playgroundButton, $style.playgroundButtonPrimary]" @click =" run" >Run</button >
16
+ <button :class =" [$style.playgroundButton, $style.playgroundButtonPrimary]" :disabled = " editorLoading " @click =" run" >Run</button >
17
17
</div >
18
18
</div >
19
19
20
20
<div :class =" $style.playgroundEditorRoot" >
21
- <div :class =" $style.playgroundEditorScroller" >
21
+ <div :class =" $style.playgroundEditorScroller" :inert = " editorLoading " >
22
22
<div :class =" [$style.highlight, $style.playgroundEditorHighlight]" v-html =" editorHtml" ></div >
23
23
<textarea
24
24
ref =" inputEl"
31
31
:class =" $style.playgroundEditorTextarea"
32
32
></textarea >
33
33
</div >
34
+ <div v-if =" editorLoading" :class =" $style.playgroundEditorLoading" >
35
+ <div >Loading...</div >
36
+ </div >
34
37
</div >
35
38
</div >
36
39
<div :class =" $style.playgroundPaneRoot" >
40
43
<label for =" output" >Output</label >
41
44
<input type =" radio" id =" ast" v-model =" resultTab" value =" ast" >
42
45
<label for =" ast" >AST</label >
46
+ <input type =" radio" id =" metadata" v-model =" resultTab" value =" metadata" >
47
+ <label for =" metadata" >Metadata</label >
43
48
</div >
44
49
<div :class =" $style.playgroundResultActionsRight" >
45
50
<button :class =" [$style.playgroundButton]" @click =" clearLog" >Clear</button >
59
64
>{{ log.text }}</div >
60
65
</div >
61
66
<div v-else-if =" resultTab === 'ast'" :class =" $style.playgroundResultContent" >
62
- <div :class =" $style.highlight" v-html =" astHtml" ></div >
67
+ <div v-if =" isSyntaxError" class =" danger custom-block" >
68
+ <p class =" custom-block-title" >Syntax Error</p >
69
+ <p >See Output tab for details</p >
70
+ </div >
71
+ <div v-else :class =" $style.highlight" v-html =" astHtml" ></div >
72
+ </div >
73
+ <div v-else-if =" resultTab === 'metadata'" :class =" $style.playgroundResultContent" >
74
+ <div v-if =" isSyntaxError" class =" danger custom-block" >
75
+ <p class =" custom-block-title" >Syntax Error</p >
76
+ <p >See Output tab for details</p >
77
+ </div >
78
+ <div v-else-if =" metadata" :class =" $style.highlight" v-html =" metadataHtml" ></div >
79
+ <div v-else >No metadata</div >
63
80
</div >
64
81
</div >
65
82
</div >
@@ -85,9 +102,10 @@ const fizzbuzz = `for (let i, 100) {
85
102
\t\t else i
86
103
} ` ;
87
104
88
- const resultTab = ref <' output' | ' ast' >(' output' );
105
+ const resultTab = ref <' output' | ' ast' | ' metadata ' >(' output' );
89
106
90
107
// #region Editor
108
+ const editorLoading = ref (true );
91
109
const inputEl = useTemplateRef (' inputEl' );
92
110
const code = ref (fizzbuzz );
93
111
const editorHtml = ref (' ' );
@@ -159,23 +177,35 @@ const logs = ref<{
159
177
}[]>([]);
160
178
const logEl = useTemplateRef (' logEl' );
161
179
180
+ const isSyntaxError = ref (false );
181
+
162
182
const ast = ref <Ast .Node [] | null >(null );
163
183
const astHtml = ref (' ' );
164
184
185
+ const metadata = ref <unknown >(null );
186
+ const metadataHtml = ref (' ' );
187
+
165
188
function parse() {
189
+ isSyntaxError .value = false ;
190
+
166
191
if (parser != null ) {
167
192
try {
168
193
const _ast = parser .parse (code .value );
169
194
logs .value = [];
170
195
ast .value = _ast ;
196
+
197
+ const meta = Interpreter .collectMetadata (_ast );
198
+ metadata .value = meta ?.get (null ) ?? null ;
171
199
} catch (err ) {
172
200
if (err instanceof errors .AiScriptError ) {
173
201
logs .value = [{
174
202
text: ` [SyntaxError] ${err .name }: ${err .message } ` ,
175
203
type: ' error' ,
176
204
}];
205
+ isSyntaxError .value = true ;
177
206
}
178
207
ast .value = null ;
208
+ metadata .value = null ;
179
209
}
180
210
} else {
181
211
ast .value = null ;
@@ -299,6 +329,8 @@ const updateHash = useThrottle((d: HashData) => {
299
329
// #endregion
300
330
301
331
onMounted (async () => {
332
+ const loadStartedAt = Date .now ();
333
+
302
334
await init ();
303
335
initAiScriptEnv ();
304
336
@@ -324,7 +356,12 @@ onMounted(async () => {
324
356
}, { immediate: true });
325
357
326
358
watch (ast , async (newAst ) => {
327
- if (highlighter && newAst != null ) {
359
+ if (highlighter ) {
360
+ if (newAst == null ) {
361
+ astHtml .value = ' ' ;
362
+ return ;
363
+ }
364
+
328
365
astHtml .value = highlighter .codeToHtml (JSON .stringify (newAst , null , 2 ), {
329
366
lang: ' json' ,
330
367
themes: {
@@ -334,7 +371,31 @@ onMounted(async () => {
334
371
defaultColor: false ,
335
372
});
336
373
}
337
- });
374
+ }, { immediate: true });
375
+
376
+ watch (metadata , async (newMetadata ) => {
377
+ if (highlighter ) {
378
+ if (newMetadata == null ) {
379
+ metadataHtml .value = ' ' ;
380
+ return ;
381
+ }
382
+
383
+ metadataHtml .value = highlighter .codeToHtml (JSON .stringify (newMetadata , null , 2 ), {
384
+ lang: ' json' ,
385
+ themes: {
386
+ light: ' github-light' ,
387
+ dark: ' github-dark' ,
388
+ },
389
+ defaultColor: false ,
390
+ });
391
+ }
392
+ }, { immediate: true });
393
+
394
+ const loadEndedAt = Date .now ();
395
+
396
+ setTimeout (() => {
397
+ editorLoading .value = false ;
398
+ }, Math .max (0 , 500 - (loadEndedAt - loadStartedAt )));
338
399
});
339
400
340
401
onUnmounted (() => {
@@ -388,6 +449,19 @@ onUnmounted(() => {
388
449
overflow : scroll ;
389
450
}
390
451
452
+ .playgroundEditorLoading {
453
+ position : absolute ;
454
+ top : 0 ;
455
+ left : 0 ;
456
+ right : 0 ;
457
+ bottom : 0 ;
458
+ background-color : rgba (255 , 255 , 255 , 0.5 );
459
+ z-index : 1 ;
460
+ display : flex ;
461
+ justify-content : center ;
462
+ align-items : center ;
463
+ }
464
+
391
465
.playgroundEditorScroller {
392
466
position : relative ;
393
467
padding : 24px 36px ;
0 commit comments