# 通知設計書 30-workspace/applyEdit

## 概要

本ドキュメントは、serve-d LSPサーバーにおけるLSP標準リクエスト「workspace/applyEdit」の設計仕様を定義する。本リクエストはサーバーからクライアント(エディタ)に送信され、ワークスペース内のファイルに対するテキスト編集を適用する。

### 本通知の処理概要

本リクエストは、サーバーがクライアントに対してワークスペース内のドキュメントにテキスト編集を適用するよう要求するものである。

**業務上の目的・背景**：serve-dでは、ファイル作成時のモジュール名自動挿入、新規DUBレシピファイルのテンプレート挿入、DUBフォーマット変換結果の適用など、サーバー側で生成したテキスト変更をクライアントのエディタに反映させる必要がある。workspace/applyEditを使用することで、エディタのUndo/Redo履歴に変更が記録され、ユーザーが変更を取り消すことが可能となる。

**通知の送信タイミング**：以下の場面で送信される。(1) D言語ソースファイル作成時のモジュール名自動更新（rename_listener.d）。(2) 新規dub.json/dub.sdl作成時のテンプレート挿入（rename_listener.d）。(3) DUBフォーマット変換結果の適用（dub.d）。

**通知の受信者**：LSPクライアント（エディタ）が受信者である。

**通知内容の概要**：ApplyWorkspaceEditParams（edit: WorkspaceEdit）をパラメータとして送信する。WorkspaceEditにはchanges（URI -> TextEdit[]マップ）またはdocumentChanges（TextDocumentEdit/RenameFile等の配列）が含まれる。

**期待されるアクション**：クライアントは指定されたテキスト編集をワークスペース内の対象ファイルに適用する。適用結果（ApplyWorkspaceEditResponse）をサーバーに返す。

## 通知種別

LSP標準リクエスト（JSON-RPC Request）。サーバーからクライアントへの方向（S->C）。応答を伴うリクエスト。

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（JSON-RPC request、rpc.sendMethodで送信） |
| 優先度 | 高 |
| リトライ | なし |

### 送信先決定ロジック

サーバーからLSPクライアントに直接送信される。rpc.sendMethod("workspace/applyEdit", params)で送信される。

## 通知テンプレート

### メール通知の場合

該当なし。本リクエストはLSPプロトコル上のJSON-RPCメッセージである。

