Skip to content

Commit b8f36bf

Browse files
playground機能
1 parent 17b0fd3 commit b8f36bf

File tree

11 files changed

+486
-242
lines changed

11 files changed

+486
-242
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<template>
2+
<div :class="$style.playgroundRoot">
3+
<div :class="$style.playgroundButtons">
4+
<button @click="run">Run</button>
5+
</div>
6+
<div :class="$style.playgroundLogs">
7+
<div v-for="log in logs" :key="log" :class="$style.playgroundLogItem">{{ log }}</div>
8+
</div>
9+
</div>
10+
</template>
11+
12+
<script setup lang="ts">
13+
import { ref } from 'vue';
14+
import type { Interpreter, Parser, utils as aisUtils } from '@syuilo/aiscript';
15+
16+
const props = defineProps<{
17+
code: string;
18+
}>();
19+
20+
const logs = ref<string[]>([]);
21+
22+
let ParserClass: typeof Parser | null = null;
23+
let InterpreterClass: typeof Interpreter | null = null;
24+
let utils: typeof aisUtils | null = null;
25+
26+
let parser: Parser | null = null;
27+
let interpreter: Interpreter | null = null;
28+
29+
async function run() {
30+
logs.value = ['[Playground] Loading...'];
31+
if (!ParserClass || !InterpreterClass || !utils) {
32+
const [
33+
{ Parser, Interpreter, utils: importedUtils },
34+
] = await Promise.all([
35+
import('@syuilo/aiscript'),
36+
new Promise((resolve) => setTimeout(resolve, 250)),
37+
]);
38+
ParserClass = Parser;
39+
InterpreterClass = Interpreter;
40+
utils = importedUtils;
41+
} else {
42+
await new Promise((resolve) => setTimeout(resolve, 250));
43+
}
44+
if (!parser) {
45+
parser = new ParserClass();
46+
}
47+
if (interpreter) {
48+
interpreter.abort();
49+
}
50+
interpreter = new InterpreterClass({}, {
51+
out: (value) => {
52+
logs.value.push(value.type === 'num' ? value.value.toString() : value.type === 'str' ? value.value : utils.valToString(value));
53+
},
54+
});
55+
56+
logs.value = [];
57+
58+
const ast = parser.parse(props.code);
59+
await interpreter.exec(ast);
60+
}
61+
</script>
62+
63+
<style module>
64+
.playgroundRoot {
65+
border-top: 1px solid var(--vp-c-divider);
66+
padding: 12px 24px;
67+
display: grid;
68+
grid-template-columns: auto 1fr;
69+
gap: 12px;
70+
}
71+
72+
.playgroundButtons button {
73+
background-color: var(--vp-button-brand-bg);
74+
color: var(--vp-button-brand-text);
75+
font-weight: 700;
76+
transition: background-color 0.25s;
77+
padding: 4px 16px;
78+
border-radius: 8px;
79+
cursor: pointer;
80+
}
81+
82+
.playgroundButtons button:hover {
83+
color: var(--vp-button-brand-hover-text);
84+
background-color: var(--vp-button-brand-hover-bg);
85+
}
86+
87+
.playgroundLogs {
88+
background-color: var(--vp-c-bg);
89+
padding: 12px;
90+
min-height: 120px;
91+
max-height: 400px;
92+
overflow-y: auto;
93+
border-radius: 8px;
94+
display: flex;
95+
flex-direction: column;
96+
gap: 4px;
97+
}
98+
99+
.playgroundLogItem {
100+
font-family: var(--vp-font-family-mono);
101+
white-space: pre-wrap;
102+
font-size: 14px;
103+
}
104+
</style>

.vitepress/config.mts

Lines changed: 0 additions & 50 deletions
This file was deleted.

.vitepress/config/en.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { defineConfig, type DefaultTheme } from 'vitepress';
2+
3+
const guideNav: DefaultTheme.SidebarItem[] = [
4+
{ text: 'Introduction', link: 'get-started' },
5+
{ text: 'Execution', link: 'execution' },
6+
];
7+
8+
const referenceNav: DefaultTheme.SidebarItem[] = [
9+
{ text: 'Syntax', link: 'syntax' },
10+
{ text: 'Built-in Properties', link: 'builtin-props' },
11+
{ text: 'Keywords', link: 'keywords' },
12+
{ text: 'Literal Expressions', link: 'literals' },
13+
{ text: 'Built-in Functions', link: 'std' },
14+
{ text: 'Built-in Functions (Math)', link: 'std-math' },
15+
];
16+
17+
export const en = defineConfig({
18+
lang: 'en-US',
19+
description: 'A user script language for browsers',
20+
21+
themeConfig: {
22+
sidebar: {
23+
'/en/guides/': { base: '/en/guides/', items: guideNav },
24+
'/en/references/': { base: '/en/references/', items: referenceNav },
25+
},
26+
},
27+
});

