Web Playground Editor 再開発計画
背景
Web Playground の editor は web/src/editor/ と web/src/language/neplg2/neplg2-provider.ts に機能が集中しており、描画、入力、状態管理、言語解析、Problems 表示、Hover 表示、補完 UI が強く結合している。
今回の作業では不具合の都度修正を重ねるのではなく、責務分割を見直して editor を一から再設計し、CLI だけで再現できるテスト基盤を先に整える。
現状確認
現在の editor 実装
CanvasEditorがテキスト状態、カーソル、選択、undo/redo、fold、language provider 連携、Problems 更新まで持っている。EditorInputHandlerが DOM Event を直接読み、ショートカット処理、Hover 遅延、補完操作、編集操作をその場でCanvasEditorに反映している。EditorRendererが描画時に token/diagnostic/selection/occurrence/fold placeholder の判断まで担っている。EditorDOMUIが Problems 表示と補完 UI を直接 editor 内部状態から構築している。
現在の言語機能実装
NEPLg2LanguageProviderはwindow.wasmBindingsに直接依存し、Web 前提の実装になっている。- highlight, diagnostics, hover, definition, occurrences, completions, indentation, comment toggle, bracket match が 1 ファイルに混在している。
- Hover と Problems の文面は ad-hoc な文字列連結で構築されており、表示仕様が独立していない。
- word boundary, indentation, comment toggle は解析結果ではなく provider 内のローカル規則で処理されている。
既存の Rust / WASM 側資産
nepl-web/src/lib.rsにはanalyze_lex,analyze_parse,analyze_name_resolution,analyze_semantics,analyze_semantics_with_vfsがあり、token / diagnostics / name_resolution / token_resolution / token_semantics まで取得できる。nodesrc/compiler_loader.jsにより Trunk の成果物を Node.js から直接ロードできるため、ブラウザを使わず CLI で editor 用解析テストを実行できる。- 一方で editor 側は Rust から返る payload をそのまま UI 直結で消費しており、再利用しやすい中間表現がない。
根本原因
- UI 層と editor state が分離されておらず、不具合が「描画の問題」なのか「入力処理の問題」なのか「解析結果の解釈ミス」なのかを切り分けにくい。
- editor の仕様が DOM event 起点で実装されており、CLI テスト可能な command/state モデルがない。
- 言語解析結果の正規化層がなく、hover/problems/highlight の仕様が provider 内の個別実装に埋もれている。
- 文字オフセット、行列位置、byte offset の変換責務が分散しており、hover/highlight/definition の位置ずれを誘発しやすい。
指示適合性の確認
この計画は次の repository 指示に適合する必要がある。
- 不具合は場当たり対応ではなく、責務の分離不足と仕様未固定を根本原因として解消する。
plan.mdは変更せず、差分や提案はnote.n.mdに記録する。todo.mdには未実装タスクだけを残す。doc/の文書は他文書と整合する書き方にそろえる。- テストは browser 依存に逃がさず、CLI だけで再現可能な形にする。
- 検証手順は
trunk buildの後にnodesrc/cli.jsベースで実行し、output の JSON を確認できる形にする。
今回の再設計では特に最後の項目が重要であり、専用 runner を作るだけでは不十分で、nodesrc/cli.js から呼べる正式な導線に載せる必要がある。
再設計方針
目標
- editor の状態遷移を pure な command reducer として定義し、DOM なしで操作テストできるようにする。
- 言語解析結果を UI 非依存の中間モデルへ正規化し、highlight / problems / hover / definition / completion を同じ仕様書から生成する。
- browser adapter は canvas 描画と DOM popup 表示に限定し、仕様判断は core 側へ寄せる。
- CLI から
trunk build後の成果物を読み込んで、editor の主要機能を JSON snapshot として検証できるようにする。
進め方の制約
repository の運用指示を守るため、実装の進め方にも制約を置く。
- 既存 editor を一度に捨てる flag day 方式にはしない。
- まず core を横に追加し、browser adapter を段階的に差し替える。
- 各段階で既存 UI を壊さない最小差分を優先し、不必要な周辺変更を避ける。
- 1 回の変更単位は「状態管理」「解析正規化」「入力」「描画」「CLI テスト導線」など責務ごとに分ける。
- 各変更単位ごとにテストを通し、必要ならその時点で commit できる粒度に保つ。
この制約により、再設計でありつつも、実際の実装は小さな段階に分割して進める。
層分割
1. Editor Core
web/src/editor-core/ を新設し、少なくとも次の責務へ分割する。
text-buffer.ts
- テキスト本体、行インデックス、offset 変換、差分適用を管理する。
editor-state.ts
- カーソル、選択、scroll、overwrite、fold、completion 状態、hover 対象、undo/redo を保持する。
editor-command.ts
- insert / delete / move / select / indent / outdent / comment / fold / accept-completion などの command を定義する。
editor-reducer.ts
- command を受けて state を更新する pure reducer を実装する。
keymap.ts
- DOM keyboard event を editor command 列へ変換する規則を分離する。
view-model.ts
- 描画や DOM UI が必要とする cursor line, selection range, visible lines, fold placeholder, problems panel items を生成する。
2. Language Analysis Core
web/src/language/neplg2/core/ を新設し、次の責務へ分割する。
analysis-source.ts
- WASM / Node loader から analyze_semantics(_with_vfs) を呼び出す。
analysis-normalizer.ts
- token, diagnostics, token_resolution, token_semantics, definitions, references を editor 共通形式へ正規化する。
highlight-model.ts
- semantic highlight と lexical fallback の生成規則をまとめる。
problem-model.ts
- diagnostics の並び順、severity、範囲、problem list item 生成を統一する。
hover-model.ts
- hover の表示要素を structured data として生成し、最終的な文字列整形を別関数に分離する。
navigation-model.ts
- definition, occurrences, symbol lookup, completion candidates を担当する。
editing-rules.ts
- indentation, word boundary, toggle comment, bracket match を解析結果と文法規則に基づいて実装する。
3. Browser Adapter
既存の web/src/editor/ は adapter 層として縮小する。
editor.ts
- stateful facade のみを持つ。
editor-input-handler.ts
- DOM event を keymap.ts と pointer command へ変換するだけにする。
editor-renderer.ts
- view-model.ts が返した描画データを canvas へ描くことだけに集中する。
editor-dom-ui.ts
- popup / completion / problems の DOM 表示を担当するが、表示内容の決定は core から受け取る。
Hover / Problems / Highlight の再設計
Highlight
- lexical token 色付けと semantic highlight を分離する。
- semantic 情報がある token は semantic 優先、ない token は lexical fallback とする。
- byte offset と UTF-16 index の変換を normalizer で一元管理する。
- renderer は完成済み token decoration 配列を描くだけにする。
Problems
- diagnostics を editor 表示用の
ProblemItemへ正規化し、ソート規則を固定する。 ProblemItemは message, severity, range, source stage, related definition を持てるようにする。- Problems panel と underline 表示は同一データから生成する。
Hover
- hover はプレーン文字列ではなく
HoverModelとして構築する。 HoverModelの候補:
- token 表記
- 推論型
- 定義種別と定義名
- 引数位置
- 定義候補一覧
- diagnostic summary
- browser 表示用 formatter と CLI snapshot 用 serializer を分ける。
CLI 完結テスト方針
基本方針
- browser の DOM event を直接叩くテストではなく、editor core の command/state を Node.js から実行する。
- 解析系テストは
trunk build後のnepl-webWASM 成果物をnodesrc/compiler_loader.jsで読み込んで実行する。 - 出力は JSON に統一し、
nodesrc/cli.jsからの既存テスト文化と整合する形にする。
追加する CLI テスト基盤
nodesrc/cli.js
- playground editor テストを呼び出す entry point を追加し、JSON を -o で出力できるようにする。
- 日常運用ではこの入口を標準にし、既存の nodesrc ワークフローとそろえる。
nodesrc/playground_editor_test_runner.js
- nodesrc/cli.js から呼ばれる下位 runner として、Trunk 成果物をロードし、fixture と command script を読み、state snapshot を JSON 出力する。
tests/playground_editor/
- editor の fixture, command script, expected snapshot を置く。
web/src/editor-core/testing/
- reducer 実行や snapshot 生成を補助する test-only utility を置く。
fixture 形式
CLI だけで運用しやすくするため、fixture 形式も固定する。
tests/playground_editor/<case>/source.nepl
- 主対象の入力ソース
tests/playground_editor/<case>/vfs.json
- 複数ファイルや import が必要な場合の仮想ファイル群
tests/playground_editor/<case>/commands.json
- key input, shortcut, pointer, hover, definition 要求などの操作列
tests/playground_editor/<case>/expected.json
- 比較対象の snapshot
commands.json は DOM event そのものではなく、editor core command と検証要求だけを表す。
テスト対象
1. Key Input / Shortcut
- 文字入力、改行、Backspace、Delete
- Arrow / Home / End / PageUp / PageDown
- Shift 付き選択拡張
- Ctrl/Cmd+A, Z, Y, /
- Tab / Shift+Tab
- F12 definition jump
- Insert による overwrite mode 切替
- completion 表示中の ArrowUp / ArrowDown / Enter / Tab / Escape
pointer 系も CLI で再現できる必要があるため、次も対象に含める。
- click による cursor 移動
- drag による選択
- gutter click による fold toggle
- hover request に対する hover model 生成
2. Editor State
- cursor / selection / preferred column
- undo / redo stack
- folded line と visible line の対応
- completion selection state
- hover target state
- overwrite mode と通常入力の差
3. Highlight / Problems / Hover
- keyword / string / number / comment / function / variable の分類
- definition 解決済み token の function highlight
- diagnostics の range と severity
- hover に含まれる型情報、定義情報、候補情報
- definition jump の target range
- occurrences の収集
- folding range の抽出
4. Multi-file / VFS
#importを含む複数ファイル fixture でanalyze_semantics_with_vfsを使う。- definition / hover / problems が file_path を跨いで正しく生成されるか確認する。
期待する JSON snapshot
各ケースは少なくとも次を出力できるようにする。
textcursorselectionfoldedLinescompletiondiagnosticsproblemshoverdefinitionoccurrencesdecorationsvisibleLines
検証コマンドの標準化
playground editor 再開発では、検証手順そのものも固定する。
trunk buildnode nodesrc/cli.js ... -o json=<path>- 生成された output JSON を確認し、snapshot 差分と失敗ケースを読む
想定する最終形の例:
trunk build
node nodesrc/cli.js -i tests/playground_editor -o json=tmp/playground-editor-tests.jsonまた、開発中の局所再現用には nodesrc/playground_editor_test_runner.js を直接使えてよいが、CI と完了確認は nodesrc/cli.js 経由へ統一する。
実装フェーズ
Phase 0: 仕様固定
- editor core の状態モデルと command 一覧を決める。
- hover / problems / highlight の JSON schema を決める。
- CLI test runner の入出力形式を決める。
nodesrc/cli.jsへどう統合するかをこの段階で決める。- fixture ディレクトリ構成と
commands.json/expected.jsonの schema を決める。
Phase 1: Pure Core 先行
- text buffer, state, reducer, keymap を実装する。
- DOM 非依存の unit test を Node.js から回せるようにする。
- この段階では既存 browser adapter へはまだ最小限の接続しかしない。
Phase 2: Language Model 再構築
NEPLg2LanguageProviderから解析正規化ロジックを分離する。- hover / problems / highlight / completion / navigation を純粋関数化する。
Phase 3: Browser Adapter 差し替え
- 既存 canvas editor を新 core に接続する。
- DOM / canvas は view-model 消費に限定する。
- 旧実装を即削除せず、差し替え完了まで比較可能な状態を維持する。
Phase 4: CLI Snapshot 拡充
- fixture を増やし、複数ファイル・日本語・全角・byte offset 境界を含むケースを追加する。
trunk build+ CLI テスト + JSON 検証を標準手順にする。
Phase 5: 完了判定と運用化
nodesrc/cli.js経由の JSON 出力が CI とローカルの両方で再現できる状態にする。doc/testing.mdとdoc/web_playground.mdに playground editor の正式な検証手順を追記する。- 実装修正ごとに、必要なら README / doc を更新する運用へそろえる。
各フェーズの検証と commit
各フェーズの完了時には、少なくとも次を満たす。
trunk buildが通るnode nodesrc/cli.js ... -o json=<path>で対象ケースの JSON が更新または一致する- 必要な document 更新が済んでいる
- その時点で独立に commit 可能な粒度になっている
非目標
- 初回の再開発では Monaco など他 editor への置換は行わない。
- terminal / explorer / tabs の再設計は対象外とし、editor との境界整理に留める。
- visual design の刷新は副次対応とし、まず仕様とテストの再建を優先する。
完了条件
- editor 操作の主要経路が CLI から command script で再現できる。
- highlight / problems / hover / definition / completion の仕様が JSON snapshot として固定される。
- browser adapter が core なしでは振る舞いを決めない構成になる。
- 既知の editor 不具合修正が「個別対処」ではなく、新 core のテスト追加で再発防止できる状態になる。
- 実装完了後の標準確認手順が
trunk buildとnodesrc/cli.jsによる JSON 検証として文書化されている。