# 機能設計書 68-保存時インデックス更新

## 概要

本ドキュメントは、serve-dにおける保存時インデックス更新機能の設計を記述する。テキストドキュメントの保存時にインデックスを更新し、ファイル保存をトリガーとしたインデックスの確定的な更新を行う。

### 本機能の処理概要

**業務上の目的・背景**：変更時インデックス更新（機能No.67）はデバウンス付きの増分更新であるため、保存されたファイルの最終状態が必ずしもインデックスに反映されていない可能性がある。本機能はファイル保存をトリガーとして確定的なインデックス更新を行い、保存済みファイルの状態がインデックスに正確に反映されることを保証する。

**機能の利用シーン**：
- 開発者がD言語ソースファイルを保存した際に自動的にトリガーされる
- Ctrl+S等のファイル保存操作後

**主要な処理内容**：
1. textDocument/didSave通知を受信する
2. D言語ファイルかどうか確認する
3. インデックスが有効かどうか確認する
4. 変更時のデバウンスタイマーをキャンセルする
5. IndexComponentのreindexSavedで保存済みインデックス更新を実行する
6. インデックスの遅延保存を予約する

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

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

## 関連画面

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

## 機能種別

データ更新・インデックス確定更新

## 入力仕様

### 入力パラメータ

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

### 入力データソース

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

## 出力仕様

### 出力データ

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

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. textDocument/didSave通知を受信
   └─ reindexOnSave(params)が呼び出される
2. D言語ファイルチェック
   └─ document.getLanguageId != "d" ならreturn
3. インデックス有効チェック
   └─ config.d.enableIndex == false ならreturn
4. 変更時デバウンスタイマーのキャンセル
   └─ clearTimeout(reindexChangeTimeout) で変更時タイマーを取り消し
5. IndexComponentの存在確認
   └─ backend.hasBest!IndexComponent(filePath)
6. 保存済みインデックス更新
   └─ indexer.reindexSaved(filePath, document.rawText)
7. インデックスの遅延保存
   └─ delayedSaveIndex(indexer)
```

### フローチャート

```mermaid
flowchart TD
    A[textDocument/didSave 通知受信] --> B{D言語ファイル?}
    B -->|No| Z[終了]
    B -->|Yes| C{enableIndex 有効?}
    C -->|No| Z
    C -->|Yes| D[変更時デバウンスタイマーをキャンセル]
    D --> E{IndexComponent あり?}
    E -->|No| Z
    E -->|Yes| F[indexer.reindexSaved で保存済み更新]
    F --> G[delayedSaveIndex で遅延保存]
    G --> Z
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-68-01 | D言語限定 | D言語ファイル以外はインデックス更新しない | 常時 |
| BR-68-02 | インデックス有効チェック | enableIndexがfalseのワークスペースではスキップ | 常時 |
| BR-68-03 | 変更時タイマーキャンセル | 保存時にreindexChangeTimeoutをキャンセルして重複更新を防止 | 常時 |
| BR-68-04 | reindexSaved使用 | 保存時はreindex（増分）ではなくreindexSavedを使用 | 常時 |

### 計算ロジック

特になし。

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

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

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

## エラー処理

### エラーケース一覧

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

### リトライ仕様

なし。次回の保存時に再実行される。

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

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

## パフォーマンス要件

- 変更時タイマーのキャンセルにより重複インデックス更新を回避
- delayedSaveIndexで2500ms遅延保存
- reindexSavedはreindexとは異なるAPIで、保存済みファイルに最適化されている可能性がある

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

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

## 備考

- `@protocolNotification("textDocument/didSave")` でtextDocument/didSaveの追加ハンドラとして登録
- 変更時インデックス更新（機能No.67）のreindexChangeTimeoutを保存時にキャンセルする連携がある
- reindexSavedとreindexは異なるIndexComponent APIである点に注意
- 同一のtextDocument/didSave通知はextension.dの他のハンドラ（DScanner、DUBリント、テスト検出等）でも処理される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.d | `source/served/commands/index.d` | reindexChangeTimeout変数（71行目）との関連 |

**読解のコツ**: reindexOnSaveは変更時（reindexOnChange）と保存時（reindexOnSave）の連携を理解することが重要。保存時に変更時タイマーをキャンセルすることで、保存直後の不要な増分更新を防ぐ。

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

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

**主要処理フロー**:
1. **96行目**: `@protocolNotification("textDocument/didSave")` でハンドラ登録
2. **99-100行目**: ドキュメント取得、D言語チェック
3. **102-103行目**: enableIndexチェック
4. **105-106行目**: ファイルパス取得、変更時タイマーキャンセル
5. **108-111行目**: IndexComponentの存在確認とreindexSaved実行
6. **112行目**: delayedSaveIndex呼び出し

#### Step 3: 変更時との比較

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

**比較ポイント**:
- 変更時：デバウンス付き、reindex(false)で増分更新
- 保存時：即座に実行、reindexSaved()で保存済み更新、変更時タイマーをキャンセル

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

```
reindexOnSave(params) [index.d:96-114]
    |
    +-- documents[params.textDocument.uri] (ドキュメント取得)
    |
    +-- document.getLanguageId (言語チェック)
    |
    +-- workspace(uri).config.d.enableIndex (インデックス有効チェック)
    |
    +-- clearTimeout(reindexChangeTimeout) (変更時タイマーキャンセル)
    |
    +-- backend.best!IndexComponent(filePath)
    |
    +-- indexer.reindexSaved(filePath, document.rawText) (保存済み更新)
    |
    +-- delayedSaveIndex(indexer) [index.d:117-123]
        +-- setTimeout(2500ms)
        +-- indexer.saveIndex()
```

### データフロー図

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

textDocument/didSave    ──▶  reindexOnSave()                   ──▶  インデックスデータ（更新）
(DidSaveTextDocumentParams)    |
                              +-- 変更時タイマーキャンセル
                              +-- indexer.reindexSaved() (保存済み更新)
                              +-- delayedSaveIndex() (2500ms遅延保存)
```

### 関連ファイル一覧

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