### 本文テンプレート

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "workspace/applyEdit",
  "params": {
    "edit": {
      "changes": {
        "file:///path/to/file.d": [
          {
            "range": {
              "start": { "line": 0, "character": 0 },
              "end": { "line": 0, "character": 0 }
            },
            "newText": "module mypackage.mymodule;\n\n"
          }
        ]
      }
    }
  }
}
```

### 添付ファイル

該当なし。

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| edit.changes | URI -> TextEdit[]のマッピング | サーバー処理結果 | changes or documentChangesのいずれか |
| edit.documentChanges | TextDocumentEdit/RenameFileの配列 | サーバー処理結果 | changes or documentChangesのいずれか |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 自動 | D言語ソースファイル作成・リネーム | config.d.generateModuleNames == true | モジュール名自動更新 |
| 自動 | 新規dub.json作成 | ファイル内容が空 | JSONテンプレート挿入 |
| 自動 | 新規dub.sdl作成 | ファイル内容が空 | SDLテンプレート挿入 |
| 画面操作 | DUBフォーマット変換実行 | 変換成功 | 変換結果の適用（リネーム含む可能性あり） |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| generateModuleNames == false | D言語ファイル作成時のモジュール名自動更新を抑止 |
| patches.length == 0 | ModulemanComponentが変更パッチを返さなかった場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[サーバー処理で編集適用が必要] --> B[WorkspaceEdit構築]
    B --> C{documentChangesサポート?}
    C -->|Yes| D[documentChanges形式で構築]
    C -->|No| E[changes形式で構築]
    D --> F[ApplyWorkspaceEditParams生成]
    E --> F
    F --> G[rpc.sendMethod workspace/applyEdit 送信]
    G --> H[クライアント: 編集適用]
    H --> I[終了]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし。

### 更新テーブル一覧

該当なし。クライアント側のエディタバッファが更新される。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 編集適用失敗 | クライアントがWorkspaceEditの適用に失敗 | クライアントがApplyWorkspaceEditResponseで失敗を通知 |
| ファイル未発見 | 指定URIのファイルが存在しない | クライアント側のエラー処理に依存 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし。

## セキュリティ考慮事項

- ファイルの内容が変更されるため、意図しない変更のリスクがある
- workspace/applyEditはUndo/Redo対応しているため、ユーザーが変更を取り消せる
- serve-d内では主にファイル作成時の自動挿入に使用されており、安全性は高い

## 備考

- serve-dではrpc.sendMethod("workspace/applyEdit", params)で呼び出しており、応答を待たない（sendMethod使用）
- rename_listener.dでは3箇所でworkspace/applyEditが使用される
  1. D言語ソースファイルのモジュール名自動更新（L146）
  2. 新規dub.jsonのテンプレート挿入（L162）
  3. 新規dub.sdlのテンプレート挿入（L177）
- dub.dではDUBフォーマット変換結果の適用で使用される（L571）
- DUBフォーマット変換時はresourceOperations.renameサポートに応じてdocumentChanges/changesを使い分ける
- モジュール名自動更新後にはwindow/showInformationMessageで通知も行われる

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protocol.d | `protocol/source/served/lsp/protocol.d` | WorkspaceEdit、ApplyWorkspaceEditParams、TextEdit、TextDocumentEdit、RenameFile等の定義 |

**読解のコツ**: WorkspaceEditはchanges（URI->TextEdit[]マップ）またはdocumentChanges（DocumentChange配列）のいずれかを使用する。DocumentChangeはTextDocumentEdit / CreateFile / RenameFile / DeleteFileの共用体。

#### Step 2: エントリーポイントを理解する（rename_listener.d）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | rename_listener.d | `source/served/workers/rename_listener.d` | onFullyCreateDSource（L129-149）、onFullyCreateDubJson（L151-164）、onFullyCreateDubSdl（L166-179） |

**主要処理フロー**:
1. **L129-149**: D言語ソースファイル作成時のモジュール名自動更新
   - L139: ModulemanComponent.normalizeModulesでパッチ取得
   - L142-144: WorkspaceEdit構築（changes形式）
   - L145-146: ApplyWorkspaceEditParams構築・送信
   - L147: window/showInformationMessageで通知
2. **L151-164**: 新規dub.json作成時
   - L154: ファイル内容の空チェック
   - L157-159: WorkspaceEdit構築（JSONテンプレート）
   - L161-162: 送信
3. **L166-179**: 新規dub.sdl作成時
   - L169: ファイル内容の空チェック
   - L172-174: WorkspaceEdit構築（SDLテンプレート）
   - L176-177: 送信

#### Step 3: エントリーポイントを理解する（dub.d）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dub.d | `source/served/commands/dub.d` | convertDubFormat関数内（L546-572） |

**主要処理フロー**:
- **L551-555**: resourceOperations.renameサポート判定
- **L557-563**: documentChanges形式（RenameFile + TextDocumentEdit）
- **L566**: changes形式（テキスト編集のみ）
- **L568-571**: ApplyWorkspaceEditParams構築・送信

### プログラム呼び出し階層図

```
[サーバー処理]
    |
    +-- rename_listener.d
    |     |
    |     +-- onFullyCreateDSource() [L129]
    |     |     +-- ModulemanComponent.normalizeModules()
    |     |     +-- rpc.sendMethod("workspace/applyEdit", ...)
    |     |
    |     +-- onFullyCreateDubJson() [L151]
    |     |     +-- rpc.sendMethod("workspace/applyEdit", ...)
    |     |
    |     +-- onFullyCreateDubSdl() [L166]
    |           +-- rpc.sendMethod("workspace/applyEdit", ...)
    |
    +-- dub.d
          |
          +-- convertDubFormat() [L514]
                +-- execute(["dub", "convert", ...])
                +-- rpc.sendMethod("workspace/applyEdit", ...)
```

### データフロー図

```
[入力]                          [処理]                              [出力]

ファイル作成/               WorkspaceEdit構築              workspace/applyEdit
フォーマット変換    -----> テキスト編集の算出          --> (TextEdit / RenameFile)
                          ApplyWorkspaceEditParams生成      エディタバッファ更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| rename_listener.d | `source/served/workers/rename_listener.d` | ソース | ファイル作成検知・モジュール名自動更新（L129-179） |
| dub.d | `source/served/commands/dub.d` | ソース | DUBフォーマット変換結果の適用（L546-572） |
| protocol.d | `protocol/source/served/lsp/protocol.d` | ソース | WorkspaceEdit、ApplyWorkspaceEditParams型定義 |
| jsonrpc.d | `lsp/source/served/lsp/jsonrpc.d` | ソース | sendMethodによるリクエスト送信 |
| moduleman.d | `workspace-d/source/workspaced/com/moduleman.d` | ソース | ModulemanComponent.normalizeModules（モジュール名正規化） |
| translate.d | `source/served/utils/translate.d` | ソース | 翻訳メッセージ（d.served.moduleNameAutoUpdated） |
