VanillaJSとエディタ、VSCode実装について

~ガチのJS について~

はなだ のぶかず

  • 株式会社Groovenauts 
  • Shen / Lisp / Rust / Typescript / OCaml / Scalaなど
  • Viscuit / Scratch / Processing / Lispを子どもたちに指導
  • 言語実装が趣味(ビジュアル言語、テキスト言語つくるよ!)
  • GUIや音響プログラミングも研究したり(Direct Manipulation, Morphic, SuperColliderとか)
  • ボドゲはいいぞ

はなすこと

  • ずっといちばん私がいいたいこと
  • エディタの実装について
  • vscodeのデータ構造について

昨今のフロントエンドとかSPA について

  • 思うことはいっぱいある
  • 話をすることが難しいなと思っている
  • サーバーの様にフレームワークに沿って書くのが善であるように思われていうる

VanillaJSについて

  • フレームワークを前提として考えへのアンチテーゼ
  • キチンと設計や実装技術を重視する考え方
  • フレームワークはあくまで"プラグイン"

フレームワークは万能ではない

  • フレームワーク-> よくある実装パターンや設計をまとめて、楽をするもの
  • フロントエンドSPAもフレームワークを使えば楽をできる?
  • でもSPA(GUI)は、よくある実装パターンや設計がまとまっているだろうか?

GUI(SPA)は未だ

抽象化できない

  • GUIと一言で言ってもいっぱい:業務アプリ、ゲーム、テキストエディタ、カレンダーアプリ、地図アプリ、ビジュアル言語、チャットアプリ.....
  • 設計技術も実はたくさん: MVC、Document-View, MVVM、MVP、PAC、Morphic....
  • 実装技術もたくさん....枝刈り(Reactでやってるやつ)、gap buffer、ジェスチャーの実装、Direct Manipulationとか...
  • 音とかどうするの?

GUIは複雑である

  • コード量が多い
    • デザイン
    • 初期化、構築
    • インタラクション
      • 設計力、抽象化
  • 本質的に難しい
    • 非決定性、非同期、状態
  • 速度も重要
    • 素朴は実装はだいたい遅い

