# 通知設計書 7-textDocument/didChange

## 概要

本ドキュメントは、LSPクライアントからserve-dサーバーへ送信される `textDocument/didChange` 通知の設計を記述する。この通知はLSP標準仕様に準拠し、テキストドキュメントの内容が変更されたことをサーバーに通知するために使用される。

### 本通知の処理概要

`textDocument/didChange` 通知は、エディタ（クライアント）でドキュメントの内容が変更された際にserve-dサーバーに送信される通知である。サーバー側では2つのハンドラが登録されている。extension.dのonDidChangeDocumentではD-Scannerによる静的リンティングとdfmtによるフォーマット診断が実行され、index.dのreindexOnChangeではインデックスの更新が行われる。また、TextDocumentManagerがインメモリのドキュメント内容を更新する。

**業務上の目的・背景**：リアルタイムのコード編集に対応するため、ドキュメント変更を即座にサーバーに反映し、リンティング結果やインデックスを更新する。incremental sync方式を採用しており、変更差分のみを転送することでネットワーク効率を最適化している。

**通知の送信タイミング**：ユーザーがエディタ上でドキュメントを編集するたびにクライアントから送信される。

**通知の受信者**：serve-d LSPサーバーが受信する。

**通知内容の概要**：ドキュメントのURI、バージョン番号、変更内容の配列（TextDocumentContentChangeEvent）で構成される。

**期待されるアクション**：サーバーがインメモリのドキュメントを更新し、リンティングとインデックス更新を実行する。結果としてpublishDiagnostics通知がクライアントに送信される。

## 通知種別

LSP標準通知（クライアント -> サーバー）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（JSON-RPC通知） |
| 優先度 | 高（リアルタイム編集に対応） |
| リトライ | 無し |

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

クライアントがドキュメントを変更した際に自動的にserve-dサーバーへ送信される。Incremental sync方式。

## 通知テンプレート

### LSP通知の場合

| 項目 | 内容 |
|-----|------|
| メソッド名 | `textDocument/didChange` |
| パラメータ型 | `DidChangeTextDocumentParams` |
| 形式 | JSON-RPC 2.0 通知 |

### 本文テンプレート

```json
{
  "jsonrpc": "2.0",
  "method": "textDocument/didChange",
  "params": {
    "textDocument": {
      "uri": "file:///path/to/file.d",
      "version": 2
    },
    "contentChanges": [
      {
        "range": {
          "start": {"line": 1, "character": 0},
          "end": {"line": 1, "character": 5}
        },
        "text": "newText"
      }
    ]
  }
}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| textDocument.uri | ドキュメントのURI | クライアントのファイルシステム | Yes |
| textDocument.version | 変更後のバージョン番号 | クライアントの管理値 | Yes |
| contentChanges | 変更内容の配列（range + text） | クライアントの差分計算 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ユーザー操作 | エディタでテキストを編集 | 常に送信 | 入力、削除、ペースト等全ての変更 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| LSP接続未確立 | サーバーが初期化されていない場合 |

## 処理フロー

### 受信フロー

```mermaid
flowchart TD
    A[textDocument/didChange通知受信] --> B[TextDocumentManager.process]
    B --> C[インメモリドキュメント更新]
    C --> D[ハンドラ1: onDidChangeDocument]
    C --> E[ハンドラ2: reindexOnChange]
    D --> F{D言語ファイル?}
    F -->|No| G[スキップ]
    F -->|Yes| H[doDscanner実行]
    H --> I[タイマー付きdfmtリント実行]
    E --> J{D言語かつインデックス有効?}
    J -->|Yes| K[タイマー付きreindex実行]
    J -->|No| L[スキップ]
