# 通知設計書 5-textDocument/didOpen

## 概要

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

### 本通知の処理概要

`textDocument/didOpen` 通知は、エディタ（クライアント）でファイルが開かれた際にserve-dサーバーに送信される通知である。サーバー側では2つのハンドラが登録されている。extension.dのonDidOpenDocumentではリンティングの実行判断を行い、rename_listener.dのmarkRecentFileOpenedでは最近開いたファイルの追跡を行う。さらに、TextDocumentManagerがドキュメントの内容をインメモリに格納する。

**業務上の目的・背景**：LSPサーバーがドキュメントの内容を把握するためには、クライアントから開かれたドキュメントの通知を受け取る必要がある。serve-dはこの通知をトリガーとして、ドキュメントの初回リンティング、最近開いたファイルの追跡（ファイル作成・リネーム検出用）、インメモリドキュメントストアへの登録を行う。

**通知の送信タイミング**：ユーザーがエディタ上でファイルを開いたとき（新規ファイルの作成直後を含む）にクライアントから送信される。

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

**通知内容の概要**：開かれたドキュメントのURI、言語ID、バージョン番号、テキスト内容（TextDocumentItem）で構成される。

**期待されるアクション**：サーバーがドキュメントをインメモリに登録し、設定に応じてリンティングを実行する。ファイル作成検出のためのトラッキングも行われる。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（JSON-RPC通知） |
| 優先度 | 高（ドキュメント管理に必須） |
| リトライ | 無し（クライアント側の実装に依存） |

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

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

## 通知テンプレート

### LSP通知の場合

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

### 本文テンプレート

```json
{
  "jsonrpc": "2.0",
  "method": "textDocument/didOpen",
  "params": {
    "textDocument": {
      "uri": "file:///path/to/file.d",
      "languageId": "d",
      "version": 1,
      "text": "module app;\n\nvoid main() {}\n"
    }
  }
}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| textDocument.uri | ドキュメントのURI | クライアントのファイルシステム | Yes |
| textDocument.languageId | 言語識別子 | クライアントの言語判定 | Yes |
| textDocument.version | ドキュメントバージョン | クライアントの管理値 | Yes |
| textDocument.text | ドキュメントの全テキスト | クライアントのバッファ | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ユーザー操作 | エディタでファイルを開く | 常に送信 | クライアントが自動送信 |
| ユーザー操作 | 新規ファイルの作成と表示 | 常に送信 | クライアントが自動送信 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| LSP接続未確立 | サーバーが初期化されていない場合はクライアントが通知を保留する |

## 処理フロー

### 受信フロー

```mermaid
flowchart TD
    A[textDocument/didOpen通知受信] --> B[TextDocumentManager.process]
    B --> C[Documentオブジェクト作成・登録]
    C --> D[ハンドラ1: onDidOpenDocument]
    C --> E[ハンドラ2: markRecentFileOpened]
    D --> F{lintOnFileOpen設定}
    F -->|always| G[リンティング実行]
    F -->|project| H{プロジェクト内ファイル?}
    F -->|never| I[スキップ]
    H -->|Yes| G
    H -->|No| I
    G --> J[didChangeハンドラに委譲]
    E --> K[RecentFilesに追跡記録]
    K --> L{created + opened?}
    L -->|Yes| M[onFullyCreate実行]
    L -->|No| N[待機]
