Improve MisskeyPages

This commit is contained in:
syuilo 2019-05-01 10:05:33 +09:00
parent d0c8d537f5
commit 10216af48a
No known key found for this signature in database
GPG Key ID: BDC4C49D06AB9D69
3 changed files with 54 additions and 15 deletions

View File

@ -2036,12 +2036,18 @@ pages:
_numberToString: _numberToString:
arg1: "数値" arg1: "数値"
ref: "変数" ref: "変数"
in: "引数" in: "スロット入力"
_in: _in:
arg1: "スロット番号" arg1: "スロット番号"
fn: "関数" fn: "関数"
_fn: _fn:
slots: "スロット"
slots-info: "スロットひとつひとつを改行で区切ってください"
arg1: "出力" arg1: "出力"
for: "繰り返し"
_for:
arg1: "回数"
arg2: "処理"
typeError: "スロット{slot}は\"{expect}\"を受け付けますが、\"{actual}\"が入れられています!" typeError: "スロット{slot}は\"{expect}\"を受け付けますが、\"{actual}\"が入れられています!"
thereIsEmptySlot: "スロット{slot}が空です!" thereIsEmptySlot: "スロット{slot}が空です!"
types: types:

View File

@ -27,18 +27,27 @@ import {
faDice, faDice,
faSortNumericUp, faSortNumericUp,
faExchangeAlt, faExchangeAlt,
faRecycle,
} from '@fortawesome/free-solid-svg-icons'; } from '@fortawesome/free-solid-svg-icons';
import { faFlag } from '@fortawesome/free-regular-svg-icons'; import { faFlag } from '@fortawesome/free-regular-svg-icons';
import { version } from '../../config'; import { version } from '../../config';
export type Block = { export type Block<V = any> = {
id: string; id: string;
type: string; type: string;
args: Block[]; args: Block[];
value: any; value: V;
}; };
type FnBlock = Block<{
slots: {
name: string;
type: Type;
}[];
expression: Block;
}>;
export type Variable = Block & { export type Variable = Block & {
name: string; name: string;
}; };
@ -53,6 +62,7 @@ type TypeError = {
const funcDefs = { const funcDefs = {
if: { in: ['boolean', 0, 0], out: 0, category: 'flow', icon: faShareAlt, }, if: { in: ['boolean', 0, 0], out: 0, category: 'flow', icon: faShareAlt, },
for: { in: ['number', 'function'], out: 0, category: 'flow', icon: faRecycle, },
not: { in: ['boolean'], out: 'boolean', category: 'logical', icon: faFlag, }, not: { in: ['boolean'], out: 'boolean', category: 'logical', icon: faFlag, },
or: { in: ['boolean', 'boolean'], out: 'boolean', category: 'logical', icon: faFlag, }, or: { in: ['boolean', 'boolean'], out: 'boolean', category: 'logical', icon: faFlag, },
and: { in: ['boolean', 'boolean'], out: 'boolean', category: 'logical', icon: faFlag, }, and: { in: ['boolean', 'boolean'], out: 'boolean', category: 'logical', icon: faFlag, },
@ -99,6 +109,10 @@ const blockDefs = [
})) }))
]; ];
function isFnBlock(block: Block): block is FnBlock {
return block.type === 'fn';
}
type PageVar = { name: string; value: any; type: Type; }; type PageVar = { name: string; value: any; type: Type; };
const envVarsDef = { const envVarsDef = {
@ -326,7 +340,7 @@ export class AiScript {
@autobind @autobind
private interpolate(str: string, values: { name: string, value: any }[]) { private interpolate(str: string, values: { name: string, value: any }[]) {
return str.replace(/\{(.+?)\}/g, match => { return str.replace(/\{(.+?)\}/g, match => {
const v = this.getVariableValue(match.slice(1, -1).trim(), values); const v = this.getVarVal(match.slice(1, -1).trim(), values);
return v == null ? 'NULL' : v.toString(); return v == null ? 'NULL' : v.toString();
}); });
} }
@ -378,23 +392,23 @@ export class AiScript {
} }
if (block.type === 'ref') { if (block.type === 'ref') {
return this.getVariableValue(block.value, values); return this.getVarVal(block.value, values);
} }
if (block.type === 'in') { if (block.type === 'in') {
return slotArg[block.value]; return slotArg[block.value];
} }
if (block.type === 'fn') { // ユーザー関数定義 if (isFnBlock(block)) { // ユーザー関数定義
return { return {
slots: block.value.slots, slots: block.value.slots.map(x => x.name),
exec: slotArg => this.evaluate(block.value.expression, values, slotArg) exec: slotArg => this.evaluate(block.value.expression, values, slotArg)
}; };
} }
if (block.type.startsWith('fn:')) { // ユーザー関数呼び出し if (block.type.startsWith('fn:')) { // ユーザー関数呼び出し
const fnName = block.type.split(':')[1]; const fnName = block.type.split(':')[1];
const fn = this.getVariableValue(fnName, values); const fn = this.getVarVal(fnName, values);
for (let i = 0; i < fn.slots.length; i++) { for (let i = 0; i < fn.slots.length; i++) {
const name = fn.slots[i]; const name = fn.slots[i];
slotArg[name] = this.evaluate(block.args[i], values); slotArg[name] = this.evaluate(block.args[i], values);
@ -418,6 +432,14 @@ export class AiScript {
or: (a, b) => a || b, or: (a, b) => a || b,
and: (a, b) => a && b, and: (a, b) => a && b,
if: (bool, a, b) => bool ? a : b, if: (bool, a, b) => bool ? a : b,
for: (times, fn) => {
const result = [];
for (let i = 0; i < times; i++) {
slotArg[fn.slots[0]] = i + 1;
result.push(fn.exec(slotArg));
}
return result;
},
add: (a, b) => a + b, add: (a, b) => a + b,
subtract: (a, b) => a - b, subtract: (a, b) => a - b,
multiply: (a, b) => a * b, multiply: (a, b) => a * b,
@ -449,8 +471,13 @@ export class AiScript {
return fn(...args); return fn(...args);
} }
/**
*
* @param name
* @param values
*/
@autobind @autobind
private getVariableValue(name: string, values: { name: string, value: any }[]): any { private getVarVal(name: string, values: { name: string, value: any }[]): any {
const v = values.find(v => v.name === name); const v = values.find(v => v.name === name);
if (v) { if (v) {
return v.value; return v.value;

View File

@ -35,15 +35,18 @@
</section> </section>
<section v-else-if="value.type === 'in'" class="hpdwcrvs"> <section v-else-if="value.type === 'in'" class="hpdwcrvs">
<select v-model="value.value"> <select v-model="value.value">
<option v-for="v in fnSlots" :value="v">{{ v }}</option> <option v-for="v in fnSlots" :value="v.name">{{ v.name }}</option>
</select> </select>
</section> </section>
<section v-else-if="value.type === 'fn'" class="" style="padding:16px;"> <section v-else-if="value.type === 'fn'" class="" style="padding:0 16px 16px 16px;">
<ui-textarea v-model="slots"></ui-textarea> <ui-textarea v-model="slots">
<span>{{ $t('script.blocks._fn.slots') }}</span>
<template #desc>{{ $t('script.blocks._fn.slots-info') }}</template>
</ui-textarea>
<x-v v-if="value.value.expression" v-model="value.value.expression" :title="$t(`script.blocks._fn.arg1`)" :get-expected-type="() => null" :ai-script="aiScript" :fn-slots="value.value.slots" :name="name"/> <x-v v-if="value.value.expression" v-model="value.value.expression" :title="$t(`script.blocks._fn.arg1`)" :get-expected-type="() => null" :ai-script="aiScript" :fn-slots="value.value.slots" :name="name"/>
</section> </section>
<section v-else-if="value.type.startsWith('fn:')" class="" style="padding:16px;"> <section v-else-if="value.type.startsWith('fn:')" class="" style="padding:16px;">
<x-v v-for="(x, i) in value.args" v-model="value.args[i]" :title="aiScript.getVarByName(value.type.split(':')[1]).value.slots[i]" :get-expected-type="() => null" :ai-script="aiScript" :name="name" :key="i"/> <x-v v-for="(x, i) in value.args" v-model="value.args[i]" :title="aiScript.getVarByName(value.type.split(':')[1]).value.slots[i].name" :get-expected-type="() => null" :ai-script="aiScript" :name="name" :key="i"/>
</section> </section>
<section v-else class="" style="padding:16px;"> <section v-else class="" style="padding:16px;">
<x-v v-for="(x, i) in value.args" v-model="value.args[i]" :title="$t(`script.blocks._${value.type}.arg${i + 1}`)" :get-expected-type="() => _getExpectedType(i)" :ai-script="aiScript" :name="name" :fn-slots="fnSlots" :key="i"/> <x-v v-for="(x, i) in value.args" v-model="value.args[i]" :title="$t(`script.blocks._${value.type}.arg${i + 1}`)" :get-expected-type="() => _getExpectedType(i)" :ai-script="aiScript" :name="name" :fn-slots="fnSlots" :key="i"/>
@ -118,7 +121,10 @@ export default Vue.extend({
watch: { watch: {
slots() { slots() {
this.value.value.slots = this.slots.split('\n'); this.value.value.slots = this.slots.split('\n').map(x => ({
name: x,
type: null
}));
} }
}, },
@ -129,7 +135,7 @@ export default Vue.extend({
created() { created() {
if (this.value.value == null) Vue.set(this.value, 'value', null); if (this.value.value == null) Vue.set(this.value, 'value', null);
if (this.value.value && this.value.value.slots) this.slots = this.value.value.slots.join('\n'); if (this.value.value && this.value.value.slots) this.slots = this.value.value.slots.map(x => x.name).join('\n');
this.$watch('value.type', (t) => { this.$watch('value.type', (t) => {
this.warn = null; this.warn = null;