Wordgard 0.1 リリース
(marijnhaverbeke.nl)- Wordgard 0.1は、ProseMirror安定化後の9年間の経験とCodeMirror 6の設計を反映して新たに作られたJavaScriptリッチテキストエディタライブラリ
- 既存のProseMirrorを2.0に置き換えたり1.xに継ぎ足したりせず、互換性の負担がない新しいAPIと別名で再設計
- 中核設計ではstepsの代わりに変更セクションベースのモデルを使い、独立したノード・マーク型とCodeMirror流のfacet拡張システムを組み合わせる
- ブラウザの選択動作への依存を減らし、ポインタ・キーボード選択を直接処理する一方、タッチ選択はネイティブのコンテキストメニューの問題からブラウザ実装を維持
- npmの
wordgardとしてインストールでき、ドキュメントとリファレンスマニュアルも公開されたが、フィードバックとバグ修正を経ながらしばらくは0.xバージョンに留まる予定
Wordgardの性格と公開状況
- Wordgardは、ProseMirrorスタイルのリッチテキストエディタシステムを新たに作り直したプロジェクト
- ProseMirror安定化後の9年間で学んだことと、CodeMirrorバージョン6の再設計から大きな影響を受けている
- ブラウザDOMでエディタインターフェースを表示するJavaScriptライブラリであり、ライセンスはMIT
- コードはForgejoサーバーで公開されている
- npmレジストリから
wordgardとしてインストールでき、使い方はWebサイトで確認できる
ProseMirrorを置き換えずに新システムを作った理由
- ProseMirrorは引き続きメンテナンスされるが、一部の設計には今の基準では別の形にすべきだった部分が残っている
- 非互換インターフェースのProseMirror 2.0を出すと、人々が「ProseMirror」と呼ぶときに何を指すのか曖昧になる可能性がある
- ProseMirror 1.xに下位互換の形で新しいアイデアを継ぎ足すと、構造が妥協的になりかねない
- WordgardはProseMirrorの多くのアイデアを受け継ぎつつ、プログラミングインターフェースは互換性を考慮せずゼロから再設計している
変更表現: stepsではなくセクションベースモデル
- ProseMirrorのstepsは、変更を複数の原子的な操作に分割し、各stepが前のstepによって作られた文書に適用される方式
- この方式は動作するが、複数stepの位置補正や変更範囲の追跡が複雑で扱いにくい
- WordgardはCodeMirrorの変更表現とShareJSの「delta」形式に由来する方式を土台に、より単純なモデルを採用する
- 文書長が10のとき位置4に
Lを挿入すると、[keep 4] [replace 0 with "L"] [keep 6]と表現する - 先頭2文字を削除すると、
[replace 2 with ""] [keep 8]となる
- 文書長が10のとき位置4に
- リッチテキスト処理のために変更セクションを追加し、構造を保ったまま強調・リンクスタイル・画像の代替テキストのようなマークを追加または削除できる
- 3から6までの単語を太字にすると、
[keep 3] [update 3 +bold] [keep 4]と表現する
- 3から6までの単語を太字にすると、
- WordgardはProseMirrorと同じトークンカウントインデックスを使い、ノードの開始・終了トークンとリーフトークンの平坦なシーケンスとして文書位置を扱う
- 単一トランザクションは常に1つの変更だけを持つため、変更の合成や検査・推論が容易になる
- 限定的なオペレーショナル変換をサポートし、同じ開始文書を基準に表現された複数の変更をマージできる
- 複数の変更を持つトランザクションをより扱いやすく表現できる
- 共同編集や、一部の変更だけを巻き戻すundo historyの実装に活用できる
有効な文書構造を維持する方法
- Wordgard文書は単純なトークン列ではなく、平衡の取れたツリー構造でなければならない
- 例えばノード終了トークンを削除すると、トークンのバランスが崩れて適用できない変更になることがある
- 変更セットを生成するコードは、結果が有効な文書構造になるよう変更を検査し補正する必要がある
- オペレーショナル変換でも、変換後の変更が文書を無効化してはならない
- Wordgardの変更モデルは、変換中に結合結果を補正するfix-up changeを導出する
- A-over-BとB-over-Aに対して同じ補正を作るよう、入力を注意深く扱う
- 補正がなければ、2つの順序は同じだが無効になり得る文書を作ることがある
- 同じ補正を合成すれば、両方の順序が同じ有効文書に収束する
- ほとんどの変更では補正は不要だが、必要な場合でも収束性を保つよう設計されている
スキーマ構成とマークの一般化
- ProseMirrorの文書スキーマはノード間の関係を直接指定するため、通常は手作業で設定する必要がある
- ProseMirrorのノード型とマーク型は特定のスキーマ内にしか存在せず、スキーマ間で共有できるノードの同一性がない
- Wordgardではノード・マーク型が独立したオブジェクトであり、複数の文書スキーマに含められる
- これらのオブジェクトは型付けと自動補完を支援するハンドルとして機能し、必要な要素を組み合わせてスキーマを作りやすい
- スキーマは既存要素の関係をオーバーライドできる
- ノードやマークの定義は基本コンテンツや対象型を指定する
- 同じ要素を別の形で使いたいときは、スキーマ側でその関係を変更できる
- 既定の組み込みノードをより豊富に提供できるため、編集支援拡張やメニューボタンのようなシステム統合をそのノードに直接結び付けやすい
- テキスト整列や代替テキストのように特定のノード属性に結び付いていた機能は、マークの一般化によってよりモジュール的に追加できる
- ノード型自体は、どのマークが自分を対象にするのかを知る必要がない
コンテンツ制約を緩和した理由
- ProseMirrorの代表的機能である正規表現ベースの許容コンテンツ指定は、Wordgardではサポートされない
- Wordgardのノードコンテンツ記述は、どの子型をサポートするかだけを制限し、その順序は制限しない
- 正規表現ベースの制約は汎用的な文書操作コードを書きにくくする
- 特定のスキーマ向けに書かれていないコードは、どの変換が有効かをほとんど仮定できない
- すべての操作をコンテンツ制約と照合する必要があり、この過程が微妙で負担になる
- 文書形状を強く固定する制約は、ユーザーが意図する形に向かう途中の編集段階を妨げ、ユーザー体験を損なう可能性がある
- Wordgardは、より緩やかな文書形状アプローチを促進する
- スキーマ規則を超える不変条件が必要な場合には、correction抽象化を提供する
- 許容したくない文書形状をプログラムで補正する
- コンテンツ式の強制よりも、より賢く文脈を反映した補正が可能
- ProseMirrorの制約でも表現できなかった、長方形のテーブル保証のような条件にも使える
拡張システム: CodeMirror 6流のfacet
- ProseMirrorの拡張システムは、プラグインが複数の役割を担い、配列順が優先度に影響する方式
- あるプラグインが、あるフックでは低い優先度を必要とし、別のフックでは高い優先度を必要とする状況があり得る
- CodeMirrorのfacetsベースのシステムは、拡張をより細かくし、各拡張値が独自の優先度カテゴリを設定できるようにする
- Facetは型付きの拡張ポイントであり、ライブラリ自体だけでなくどんなコードからでも定義できる
- Wordgardはこの点でCodeMirrorのシステムをほぼそのまま取り入れており、状態更新と再構成メカニズムも含む
- 構成はプラグイン配列ではなく拡張ツリー
- イベントハンドラの定義
- エディタプロパティの設定
- 新しいエディタ状態の追加
- 機能実装は通常、連携して動作する拡張の束として構成される
- 拡張バンドルの多くは、構成に追加するだけでうまく組み合わさるようプリミティブが設計されている
ブラウザ依存の縮小と選択処理
- ProseMirrorの多くの問題は、ブラウザのネイティブ選択動作に依存する方式と関係している
- 従来のアプローチでは、ブラウザに双方向テキストや特殊なスタイルのコンテンツでのカーソル移動を任せ、その結果を独自の選択モデルに反映していた
- 実際のブラウザは、一部のコンテンツをまたいでカーソルを移動できなかったり、カーソルを描画しなかったり、誤った位置に描画したり、マウス選択ドラッグで異常な動作を示したりすることがある
- Wordgardは、ポインタおよびキーボードによる選択をほぼすべて直接処理する
- 双方向テキスト処理を実装
- コンテンツ配置モデルを作成
- カーソルを自前で描画
- タッチ選択は例外的にネイティブ実装を使う
- 再実装するとネイティブのコンテキストメニューが壊れるように見える
- スマートフォンやタブレットではコンテキストメニューの代替が難しい
- タッチ選択はキーボード選択より異常動作が少ない傾向がある
入力イベント処理とDOM変更監視の撤廃
- この9年間で、ブラウザの編集イベント対応、特に
beforeinput対応はより一貫したものになった - 実使用環境での検証は必要だが、WordgardはProseMirrorが依存していたDOM変更監視や変更内容のパースのトリックなしでも動作できそうだ
- Wordgardは合成テキスト入力を除くすべてについて**
beforeinputイベント**を処理する - この方式により、多数の汚い回避実装が必要になる問題群を避けられる
安定性、バージョン計画、ライセンス
- Wordgardは、以前のプロジェクトが公開時点で置かれていた状態よりも少し進んだ段階にある
- 中核インターフェースは望んでいた機能のほぼすべてをサポートしており、設計が実用的か確かめるための複数の拡張も書かれている
- ドキュメントはまだやや粗いが、リファレンスマニュアルは完成しており利用できる
- 実際の作業で人々が使い始めるまでは、多くの問題が表面化しない可能性がある
- 今後追加したい機能があり、公開後に他の人たちにも見てもらえることを期待している
- 公開インターフェースの一部は、より多くの知見に応じて再考が必要になるかもしれない
- 初版は0.1であり、フィードバック収集・バグ修正・粗い部分の整理のため、しばらくは0.xバージョンに留まる予定
- 期間は少なくとも1年程度と見込まれている
- ライセンスは以前のプロジェクトと同様にMIT
- より制限的なライセンスも検討したが、広く使われることのほうに関心があり、寛容なライセンスを選んだ
AIモデル、コード生成、プルリクエスト方針
- このソフトウェアの作成に言語モデルは使われていない
- JavaScriptコードがWeb上にあり、文書も公開される以上、公開コードやアイデアが大規模言語モデルに取り込まれるのを防ぐ信頼できる方法はないと見ている
- Wordgardでは、標準的なオープンソース慣行とは異なり、pull requestを受け付けない実験を行う
- 大きな変更をレビューし、期待に沿うよう調整する過程は、自分で実装するよりも多くの手間になることが多い
- コード生成コストが大幅に下がる中で、他人がコードを投げ込み、管理者がレビュー・保守したり、却下理由を説明したりしなければならない構造は、以前ほど魅力的ではなくなっている
1件のコメント
Lobste.rs のコメント
作者として、質問やフィードバックがあればこのスレッドを時々確認するつもり
Markdown レンダラーで HTML を生成して Wordgard で編集させることはできそうだが、その後エディタの内容から Markdown をどう取り出せるのだろう?
最終的には Wordgard に移るのだろうか? 新しいプロジェクトで ProseMirror を使おうとしている人がいるなら、どんな時に Wordgard を選ぶべきだろう?
そして real, human artist が手がけた素敵なアートもある
良い
Marijn のプロジェクトと発表を心から祝福する。素晴らしそうだし、Kamila Stankiewicz のアートも気に入った
プロジェクトのメインホームページは https://wordgard.net/
この部分、特に最後の段落全体が本当に興味深い
AI コード生成とより良い関係を築けるようになるまで、あるいはそもそも関係を持たない方向に進むまで、こうした方式がしばらくもっと一般的になるのかも気になる
ちなみにコードは MIT ライセンス