GUIは一度忘れ去られた

  • 古くは、Smalltalkから....(68マウスの誕生~90年代まで
  • 00年代、Webアプリがブレイク(GUIの実装技術はビジネスの場から一旦忘れ去られてしまった)
  • JSが盛り上がる(GmailやGoogle Mapなど)
  • スマホなど

だいたいのフレームワークは

新しくない

  • Reactの仮想Domですら(枝刈り)
  • Webの文化に合うようなマーケティング
  • FacebookやGithubはGUIの技術はもってない
    • でもFacebookのOSSのシャープなところは好きよ
      • PHPのコードをC++に変換するやつとか
  • Githubも使いにくいよね(Atomとか...)
  • MicrosoftとGoogle見ればいいよ(暴論)

どうすればいいか?

  • 歴史、過去について調べる
  • 他の設計に触れてみる(Morphicなど)
  • たくさん実装する、たくさん読む(JS以外も
  • フレームワーク自体を研究する
  • VanillaJS (以外とできるよ)

エディタの実装について

なぜVSCodeの話をするのか?

  • 新しい言語の実装を考えているから
  • VSCodeが何故軽快なのかしらべている
  • おもしろいから

テキストエディタについて

  • テキストを編集する
    • 挿入、削除、検索、置換....
  • テキストエディタ実装=文字列データ構造を調べる

テキストエディタ

キー入力

テキストデータ

テキスト表示

その他の実装

  • テキストの描画処理
  • 拡張機能
  • コマンド等

単純なテキストデータ構造

  • 配列
    • ランダムアクセスが早いO(1)
    • 挿入、削除がO(N)
  • 双方向リスト
    • ランダムアクセスが遅いO(N)
    • 挿入、削除がO(1)

代表的な実装

  • 行単位管理
  • Gap Buffer

行単位管理

改行で区切り一行を配列で管理する

 

行を双方向リストで管理

 

ほどんどのエディタはこれ

 

  • 一行が短かければ高速
  • 行のが長いと、遅い
  • 行のランダムアクセスができない。

行テキスト

行テキスト

行テキスト

Gap Buffer

動的な配列であり、編集箇所にGapをつくるデータ構造。

 

テキストエディタの編集箇所は基本的には局所化している。

 

Emacsがこれ。

はやい。でも行情報は別途管理が必要。

 

 

Gap

Gap

テキストデータ

テキストデータ

テキストデータ

VSCodeの実装

VSCodeについて

  • Electronで作られている
  • ChromiumでありHTML+JS+CSS
  • オープンソース
    • コードが読めるぜ!
    • ビルドもできるぜ!

ソースコードを読もう!

  • 僕なりのやりかた
  • 目的をまず決める
    • エディタがどうデータを管理しているか調べる
      • 1. どのように挿入してるか?
      • 2.どのように削除しているか?
  • 全部よまない
    • どのように分割されているか?
    • 全部読まないと分かんないのはクソ

ビルド、実行、デバック

  • ビルドする
  • 動かしてみる
  • 開発ツールを試す

全体を眺める

  • package.json
    • 依存の確認
    • npm scriptと見たりとか
  • src

欲しいものを探す

  • ほしいものはだいたい探しやすい
  • 検索してみる
  • 処理を追ってみる
  • 設計や実装技法を知ってるなら読むのが更に早くなる

VSCodeのコード

  • コメントが冗長じゃなくてよい
  • Typescriptなので型を手掛かりにできる
  • ちゃんと境界を引いて設計してる(気がする)
  • MVVMのモデル

Modelを探す

  • テキストデータを探す
  • Modelにある
  • Model ≠ State

PieceTreeTextBuffer

  • VSCodeのデータ構造
  • PieceTreeTextBuffer: エディタのテキストデータ
  • PieceTreeTextBufferBuilder: ビルダー
  • PieceTreeBase :  TextBufferの内部実装
  • rbTreeBase :  高速な平衡2分探索木の実装(赤黒木)

PieceTreeBase

export class PieceTreeBase {
    root!: TreeNode; // 赤黒木
    protected _buffers!: StringBuffer[]; // 文字列のバッファ
 ....


export class TreeNode {
        parent: TreeNode; // 親
	left: TreeNode;  // 左の子
	right: TreeNode; // 右の子
        color: NodeColor; // 赤黒木の色

        piece: Piece; // 
        size_left: number; // 左の木のサイズ

...


export class Piece {
	readonly bufferIndex: number; // バッファインデックス
	readonly start: BufferCursor; // バッファの最初の位置
	readonly end: BufferCursor; // バッファの最後の位置
	readonly length: number; //長さ
 
..

String Bufferの動き

行頭にabcを挿入

abc

String Buffer

テキストデータ

abc

aのあとに123を挿入

a123bc

abc123

3bを削除

a12c

abc123

aの前にxyz-を挿入

xyz-a12c

a12cxyz-

Piece

OK! Google ! Yes We Can!!!!!

StringBuffer

4

15

Piece

PieceはStringBufferの

文字列の始まりの位置と終わりの位置をもつ

PieceとTree

StringBuffer

kick base World Hello Nobukazu Hanada .

11

15

17

21

23

31

33

38

Piece0

Piece1

Piece2

Piece3

39

Piece4

Hello World Nobukazu Hanada .

テキストデータ

VSCodeのデータ構造

  • String Bufferにより、挿入文字列を末尾に挿入
    • 実際のテキスト編集箇所は関係ない
  • PieceTreeにより、String Bufferから文字列を構成する

その他の高速化処理

  • 操作の局所性を用いて、Pieceの検索のメモ化
  • String Bufferを分割する
  • トークナイズ

まとめ

  • 赤黒木などアルゴリズム大事
  • たのしい