misskey-dev / misskey

🌎 A completely free and open interplanetary microblogging platform 🚀
https://misskey-hub.net/
GNU Affero General Public License v3.0
9.99k stars 1.36k forks source link

Pagesの非AiScript変数を廃止 #8034

Closed syuilo closed 1 year ago

syuilo commented 2 years ago

Summary

AiScriptとは別に、Pagesとしての変数という概念があるのは、実装が複雑になり、ユーザーの理解も難しくなる

そこで、変数機能はAiScriptのものに統一したい

とはいえ全てAiScriptで書かなければならないというのは、Pagesの「プログラムが分からなくても、グラフィカルに動的なコンテンツを作れる」という利点を失うことになるため、Pages変数を「AiScript変数をグラフィカルに定義できる機能」としたい 内部的にAiScriptにコンパイルされて、ランタイムには関わらない

乱数に関しては、各種乱数生成関数をAiScriptランタイムに提供する。

「乱数をリセット」ボタンを押した際の処理は、Pagesシードを再生成して、AiScriptランタイムのMkPages:updated関数を呼び出すようにする? もしくはそもそも乱数リセットボタン自体不要になる?

syuilo commented 2 years ago

大きな変更になるから、今までに作られたPagesをどうするか考えないといけない

syuilo commented 2 years ago

選択肢1

Pagesにバージョンが判別できるフラグを追加して、旧と新で処理を分ける

pros

cons

選択肢2

古いPagesを移行する処理を実装する

pros

cons

marihachi commented 2 years ago

2は必ず移行できるか分からないかも。 将来的な変更で、移行できない要素が出てくる可能性はある。

marihachi commented 2 years ago

1はバージョンごとで構造を分けられれば複雑さはある程度抑えられそうに見える Pages関係の根本から全部別にするとか 共通となってる部分を変更しても影響しないほうが、今後のメンテナンスがしやすくなる

syuilo commented 2 years ago

ついでにAiScriptのバージョンも上げたいことを考えると1かも

marihachi commented 2 years ago

ページ変数はAiScriptと同じで順次処理に変更って認識かな

syuilo commented 2 years ago

そうね

marihachi commented 2 years ago

今考えてるところまでまとめた。 入力ブロック関係、その他は未検討。まだ大体の雰囲気のレベル。

hpml.variables

ページ変数の構造データ。 AiScriptコードに変換される元データとなる。

hpml.vars

各種コンポーネント向けに変数テーブルを公開する。

hpml.collectVars()

AiScript変数の内容を変数テーブル(hpml.vars)に集める。 今までページ変数で行っていたような評価は行わず、単純に変数の内容を拾う。

AiScriptのonUpdated

AiScript変数の更新を受けて、hpml.collectVarsを実行する。

ページで使える変数

ページで直接使える変数はルートスコープで定義され、且つページ変数のAttributeが付加されている変数のみ。

syuilo commented 2 years ago

🆒

marihachi commented 2 years ago

検討点

AiScriptは上から順に実行されるので、変数がスコープに追加されるまでの間は変数が定義されていない。 そのタイミングの変数値をページ上にどう表示するか。

思いつくのはこんな感じ:

Aはスクリプトっぽい。 Bのほうがキレイそうではある。ちょっとコンパイル言語っぽいアプローチ。初期値を静的な式として与えることもできそう(AiScript側の変更が必要かも)。

syuilo commented 2 years ago

AiScript走らせ始めた後にページレンダリングするようにするのはどうだろう

marihachi commented 2 years ago

AiScript走らせ始めた後にページレンダリングするようにするのはどうだろう

スクリプトの実行終わりが分からない気がする イベント処理は後からも実行されるだろうし

syuilo commented 2 years ago

AiScript側にスクリプトの最後の行まで実行したことを検知できるイベント実装するとか(Pages関係なく有益そう)

marihachi commented 2 years ago

良さそう。イベントを見てページレンダリングする感じでいくか

marihachi commented 2 years ago

Related #5489

marihachi commented 2 years ago

入力ブロックとかの仕様を考え始めてる。本当にこれでいけるかは不明。

仕様案1

ブロック

全てのブロックはAiScript変数(hpml.scriptVars)の内容を使用してレンダリングする。

入力ブロックとAiScript上の入力ブロック変数

入力ブロックの値の変更時は、MkPages:updatedイベントの発火とAiScript変数(hpml.scriptVars)の再収集を行う。 エディタ上で入力ブロックが追加されると、InputVarAttrを付加したAiScript変数を自動生成する。このAttributeは入力ブロック変数として認識させるためのAttribute。 AiScriptコードのパース以降の段階で、InputVarAttrが付加された全変数に対して以下の処理を行う: ・入力ブロック変数への代入処理をMkPages:updatedイベント内に追加(判定処理を挟んで必要に応じて代入をキャンセルできることが望ましい)。

副産物として、常にAiScriptを経由して入力ブロックを扱うようになるためAiScriptだけで入力ブロックの追加を行うことができるようになる。

marihachi commented 2 years ago

AiScriptだけで入力ブロックの追加はやりにくそう そもそもAiScriptではブロックの構造定義がやりにくいので、グラフィカルな操作で編集するほうが便利そう。

kabo2468 commented 2 years ago

手間はかかるけどScratch的なビジュアルエディタだとやりやすそう

marihachi commented 2 years ago

仕様案1.1

コンセプト

ページで使用できるAiScript変数