.vitepress/config/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { defineConfig } from 'vitepress';
2+
import { shared } from './shared';
3+
import { ja } from './ja';
4+
import { en } from './en';
5+
6+
export default defineConfig({
7+
...shared,
8+
locales: {
9+
ja: { label: '日本語', ...ja },
10+
en: { label: 'English', ...en },
11+
},
12+
});

.vitepress/config/ja.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { defineConfig, type DefaultTheme } from 'vitepress';
2+
3+
const nav: DefaultTheme.NavItem[] = [
4+
{ text: 'ガイド', link: '/ja/guides/get-started' },
5+
{ text: 'リファレンス', link: '/ja/references/syntax' },
6+
];
7+
8+
const guideNav: DefaultTheme.SidebarItem[] = [
9+
{
10+
text: 'AiScriptを使ってみよう',
11+
items: [
12+
{ text: 'はじめに', link: 'get-started' },
13+
{ text: '実行方法', link: 'execution' },
14+
],
15+
},
16+
{ text: 'リファレンス', base: '/ja/references/', link: 'syntax' },
17+
];
18+
19+
const referenceNav: DefaultTheme.SidebarItem[] = [
20+
{ text: '構文', link: 'syntax' },
21+
{ text: '組み込みプロパティ', link: 'builtin-props' },
22+
{ text: '予約語', link: 'keywords' },
23+
{ text: 'リテラル式', link: 'literals' },
24+
{ text: '組み込み関数', link: 'std' },
25+
{ text: '組み込み関数(Math)', link: 'std-math' },
26+
];
27+
28+
export const ja = defineConfig({
29+
lang: 'ja-JP',
30+
description: 'ブラウザで動く、ユーザースクリプト用言語',
31+
32+
themeConfig: {
33+
nav,
34+
35+
sidebar: {
36+
'/ja/guides/': {
37+
base: '/ja/guides/',
38+
items: guideNav,
39+
},
40+
'/ja/references/': { base: '/ja/references/', items: referenceNav },
41+
},
42+
},
43+
});

.vitepress/config/shared.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { defineConfig } from 'vitepress';
2+
import aiscriptTmLanguage from 'aiscript-vscode/aiscript/syntaxes/aiscript.tmLanguage.json' assert { type: 'json' };
3+
import { createPlaygroundTransformer } from '../scripts/playground-transformer';
4+
5+
// https://vitepress.dev/reference/site-config
6+
export const shared = defineConfig({
7+
title: 'AiScript',
8+
srcDir: 'docs',
9+
10+
markdown: {
11+
codeTransformers: [
12+
createPlaygroundTransformer(),
13+
],
14+
languages: [
15+
aiscriptTmLanguage as any,
16+
],
17+
},
18+
})
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { ShikiTransformer } from 'shiki';
2+
3+
function escapeHtml(string: string): string {
4+
return string.replace(/[&'`"<>]/g, (match) => {
5+
return {
6+
'&': '&amp;',
7+
"'": '&#x27;',
8+
'`': '&#x60;',
9+
'"': '&quot;',
10+
'<': '&lt;',
11+
'>': '&gt;',
12+
}[match] || match;
13+
});
14+
}
15+
16+
export function createPlaygroundTransformer(): ShikiTransformer {
17+
let codeRaw: string | null = null;
18+
19+
return {
20+
preprocess: (code, options) => {
21+
if (options.lang !== 'aiscript' || !options.meta?.__raw?.includes('playground')) return;
22+
codeRaw = code;
23+
},
24+
postprocess: (html, options) => {
25+
if (options.lang !== 'aiscript' || !options.meta?.__raw?.includes('playground') || codeRaw == null) return;
26+
return `${html}<Playground code="${escapeHtml(codeRaw)}"></Playground>`;
27+
},
28+
};
29+
}

.vitepress/theme/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { h } from 'vue'
33
import type { Theme } from 'vitepress'
44
import DefaultTheme from 'vitepress/theme'
55
import './style.css'
6+
import Playground from '../components/Playground.vue'
67

78
export default {
89
extends: DefaultTheme,
@@ -12,6 +13,6 @@ export default {
1213
})
1314
},
1415
enhanceApp({ app, router, siteData }) {
15-
// ...
16+
app.component('Playground', Playground);
1617
}
1718
} satisfies Theme

.vitepress/types.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="vite/client" />

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
{
2+
"name": "aiscript-docs",
3+
"type": "module",
24
"scripts": {
35
"dev": "vitepress dev",
46
"build": "vitepress build",
57
"preview": "vitepress preview"
68
},
79
"devDependencies": {
10+
"@syuilo/aiscript": "^0.19.0",
811
"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.11",
12+
"shiki": "^1.23.1",
13+
"vite": "^5.4.11",
914
"vitepress": "^1.1.4",
1015
"vue": "^3.4.25"
1116
}

0 commit comments

Comments
 (0)