# 機能設計書 11-ドキュメントクローズ (textDocument/didClose)

## 概要

本ドキュメントは、serve-d LSPサーバーにおける「ドキュメントクローズ」機能の設計を記述する。エディタ上でテキストドキュメントが閉じられた際に送信されるLSP通知 `textDocument/didClose` を処理する機能である。

### 本機能の処理概要

テキストドキュメントのクローズ通知を受信し、外部プロジェクト（ワークスペース外）のファイルに対するリント警告をクリアする処理を行う。ワークスペース内のプロジェクトファイルについては、警告を維持する。

**業務上の目的・背景**：エディタでファイルを閉じた後も不要な診断結果が表示され続けることは、開発者にとって混乱の原因となる。特にワークスペース外の外部ファイルについては、閉じた時点で診断結果を消去することで、クリーンな開発環境を維持する。一方、ワークスペース内のファイルについては、ファイルを閉じてもプロジェクト全体の品質把握のため診断情報を維持する設計としている。

**機能の利用シーン**：開発者がエディタ上でタブを閉じる、またはファイルを閉じる操作を行った際に自動的にトリガーされる。特に外部プロジェクトのファイル（ワークスペースに属さないファイル）を参照後に閉じた場合に、診断結果のクリアが実行される。

**主要な処理内容**：
1. クローズ通知の受信とパラメータ抽出
2. 対象ドキュメントがワークスペースに属するかの判定
3. 外部プロジェクトファイルの場合、全診断プロバイダの該当URI診断をnull化
4. 診断マネージャによる診断結果の更新・配信

**関連システム・外部連携**：LSPクライアント（エディタ）からの通知受信、診断マネージャ（diagnosticmanager）との連携

**権限による制御**：特になし。すべてのドキュメントクローズ通知に対して同一の処理が実行される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能に直接関連する画面定義なし |

## 機能種別

データ連携（LSP通知処理） / 状態管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| params | DidCloseTextDocumentParams | Yes | クローズされたドキュメントの情報 | - |
| params.textDocument.uri | DocumentUri | Yes | クローズされたドキュメントのURI | 有効なURI文字列 |

### 入力データソース

LSPクライアントからの `textDocument/didClose` 通知メッセージ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (なし) | void | 本関数は戻り値を返さない（通知ハンドラ） |

### 出力先

- 診断マネージャ経由で `textDocument/publishDiagnostics` 通知をLSPクライアントに送信（外部プロジェクトの場合のみ）

## 処理フロー

### 処理シーケンス

```
1. DidCloseTextDocumentParams を受信
   └─ params.textDocument.uri からドキュメントURIを取得
2. workspaceIndex でワークスペース所属判定
   └─ size_t.max の場合 = 外部プロジェクト（ワークスペース外）
3. 外部プロジェクトの場合:
   3-1. diagnostics 配列（全診断プロバイダ分）を走査
   3-2. 該当URIの診断結果を null に設定
   3-3. updateDiagnostics を呼び出して診断結果を再配信
4. ワークスペース内プロジェクトの場合:
   └─ 何もしない（警告を維持）
```

### フローチャート

