コードとビジュアルの双方向編集なエディタを試作して ビジュアルプログラミングについて考えてみた
nocodetypescriptby mizchi created at 2020/07/05/16:56
ノーコードは形を変えた現代の RPG ツクールなのではないか - mizdev の記事では、ノーコードのビジュアルプログラミングが発展性を欠く理由として、次の理由を挙げました。
汎用的なビジュアルプログラミング基盤(Scratch みたいなものではなくプロユースなもの)
↑ 上でのビジュアル環境でのデータベースのグラフ構造のビジュアル化手法
↑ 上でのビジュアル環境でのパイプラインのビジュアル化手法
↑ 上での UI とデータと UI のマッピングのビジュアル化手法
これらを隠蔽してオートスケールするマネージレスなインフラ基盤(これはパイプライン実装の中身)
で、こんなものを作った話
現代の Intellisense + Formatter 感覚
TypeScript の補完と、保存の度に prettier をバリバリに効かせた状態でプログラミングをしていると、そもそも自由文脈でコードを書いているというよりは、型推論と AST(抽象構文木)の木構造上の制約に従ってフォームの値を埋める、という感覚が支配的になってきます。これは TypeScript に限らず、型推論と formatter がある言語では、似たような感覚を得ることができるでしょう。
結果として導かれる一つの結論、「プログラマが編集する対象はプレーンテキストではなく AST である」とすると、AST を操作する UI を提供すれば、それはやはりテキストプログラミングと同じ表現力を持つはずだ、ということになるはずです。
先のノーコードの記事で例に挙げた RPG ツクールで言うと、ツクールのイベントエディタで高水準命令を書いていくことは、関数呼び出しを羅列するエディタ上での編集ということもできます。
ビジュアルプログラミング基盤を作る
ビジュアルプログラミングでも求められる表現力が結局チューリング完全ならば、ビジュアルプログラミング基盤として最初に必要なのは、コードをテキストプログラミングとビジュアルエディタの 2 つで編集できて、かつその変更が双方向に反映される、というのが、基盤を作る場合の最初の出発点ではないか?と考えました。
AST をマスターデータとして、コードとビジュアルエディタ双方を生成するイメージです。
AST を抽象的に操作するが、コードで可能な表現力は落とさない UI を提供するのが最終的なゴールですが、一旦は定数の置換、そして簡易な行の追加ができれば良いと考え、React + TypeScript で実装してみました。
demo: https://zealous-almeida-959860.netlify.app/
(monaco editor とか typescript service とか読み込んでるので重いです)
コードはこちら
- コードと、コードのように表示されたビジュアルエディタで、双方向に編集可能
- 今のところ、対応しているのは 文字列/数値/真偽値/ブロック末尾への行の追加
他に実装できそうなアイデア
const flag = true;
のような定数宣言のノードだけを表示して、そのスクリプトを実行するための設定画面を自動生成する- styled-components の
styled
のタグテンプレートを収集し、 CSS エディタのように見せて編集する - JSXElement ノードを編集・プレビューする GUI の HTML エディタをモーダルで出し、編集が終わると JSXElement ノードに反映
- 型情報に従って identifier の置換候補を表示
- ゲームエンジンの実行環境として組み込む
- makecode
TypeScript で実装したのは(自分が一番得意な言語であるのとは別に)、UI の実行環境でコンパイラの情報にアクセスできるからです。とくにスコープ内の変数情報、その型情報を持っているのが、入力支援で有意義なはずです。(まだ実装していませんが…)
実は、このコードと UI の双方向変換には先行実装があります。Microsoft のビジュアルプログラミングツールです。
microsoft/pxt-blockly: Blockly (Microsoft MakeCode fork)
blockly から TypeScript を生成するツールですね。これも頑張れば組み込めるかもしれませんが、現状、プロユースの支援ツールとしてはあまり有効に見えないので、組み込みは保留しています。
他、ocaml のプログラミング支援として、型を専用の図形で blockly で表現する、という研究もあります。(御茶ノ水の浅井研ですね…)
この辺は blockly を使う研究が多いです。
プログラミング学習支援に使えそう
このツールは、プログラミング支援文脈でも使えると思っています。とくに最初は理解が難しいパーサと構文という概念を掴むのに有用です。
定数だけ触れる、配列を書ける、ような状態からはじめて、段階的にビジュアルエディタの「補助輪」を外していく、というような機能が将来的に提供できると思います。
また、他人のコードを触ることへの恐怖感を抑えるために、構文レベルで編集可能な機能を制限できたりします。
ここから先は、機能ごとに見せ方を工夫していく必要があるでしょう。
- JSON を書ける
- 論理式が書ける
- 条件分岐が書ける
- ループが書ける
- 関数呼び出しができる
- 関数定義ができる
- ジェネリクスが扱える
- 型を合わせる
AST ノードごとに、より良い編集方式の見せ方を考える必要があり、ここから先は SIGPX あたりの先行研究をみていくつもりです。
SIGPX: Special Interest Group on Programming Experience
一緒にやる人の募集
- コード表示部分で decorator / generator / else if などの未実装部分
- とりあえず全部のノードを、なんらかの UI で編集可能にする
- for や object のノードごとの編集方式の提案と実装
- makecode のような高水準命令 UI を被せる
- UI は興味ないけど、とりあえず TypeScript Compiler API と仲良くなりたい
コードの概説
以下、コミットしたい人へのコードの解説です。
vistree
コードを表示しつつ、その置換を行うライブラリ。
一番簡単な例。
import React from "react";
import ts from "typescript";
import { VisualTree, CodeRenderer, useRendererContext } from "@mizchi/viztree";
type EditableContext = {};
export function SimpleTree() {
const source = ts.createSourceFile(
"/index.ts",
'export const x: string = "hello";',
ts.ScriptTarget.Latest
);
return <VisualTree renderer={Renderer} root={source} context={{}} />;
}
// Render tree recursively.
function Renderer({ tree }: { tree: ts.Node }) {
// get context
const { context } = useRendererContext<EditableContext>();
switch (tree.kind) {
case ts.SyntaxKind.StringLiteral: {
const t = tree as ts.StringLiteral;
return <span style={{ color: "red" }}>{t.text} as string</span>;
}
default: {
return <CodeRenderer tree={tree} />;
}
}
}
switch case でリテラルごとにノードを置き換えていくと、カスタマイズしたコードの表示ができます。
vistree-editable
↑ の置換機能を使って、双方向編集なノードを実装したもの。
ゼロから自作したい人は、これをフォークするといいかも。
workspace
↑ を Monaco Editor で編集したコードと双方向編集する実装。
やっていき
思いつき次第実装を足していきます
他、参考になりそうな実装
- red/red: Red is a next-generation programming language strongly inspired by Rebol, but with a broader field of usage thanks to its native-code compiler, from system programming to high-level scripting and cross-platform reactive GUI, while providing modern support for concurrency, all in a zero-install, zero-config, single 1MB file!
- baku89/glisp: Self-bootstrapping graphic design tool on Lisp