# 通知設計書 6-textDocument/didClose

## 概要

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

### 本通知の処理概要

`textDocument/didClose` 通知は、エディタ（クライアント）でファイルが閉じられた際にserve-dサーバーに送信される通知である。extension.dのonDidCloseDocumentハンドラで処理され、外部プロジェクトのファイルについてはリント警告のクリア処理が行われる。また、TextDocumentManagerがインメモリのドキュメントを削除する。

**業務上の目的・背景**：閉じられたドキュメントのインメモリ管理を解放し、メモリリソースを適切に管理する。また、外部プロジェクト（ワークスペース外）のファイルについては、エディタ上の診断マーカーをクリアして、閉じたファイルの不要な警告表示を防ぐ。プロジェクト内のファイルについては、ファイルを閉じても診断結果を保持し、Problems一覧等で継続的に問題を確認できるようにする。

**通知の送信タイミング**：ユーザーがエディタ上でファイルを閉じたときにクライアントから送信される。

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

**通知内容の概要**：閉じられたドキュメントのURI（TextDocumentIdentifier）で構成される。

**期待されるアクション**：サーバーがインメモリのドキュメントを削除し、外部ファイルの場合は診断情報をクリアする。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（JSON-RPC通知） |
| 優先度 | 中 |
| リトライ | 無し |

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

クライアントがファイルを閉じた際に自動的にserve-dサーバーへ送信される。

## 通知テンプレート

### LSP通知の場合

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

### 本文テンプレート

```json
{
  "jsonrpc": "2.0",
  "method": "textDocument/didClose",
  "params": {
    "textDocument": {
      "uri": "file:///path/to/file.d"
    }
  }
}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| textDocument.uri | 閉じられたドキュメントのURI | クライアントのファイルシステム | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ユーザー操作 | エディタでファイルを閉じる | 常に送信 | クライアントが自動送信 |

### 送信抑止条件

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

## 処理フロー

### 受信フロー

```mermaid
flowchart TD
    A[textDocument/didClose通知受信] --> B[TextDocumentManager.process]
    B --> C[Documentオブジェクト削除]
    C --> D[ハンドラ: onDidCloseDocument]
    D --> E{ワークスペース外のファイル?}
    E -->|Yes| F[全診断プロバイダの該当URI診断をnullに設定]
    F --> G[updateDiagnostics呼び出し]
    G --> H[クライアントに空の診断を送信]
    E -->|No| I[診断結果を保持]
    H --> J[終了]
    I --> J
```

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

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

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| TextDocumentManager.documentStore | DELETE | ドキュメントのインメモリ表現を削除 |
| diagnostics[0..2] | UPDATE | 外部ファイルの場合、該当URIの診断をnullに設定 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ドキュメント未登録 | 未登録URIに対するdidClose | TextDocumentManagerがwarningログを出力 |

### リトライ仕様

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

## 配信設定

### レート制限

該当なし

### 配信時間帯

制限なし

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

ドキュメントURIのみが送信されるため、セキュリティリスクは低い。

## 備考

- ワークスペース外ファイル判定はworkspaceIndex()がsize_t.maxを返すかどうかで行われる
- プロジェクト内ファイルは閉じても診断結果を保持する設計（"but keep warnings in local projects"というコメントあり）
- TextDocumentManager.unloadDocument()が呼ばれてインメモリドキュメントが削除される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protocol.d | `lsp/source/served/lsp/protocol.d` | DidCloseTextDocumentParams構造体の定義 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | textdocumentmanager.d | `lsp/source/served/lsp/textdocumentmanager.d` | TextDocumentManager.process()（892行目〜902行目）でtextDocument/didCloseをハンドリングし、unloadDocument()で削除 |

**主要処理フロー**:
1. **893行目**: DidCloseTextDocumentParamsをデシリアライズ
2. **896行目**: unloadDocument(targetUri)でインメモリ表現を削除
3. **898行目**: 未登録URIの場合はwarningログを出力

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | onDidCloseDocument（1129行目〜1145行目）。ワークスペース外ファイルの診断クリア処理 |

**主要処理フロー**:
- **1133行目**: workspaceIndex()でワークスペース外判定
- **1137行目〜1140行目**: 全診断プロバイダの該当URI診断をnullに設定
- **1142行目**: updateDiagnostics()で空の診断をクライアントに送信

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

```
[クライアント: textDocument/didClose送信]
    |
    v
[serverbase.d: processNotify]
    |
    +-- documents.process(msg)                    [textdocumentmanager.d:892]
    |       +-- unloadDocument(uri)               [textdocumentmanager.d:850]
    |
    +-- onDidCloseDocument(params)                [extension.d:1129]
            +-- workspaceIndex(uri) == size_t.max?
            +-- diagnostics[n][uri].diagnostics = null  (外部ファイルのみ)
            +-- updateDiagnostics(uri)             [diagnosticmanager.d:59]
```

### データフロー図

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

DidCloseTextDocumentParams -->  TextDocumentManager.process()  -->  Document削除
  textDocument.uri         -->  onDidCloseDocument()           -->  診断クリア(外部ファイルのみ)
                           -->  updateDiagnostics()            -->  publishDiagnostics(空配列)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.d | `source/served/extension.d` | ソース | onDidCloseDocumentハンドラ |
| textdocumentmanager.d | `lsp/source/served/lsp/textdocumentmanager.d` | ソース | ドキュメント削除処理 |
| diagnosticmanager.d | `source/served/linters/diagnosticmanager.d` | ソース | 診断クリアとupdateDiagnostics |
| types.d | `source/served/types.d` | ソース | workspaceIndex()関数 |
| serverbase.d | `serverbase/source/served/serverbase.d` | ソース | processNotify |