```mermaid
flowchart TD
    A[textDocument/didClose 通知受信] --> B{workspaceIndex == size_t.max?}
    B -->|Yes: 外部プロジェクト| C[全診断プロバイダの該当URI診断をクリア]
    C --> D[updateDiagnostics 呼び出し]
    D --> E[終了]
    B -->|No: ワークスペース内| E
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-11-01 | 外部プロジェクト診断クリア | ワークスペースに属さないファイルの診断結果はクローズ時にクリアする | workspaceIndex が size_t.max を返す場合 |
| BR-11-02 | ローカルプロジェクト診断維持 | ワークスペースに属するファイルの診断結果はクローズ後も維持する | workspaceIndex が有効なインデックスを返す場合 |

### 計算ロジック

特になし

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

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

本機能ではデータベース操作は行わない。インメモリの診断キャッシュ（`diagnostics` 配列）の更新のみを行う。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 本機能は通知ハンドラのため、エラー時もクライアントへのエラーレスポンスは行わない | ログ出力で対応 |

### リトライ仕様

リトライ処理なし。通知ハンドラのため、失敗時はクライアントにエラー通知されない。

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

トランザクション管理なし。インメモリ操作のみ。

## パフォーマンス要件

通知ハンドラのため、即時処理が求められる。診断コレクションの走査は O(N*M)（N=診断プロバイダ数、M=URIごとの診断数）であるが、プロバイダ数は3固定（NumDiagnosticProviders=3）のため軽量。

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

特になし。LSPプロトコルの標準通知処理。

## 備考

- 本機能は `@protocolNotification("textDocument/didClose")` アトリビュートにより LSP通知ハンドラとして登録される
- 診断プロバイダは DScanner、DUB、dfmt の3つ（NumDiagnosticProviders=3）

---

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

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

### 推奨読解順序

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

まず、診断データの管理構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | diagnosticmanager.d | `source/served/linters/diagnosticmanager.d` | 診断コレクションの型定義（NumDiagnosticProviders, DiagnosticCollection, diagnostics配列）を確認する |

**読解のコツ**: `diagnostics` はグローバル変数で `DiagnosticCollection[3]` 型。各要素が DScanner/DUB/dfmt の診断結果を保持する。`DiagnosticCollection` は `PublishDiagnosticsParams[]` のエイリアス。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | extension.d | `source/served/extension.d` | `onDidCloseDocument` 関数がエントリーポイント |

**主要処理フロー**:
1. **1129行目**: `@protocolNotification("textDocument/didClose")` でLSP通知として登録
2. **1130行目**: `onDidCloseDocument` 関数定義
3. **1133行目**: `workspaceIndex` でワークスペース所属判定
4. **1135行目**: `diagnosticmanager` モジュールの `diagnostics` と `updateDiagnostics` をインポート
5. **1137-1140行目**: 全診断プロバイダ × 全診断の二重ループで該当URI診断をnull化
6. **1142行目**: `updateDiagnostics` 呼び出しで結果を配信

#### Step 3: 診断マネージャの更新処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | diagnosticmanager.d | `source/served/linters/diagnosticmanager.d` | `updateDiagnostics` 関数（59-89行目）の動作を理解する |

**主要処理フロー**:
- **59行目**: `updateDiagnostics` 関数。`uriHint` 引数で特定URIのみ更新可能
- **61行目**: `combineDiagnostics()` で全プロバイダの診断を統合
- **62-71行目**: 統合結果を `textDocument/publishDiagnostics` 通知でクライアントに送信
- **74-88行目**: 以前送信済みだが現在は存在しないURIの診断をクリア

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

```
onDidCloseDocument (extension.d:1130)
    │
    ├─ workspaceIndex (extension.d) ... ワークスペース所属判定
    │
    ├─ diagnostics[].diagnostics = null ... 診断結果クリア
    │
    └─ updateDiagnostics (diagnosticmanager.d:59)
           ├─ combineDiagnostics (diagnosticmanager.d:16)
           └─ rpc.send ... textDocument/publishDiagnostics 通知送信
```

### データフロー図

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

DidCloseTextDocumentParams ───▶ onDidCloseDocument ───▶ diagnostics 配列更新
                                       │
                                       └──────────────▶ updateDiagnostics
                                                              │
                                                              └──▶ textDocument/publishDiagnostics
                                                                     (空の診断結果をクライアントに送信)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.d | `source/served/extension.d` | ソース | エントリーポイント。onDidCloseDocument 関数定義 |
| diagnosticmanager.d | `source/served/linters/diagnosticmanager.d` | ソース | 診断結果の統合管理・クライアント配信 |
| types.d | `source/served/types.d` | ソース | LSPプロトコル型定義、Configuration等 |
