# 機能設計書 67-変更時インデックス更新

## 概要

本ドキュメントは、serve-dにおける変更時インデックス更新機能の設計を記述する。テキストドキュメントの変更時にデバウンス付きでインデックスを増分更新し、コード補完やシンボル検索の精度を維持する。

### 本機能の処理概要

**業務上の目的・背景**：開発者がコードを編集している最中も、シンボル検索や自動インポート補完が最新のコード状態を反映する必要がある。本機能はtextDocument/didChange通知をトリガーとして、変更されたドキュメントのインデックスをデバウンス付きで増分更新する。大きなファイルに対しては更新頻度を下げることでパフォーマンスへの影響を最小化する。

**機能の利用シーン**：
- 開発者がエディタでD言語ソースコードを編集している間、自動的にトリガーされる
- タイピング中のリアルタイムなインデックス更新

**主要な処理内容**：
1. textDocument/didChange通知を受信する
2. D言語ファイルかどうか確認する
3. インデックスが有効かどうか確認する
4. ファイルサイズに応じたデバウンス遅延を計算する
5. 既存のタイマーをキャンセルし、新しいデバウンスタイマーを設定する
6. タイマー発火時にIndexComponentのreindexで増分更新を実行する
7. インデックスの遅延保存を予約する

**関連システム・外部連携**：workspace-dのIndexComponentを使用。

**権限による制御**：設定（config.d.enableIndex）によりインデックス機能の有効/無効が制御される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | (直接の画面関連なし) | - | textDocument/didChange通知をトリガーとして自動実行 |

## 機能種別

データ更新・インデックス増分更新

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| params | DidChangeTextDocumentParams | Yes | テキストドキュメント変更通知のパラメータ | - |
| params.textDocument.uri | DocumentUri | Yes | 変更されたドキュメントのURI | - |

### 入力データソース

LSPクライアントからの `textDocument/didChange` 通知（index.dでの追加ハンドラ）。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (なし) | void | 直接の出力はなし。インデックスが内部的に更新される |

### 出力先

IndexComponentの内部データ構造（メモリ上のインデックス）。

## 処理フロー

### 処理シーケンス

```
1. textDocument/didChange通知を受信
   └─ reindexOnChange(params)が呼び出される
2. D言語ファイルチェック
   └─ document.getLanguageId != "d" ならreturn
3. インデックス有効チェック
   └─ config.d.enableIndex == false ならreturn
4. デバウンス遅延の計算
   └─ ファイルサイズ > 50KB なら500ms、それ以外は50ms
5. 既存タイマーのキャンセル
   └─ clearTimeout(reindexChangeTimeout)
6. 新しいデバウンスタイマーの設定
   └─ setTimeout内でインデックス更新処理を予約
7. タイマー発火時の処理
   └─ IndexComponentのreindex()でインデックス増分更新
   └─ delayedSaveIndex()でインデックス保存を予約
```

### フローチャート