```

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

該当なし（インメモリ管理）

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| TextDocumentManager.documentStore | UPDATE | ドキュメントのバージョンとテキスト内容を更新 |
| IndexComponent | UPDATE | ファイルのインデックスを再構築（遅延実行） |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ドキュメント未登録 | 未登録URIに対するdidChange | TextDocumentManagerがスキップ |
| リンター実行エラー | D-Scanner/dfmt実行失敗 | 各リンター内でハンドリング |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| リンティング遅延（D-Scanner） | 50KiB以下: 200ms、50KiB超: 1000ms |
| リンティング遅延（dfmt） | 50KiB以下: 50ms、50KiB超: 500ms |
| インデックス更新遅延 | 50KiB以下: 50ms、50KiB超: 500ms |

### 配信時間帯

制限なし

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

ドキュメントの変更内容（テキスト差分）が送信される。ソースコードの内容が含まれるが、同一プロセス間の通信のため外部漏洩リスクは低い。

## 備考

- TextDocumentSyncKindはincremental（差分同期）に設定されている
- doDscannerハンドラはcoded/dodscannerとserved/dodscannerの両方のエイリアスでも登録されている
- clearTimeout/setTimeoutによるデバウンス処理により、高速な連続入力時のリンティング頻度が制御される
- D-ScannerリンティングはenableStaticLintingとenableLintingの両方がtrueの場合のみ実行される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protocol.d | `lsp/source/served/lsp/protocol.d` | DidChangeTextDocumentParams、VersionedTextDocumentIdentifier、TextDocumentContentChangeEventの定義 |

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | textdocumentmanager.d | `lsp/source/served/lsp/textdocumentmanager.d` | TextDocumentManager.process()（903行目〜921行目）でtextDocument/didChangeをハンドリング。incremental変更の適用処理 |

**主要処理フロー**:
1. **905行目**: DidChangeTextDocumentParamsをデシリアライズ
2. **909行目**: version_を更新
3. **910行目〜916行目**: contentChangesを順に適用（range指定: applyChange、全体置換: setContent）

#### Step 3: 各ハンドラを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | onDidChangeDocument（1148行目〜1165行目）。D言語判定後、doDscanner実行とタイマー付きdfmtリント実行 |
| 3-2 | extension.d | `source/served/extension.d` | doDscanner（1167行目〜1187行目）。D-ScannerリンティングのデバウンスとenableStaticLinting判定 |
| 3-3 | index.d | `source/served/commands/index.d` | reindexOnChange（72行目〜94行目）。タイマー付きインデックス再構築 |

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

```
[クライアント: textDocument/didChange送信]
    |
    v
[serverbase.d: processNotify]
    |
    +-- documents.process(msg)                    [textdocumentmanager.d:903]
    |       +-- applyChange() / setContent()      (インメモリ更新)
    |
    +-- onDidChangeDocument(params)                [extension.d:1148]
    |       +-- doDscanner(params)                 [extension.d:1167]
    |       |       +-- setTimeout -> dscanner.lint(doc)
    |       +-- setTimeout -> dfmt.lint(doc)
    |
    +-- reindexOnChange(params)                    [index.d:72]
            +-- setTimeout -> indexer.reindex(...)
```

### データフロー図

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

DidChangeTextDocumentParams -->  TextDocumentManager.process()  -->  インメモリ更新
  contentChanges            -->  onDidChangeDocument()          -->  publishDiagnostics(D-Scanner)
                            -->  dfmt.lint()                    -->  publishDiagnostics(dfmt)
                            -->  reindexOnChange()              -->  IndexComponent更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.d | `source/served/extension.d` | ソース | onDidChangeDocument/doDscannerハンドラ |
| index.d | `source/served/commands/index.d` | ソース | reindexOnChangeハンドラ |
| textdocumentmanager.d | `lsp/source/served/lsp/textdocumentmanager.d` | ソース | ドキュメントのインメモリ更新 |
| dscanner.d | `source/served/linters/dscanner.d` | ソース | D-Scanner静的解析リンター |
| dfmt.d | `source/served/linters/dfmt.d` | ソース | dfmtフォーマットリンター |
| diagnosticmanager.d | `source/served/linters/diagnosticmanager.d` | ソース | 診断結果の統合管理 |
| serverbase.d | `serverbase/source/served/serverbase.d` | ソース | processNotify |
