paricafe/src/client/widgets/aiscript.vue

165 lines
3 KiB
Vue

<template>
<MkContainer :show-header="props.showHeader">
<template #header><Fa :icon="faTerminal"/>{{ $ts._widgets.aiscript }}</template>
<div class="uylguesu _monospace">
<textarea v-model="props.script" placeholder="(1 + 1)"></textarea>
<button @click="run" class="_buttonPrimary">RUN</button>
<div class="logs">
<div v-for="log in logs" class="log" :key="log.id" :class="{ print: log.print }">{{ log.text }}</div>
</div>
</div>
</MkContainer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { faTerminal } from '@fortawesome/free-solid-svg-icons';
import MkContainer from '@/components/ui/container.vue';
import define from './define';
import * as os from '@/os';
import { AiScript, parse, utils } from '@syuilo/aiscript';
import { createAiScriptEnv } from '@/scripts/aiscript/api';
const widget = define({
name: 'aiscript',
props: () => ({
showHeader: {
type: 'boolean',
default: true,
},
script: {
type: 'string',
multiline: true,
default: '(1 + 1)',
hidden: true,
},
})
});
export default defineComponent({
extends: widget,
components: {
MkContainer
},
data() {
return {
logs: [],
faTerminal
};
},
methods: {
async run() {
this.logs = [];
const aiscript = new AiScript(createAiScriptEnv({
storageKey: 'widget',
token: this.$i?.token,
}), {
in: (q) => {
return new Promise(ok => {
os.dialog({
title: q,
input: {}
}).then(({ canceled, result: a }) => {
ok(a);
});
});
},
out: (value) => {
this.logs.push({
id: Math.random(),
text: value.type === 'str' ? value.value : utils.valToString(value),
print: true
});
},
log: (type, params) => {
switch (type) {
case 'end': this.logs.push({
id: Math.random(),
text: utils.valToString(params.val, true),
print: false
}); break;
default: break;
}
}
});
let ast;
try {
ast = parse(this.props.script);
} catch (e) {
os.dialog({
type: 'error',
text: 'Syntax error :('
});
return;
}
try {
await aiscript.exec(ast);
} catch (e) {
os.dialog({
type: 'error',
text: e
});
}
},
}
});
</script>
<style lang="scss" scoped>
.uylguesu {
text-align: right;
> textarea {
display: block;
width: 100%;
max-width: 100%;
min-width: 100%;
padding: 16px;
color: var(--fg);
background: transparent;
border: none;
border-bottom: solid 1px var(--divider);
border-radius: 0;
box-sizing: border-box;
font: inherit;
&:focus {
outline: none;
}
}
> button {
display: inline-block;
margin: 8px;
padding: 0 10px;
height: 28px;
outline: none;
border-radius: 4px;
&:disabled {
opacity: 0.7;
cursor: default;
}
}
> .logs {
border-top: solid 1px var(--divider);
text-align: left;
padding: 16px;
&:empty {
display: none;
}
> .log {
&:not(.print) {
opacity: 0.7;
}
}
}
}
</style>