ルートスコープに、export属性を付加して変数を定義するとページで使用できるようになる。

入力ブロック変数

exportが付加された変数の内、input属性が付加された変数は入力ブロックの値を保持する変数として機能する。

変数値の埋め込み

AiScript変数をテキストブロック等に埋め込むことができる。

ユーザーが入力した値へのアクセス

AiScriptが大元の変数値を保持している。 export+input属性を付加することで変数を外部に公開し、MkPages:updatedイベントから入力ブロックの値の変化を変数に反映することで、 入力ブロックとAiScript変数が相互作用する。

実装

今までページ変数で行っていたような評価(旧hpml.eval())は行わず、AiScriptインタプリタの実行結果から変数値を収集する。

AiScript変数値の保持

AiScript変数に関する全ての情報はhpml.variableInfosに保持され、変数値のコピーがhpml.varsに保持される(レンダリング専用)。

ブロック

全てのブロックはexportされた変数(hpml.vars)を使用してレンダリングされる。

入力ブロックとAiScript上の入力ブロック変数

エディタ上で入力ブロックが追加されると、exportとinput属性を付加したAiScript変数をAST上に追加する。 AiScriptコードのパース以降の段階で、export&input属性が付加された全変数に対して以下の処理を行う: ・入力ブロック変数への代入処理をMkPages:updatedイベント内に追加(判定処理を挟んで必要に応じて代入をキャンセルできることが望ましい)。

入力ブロックの値の変更時は、MkPages:updatedイベントが発行される。 AiScript側はこのMkPages:updatedをトリガとして変数の値を変更する。 変更が行われると、変数スコープのonUpdatedイベントが発行される。

AiScript変数値のリフレッシュ

AiScript変数の値は以下のタイミングで再取得(リフレッシュ)される: ・スクリプトが最後の行まで実行された時。初回取得。 ・変数スコープのonUpdatedイベントが発行された時。値が変更されると随時発行される。 ※onUpdatedイベントが発生した際に現状では更新された変数が識別できないため、hpml.refreshVars()を実行して全体のリフレッシュを行う。

全体フロー

  1. buildAst()
  2. collectVars()
  3. run()
  4. 最後の行まで実行されたタイミングでrefreshVars()
  5. 変数値の変更されたタイミングで随時refreshVars()

Hpmlクラス

variables [途中]

ページ変数のモデルデータ。 AiScriptのASTに変換される元データとなる。

ast

AiScriptインタプリタで実行するAST。

variableInfos

AiScript変数に関する全ての情報を保持する。

vars

各種コンポーネント向けに変数テーブルを公開する。

buildAst()

AiScriptパーサでASTを生成。 hpml.variablesを解釈しASTを組み換える。

collectVars()

ASTの解析によってAiScript変数の各種情報(付加されているAttirubte等)をhpml.variableInfosに収集する。 変数値については別途hpml.refreshVars()で収集する。

refreshVars()

インタプリタのスコープ(実行コンテキスト)からAiScript変数の値を取得し、値をvariableInfosおよびhpml.varsに収集する。 収集対象の変数はhpml.variableInfosにある変数名に限定される。

updatePageVar()

run()

AiScriptインタプリタがASTを実行

abort()

AiScriptインタプリタの実行を中止

marihachi commented 2 years ago

入力ブロックの値の変更でMkPages:updatedイベント発行→AiScriptの関数呼び出し→AiScript側で変数値を更新→onUpdatedイベント発行→hpml.varsへの反映 っていう流れが結構時間がかかりそうという懸念がある。 時間がかかるなら別のアプローチを取ることになるかも

marihachi commented 2 years ago

数値入力ブロックと表示変数10個で動かしてみた。これくらいで少しカクつきはじめた。 処理にまだ改善の余地があるので、もうちょっと軽くなる見込みがある。

marihachi commented 2 years ago

@syuilo おそらくかなりwipなPRを投げる感じになると思うので、upstream側に作業ブランチが欲しい。 (直接developに取り込むわけにはいかないので) よろしくお願いします。

syuilo commented 2 years ago

む、ブランチって勝手に作れないっけ

syuilo commented 2 years ago

権限付与した

marihachi commented 2 years ago

しゅいろありがとう:pray:

marihachi commented 2 years ago

ブランチ作った https://github.com/misskey-dev/misskey/tree/refine-pages

marihachi commented 2 years ago

処理の改善をしてみたけど、予想に反してあまり改善しなかった ボトルネックが別にある

marihachi commented 2 years ago

一旦PR投げた。

futchitwo commented 1 year ago

Misskey Play できて動的 Pages 廃止になったからclose?

syuilo commented 1 year ago

そういやまだ

乱数に関しては、各種乱数生成関数をAiScriptランタイムに提供する。

  • シードを受け取り乱数を返す関数
  • Pagesシードが設定済みの乱数を返す関数
  • 日ごとのシードが設定済みの乱数を返す関数

が出来てない

futchitwo commented 1 year ago

そういやまだ

乱数に関しては、各種乱数生成関数をAiScriptランタイムに提供する。

  • シードを受け取り乱数を返す関数
  • Pagesシードが設定済みの乱数を返す関数
  • 日ごとのシードが設定済みの乱数を返す関数

が出来てない

シードから乱数生成関数を返す関数ならすでにある(Math:gen_rng) それを利用して他のも作れそう(ただ組み込み関数はあったほうが便利かもしれない)