```mermaid
flowchart TD
    A[textDocument/didChange 通知受信] --> B{D言語ファイル?}
    B -->|No| Z[終了]
    B -->|Yes| C{enableIndex 有効?}
    C -->|No| Z
    C -->|Yes| D[デバウンス遅延計算]
    D --> E[既存タイマーキャンセル]
    E --> F[新しいデバウンスタイマー設定]
    F --> G{タイマー発火}
    G --> H{IndexComponent あり?}
    H -->|No| Z
    H -->|Yes| I[indexer.reindex で増分更新]
    I --> J[delayedSaveIndex で遅延保存]
    J --> Z
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-67-01 | D言語限定 | D言語ファイル以外はインデックス更新しない | 常時 |
| BR-67-02 | インデックス有効チェック | enableIndexがfalseのワークスペースではスキップ | 常時 |
| BR-67-03 | ファイルサイズ別デバウンス | 50KB超のファイルは500ms、それ以下は50msのデバウンス | 常時 |
| BR-67-04 | デバウンスタイマー管理 | 新しい変更があるたびに既存タイマーをキャンセルして再設定 | 常時 |
| BR-67-05 | 増分更新 | reindexの第5引数がfalseで増分更新モード | 常時 |

### 計算ロジック

デバウンス遅延の計算:
```
delay = document.length > 50 * 1024 ? 500 : 50  // ミリ秒
```

## データベース操作仕様

### 操作別データベース影響一覧

データベース操作はない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | IndexComponent未検出 | hasBest!IndexComponentがfalseの場合 | 処理をスキップ |

### リトライ仕様

デバウンスにより自然なリトライが行われる。次の変更通知でタイマーが再設定される。

## トランザクション仕様

トランザクション管理は不要。

## パフォーマンス要件

- デバウンスにより頻繁なインデックス更新を抑制（50ms / 500ms）
- 大きなファイル（50KB超）では遅延を長くしてCPU負荷を軽減
- インデックス保存は更にdelayedSaveIndex（2500ms遅延）で制御

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

ドキュメントの内容を読み取りインデックスを更新するのみ。

## 備考

- `@protocolNotification("textDocument/didChange")` でtextDocument/didChangeの追加ハンドラとして登録
- reindexChangeTimeoutはモジュールレベルのグローバル変数（71行目）でタイマーIDを保持
- reindexの第5引数 `false` は増分更新を示す（trueは完全再インデックス）
- 同一のtextDocument/didChange通知はextension.dの他のハンドラ（DScanner静的解析、dfmtリント等）でも処理される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.d | `source/served/commands/index.d` | reindexChangeTimeout変数（71行目）- デバウンスタイマーID |

**読解のコツ**: `clearTimeout`/`setTimeout` はserve-d独自のタイマーAPIで、JavaScriptの同名APIに類似。`getYield()` はFutureをファイバー内で待機する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.d | `source/served/commands/index.d` | reindexOnChange関数（72-94行目） |

**主要処理フロー**:
1. **72行目**: `@protocolNotification("textDocument/didChange")` でハンドラ登録
2. **75-76行目**: ドキュメント取得、D言語チェック
3. **78-79行目**: enableIndexチェック
4. **81行目**: ファイルサイズに応じたデバウンス遅延計算
5. **82行目**: 既存タイマーキャンセル
6. **83-93行目**: 新しいタイマーセットアップ（setTimeout内でreindex実行）

#### Step 3: 依存関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.d | `source/served/commands/index.d` | delayedSaveIndex関数（117-123行目） |

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

```
reindexOnChange(params) [index.d:72-94]
    |
    +-- documents[params.textDocument.uri] (ドキュメント取得)
    |
    +-- document.getLanguageId (言語チェック)
    |
    +-- workspace(uri).config.d.enableIndex (インデックス有効チェック)
    |
    +-- clearTimeout(reindexChangeTimeout) (既存タイマーキャンセル)
    |
    +-- setTimeout(delay) (デバウンスタイマー設定)
        |
        +-- backend.best!IndexComponent(filePath)
        |
        +-- indexer.reindex(filePath, now, length, rawText, false)
        |
        +-- delayedSaveIndex(indexer) [index.d:117-123]
            +-- setTimeout(2500ms)
            +-- indexer.saveIndex()
```

### データフロー図

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

textDocument/didChange   ──▶  reindexOnChange()                  ──▶  インデックスデータ（更新）
(DidChangeTextDocumentParams)    |
                                +-- デバウンス (50ms/500ms)
                                +-- indexer.reindex() (増分更新)
                                +-- delayedSaveIndex() (2500ms遅延保存)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.d | `source/served/commands/index.d` | ソース | reindexOnChange関数の定義（72-94行目） |
| extension.d | `source/served/extension.d` | ソース | textDocument/didChangeの他ハンドラ |
| types.d | `source/served/types.d` | ソース | ワークスペース設定 |
| async.d | `source/served/utils/async.d` | ソース | setTimeout/clearTimeoutユーティリティ |