```

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

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| TextDocumentManager.documentStore | ドキュメントのインメモリ格納 | Document[DocumentUri]型の連想配列 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| TextDocumentManager.documentStore | INSERT | 新しいDocumentオブジェクトを登録 |
| RecentFiles.infos | UPDATE | 最近開いたファイル情報を更新 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ハンドラ例外 | onDidOpenDocumentまたはmarkRecentFileOpened内で例外発生 | processNotify内でキャッチし、エラーログ出力 |

### リトライ仕様

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

## 配信設定

### レート制限

該当なし（クライアント駆動の通知のため）

### 配信時間帯

制限なし

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

ドキュメントの全テキストがJSON-RPC経由で送信される。ソースコードの内容が含まれるが、同一プロセス間の通信であるため、外部への漏洩リスクは低い。

## 備考

- TextDocumentManagerのprocess()でドキュメントのインメモリ登録が行われる（textdocumentmanager.d:884行目）
- onDidOpenDocumentはlintOnFileOpen設定（"always" / "project" / デフォルト）に基づいてリンティング実行を判断する
- markRecentFileOpenedはRecentFiles構造体で最大8ファイルの追跡を行い、5秒以内にcreatedとopenedの両方が記録されるとonFullyCreateが呼ばれる
- initialize時のtextDocumentSync.openCloseがtrueに設定されているため、クライアントはdidOpen/didClose通知を送信する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protocol.d | `lsp/source/served/lsp/protocol.d` | DidOpenTextDocumentParams構造体、TextDocumentItem構造体の定義 |
| 1-2 | textdocumentmanager.d | `lsp/source/served/lsp/textdocumentmanager.d` | Document構造体（14行目〜）、TextDocumentManager構造体（744行目〜） |
| 1-3 | rename_listener.d | `source/served/workers/rename_listener.d` | FileOpenInfo構造体（17行目〜47行目）、RecentFiles構造体（50行目〜91行目） |

**読解のコツ**: Document構造体はuri、languageId、version_、textの4フィールドを持ち、テキスト操作のユーティリティメソッドを多数提供する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | textdocumentmanager.d | `lsp/source/served/lsp/textdocumentmanager.d` | TextDocumentManager.process()（882行目〜921行目）でtextDocument/didOpenをハンドリングし、Documentをインメモリに登録 |
| 2-2 | serverbase.d | `serverbase/source/served/serverbase.d` | processNotify()（348行目〜387行目）でdocuments.process(msg)を呼び出した後、protocolNotificationハンドラを実行 |

**主要処理フロー**:
1. **serverbase.d:371行目**: documents.process(msg) - TextDocumentManagerへの通知転送
2. **textdocumentmanager.d:884行目**: textDocument/didOpenの処理 - insertOrUpdate(Document(params.textDocument))
3. **serverbase.d:373行目**: protocolNotificationハンドラの実行

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | onDidOpenDocument（1114行目〜1127行目）。lintOnFileOpen設定に基づくリンティング判断 |
| 3-2 | rename_listener.d | `source/served/workers/rename_listener.d` | markRecentFileOpened（108行目〜112行目）。RecentFilesへのファイル追跡登録 |

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

```
[クライアント: textDocument/didOpen送信]
    |
    v
[serverbase.d: processNotify]
    |
    +-- documents.process(msg)                    [textdocumentmanager.d:882]
    |       +-- insertOrUpdate(Document(item))    [textdocumentmanager.d:884]
    |
    +-- protocolNotificationハンドラ実行
            |
            +-- onDidOpenDocument(params)          [extension.d:1114]
            |       +-- config(uri).d.lintOnFileOpen判定
            |       +-- onDidChangeDocument(...)   (リンティング委譲)
            |
            +-- markRecentFileOpened(params)        [rename_listener.d:108]
                    +-- recentFiles.get(uri).setOpened()
                    +-- onFullyCreate(uri)         (created+openedの場合)
```

### データフロー図

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

DidOpenTextDocumentParams -->  TextDocumentManager.process()   -->  Document登録
  textDocument.uri       -->  onDidOpenDocument()              -->  リンティング結果(publishDiagnostics)
  textDocument.text      -->  markRecentFileOpened()           -->  RecentFiles更新
  textDocument.version   -->                                       onFullyCreate(条件付き)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| textdocumentmanager.d | `lsp/source/served/lsp/textdocumentmanager.d` | ソース | ドキュメントのインメモリ管理 |
| extension.d | `source/served/extension.d` | ソース | onDidOpenDocumentハンドラ（リンティング判断） |
| rename_listener.d | `source/served/workers/rename_listener.d` | ソース | markRecentFileOpenedハンドラ（ファイル追跡） |
| serverbase.d | `serverbase/source/served/serverbase.d` | ソース | processNotify（通知のルーティング） |
| protocol.d | `lsp/source/served/lsp/protocol.d` | ソース | DidOpenTextDocumentParams等のLSPプロトコル型定義 |
