# 機能設計書 73-LSP RPC通信 (serve-d:lsp)

## 概要

本ドキュメントは、serve-dのサブパッケージ `serve-d:lsp` の設計を記述する。JSON-RPC通信、stdin/stdoutファイルリーダー、テキストドキュメント管理を提供し、LSPサーバーの通信基盤として機能する。

### 本機能の処理概要

**業務上の目的・背景**：LSPサーバーとクライアント間のJSON-RPC 2.0通信を実現する基盤レイヤーである。stdin/stdoutを通じたバイトストリームの読み書き、JSON-RPCメッセージのフレーミング（Content-Lengthヘッダ）、リクエスト/レスポンス/通知の送受信、および開いているテキストドキュメントのインメモリ管理を担当する。

**機能の利用シーン**：serve-dの起動時にRPCProcessorファイバーが作成され、stdinからのLSPメッセージの読み込みとstdoutへの書き込みを継続的に処理する。テキストドキュメントマネージャは、エディタで開かれているドキュメントの内容を管理し、各LSP機能が最新のドキュメント内容にアクセスできるようにする。

**主要な処理内容**：
1. JSON-RPCプロセッサ（RPCProcessor）：ファイバーベースのメッセージ読み書き、リクエスト/レスポンス/通知の送受信
2. ファイルリーダー（FileReader）：プラットフォーム固有のstdin読み込み（Windows API / POSIX）
3. テキストドキュメントマネージャ：Document構造体によるインメモリドキュメント管理、インクリメンタル更新、位置計算

**関連システム・外部連携**：stdin/stdoutを介したLSPクライアントとの通信。Content-Lengthヘッダベースのメッセージフレーミングプロトコル。

**権限による制御**：なし（通信基盤として全機能に使用される）

## 関連画面

本サブパッケージは直接的に画面と関連しない。全てのLSPリクエスト/レスポンスの通信基盤として使用される。

## 機能種別

基盤ライブラリ / 通信レイヤー

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| stdinストリーム | FileReader | Yes | クライアントからのJSON-RPCメッセージを読み込むストリーム | Content-Lengthヘッダが含まれること |
| ResponseMessage | ResponseMessage | Yes | レスポンス送信用メッセージ | jsonrpcフィールド、idフィールドが必要 |
| RequestMessage | RequestMessage | Yes | リクエスト送信用メッセージ | methodフィールドが必要 |

### 入力データソース

- stdin（標準入力）からのLSPクライアントメッセージ
- serve-d内部からのレスポンス/通知メッセージ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| JSON-RPCメッセージ | string | Content-Lengthヘッダ付きのJSON-RPCメッセージ文字列 |
| Document | Document | インメモリのドキュメント表現（URI、言語ID、バージョン、テキスト内容） |

### 出力先

- stdout（標準出力）へのLSPクライアントへのメッセージ送信
- serve-d内部モジュールへのDocument提供

## 処理フロー

### 処理シーケンス

```
1. RPCProcessor起動
   └─ ファイバーとしてstdinからの読み込みループを開始
2. メッセージ読み込み
   └─ FileReaderがstdinからデータをバッファリング
3. フレーミング解析
   └─ Content-Lengthヘッダからメッセージ長を取得
4. JSONパース
   └─ メッセージボディをJSONとしてパース
5. ディスパッチ
   └─ method名に基づいてハンドラにルーティング
6. レスポンス送信
   └─ sendメソッドでContent-Lengthヘッダ付きJSONを書き出し
```

### フローチャート

```mermaid
flowchart TD
    A[RPCProcessor.run 開始] --> B{stdinにデータあり?}
    B -->|No| C[Fiber.yield]
    C --> B
    B -->|Yes| D[Content-Lengthヘッダ解析]
    D --> E[メッセージボディ読み込み]
    E --> F[JSONパース]
    F --> G{リクエスト or 通知?}
    G -->|リクエスト| H[ハンドラ呼び出し + レスポンス送信]
    G -->|通知| I[ハンドラ呼び出し]
    H --> B
    I --> B
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-73-01 | JSON-RPC 2.0準拠 | 全メッセージにjsonrpc:"2.0"フィールドを含む | メッセージ送信時 |
| BR-73-02 | Content-Lengthフレーミング | メッセージはContent-Length: {n}\r\n\r\n{body}形式で送受信 | 全メッセージ |
| BR-73-03 | ドキュメント言語ID推定 | languageIdが未設定の場合、ファイル拡張子から推定（.d=d, .dml=dml, .dt=diet等） | Document.getLanguageId |
| BR-73-04 | ファイバーベース処理 | RPCProcessorはFiberとして動作し、IO待ちでyieldする | 常時 |

### 計算ロジック

Document構造体はUTF-8テキストのインクリメンタル更新をサポートし、LSPの行・列位置（0ベース、UTF-16コードユニット単位）とバイトオフセット間の変換を行う。

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

本機能ではデータベース操作は行わない。テキストドキュメントはインメモリで管理される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Exception | jsonrpcフィールドのないオブジェクトを送信しようとした場合 | メッセージ構造を修正 |
| - | ReadError | stdinからの読み込み失敗（Windows: ReadFile失敗） | ログ出力してプロセッサを停止 |

### リトライ仕様

通信エラー時のリトライは行わない。接続はstdin/stdoutの単方向パイプのため、再接続はクライアント側の責任。

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

不要（ステートレスなメッセージ送受信）。

## パフォーマンス要件

- ファイバーベースの非ブロッキングIO処理
- RPCProcessorのファイバースタックサイズ: 4096 * 32バイト
- FileReaderは4096バイトバッファで効率的な読み込みを行う

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

stdin/stdoutはローカルプロセス間通信のため、ネットワークセキュリティの考慮は不要。ただし、stdinの偽装には注意が必要。

## 備考

- Windows環境ではWin32 API (WaitForSingleObject, ReadFile)を使用したイベントベースの読み込みを行う
- macOS/Linux環境ではPOSIX標準のファイル読み込みを使用
- LDCコンパイラのmacOS環境ではTLS変数の問題を回避するためFiber.allowMigrationを使用

---

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

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

### 推奨読解順序

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

Document構造体によるテキストドキュメント管理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | textdocumentmanager.d | `lsp/source/served/lsp/textdocumentmanager.d` | Document構造体（13-88行目）: URI、言語ID、バージョン、テキスト内容の管理 |

**読解のコツ**: `getLanguageId`プロパティ（36-67行目）ではファイル拡張子からの言語ID推定が行われる。`.d`/`.di`はD言語、`.dt`はdietテンプレート、`.dml`はDMLとして判定される。

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

RPCProcessorファイバーの構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | jsonrpc.d | `lsp/source/served/lsp/jsonrpc.d` | RPCProcessor class（19-150行目）: ファイバーとしてのコンストラクタ、send系メソッド |

**主要処理フロー**:
1. **23-34行目**: コンストラクタでFileReaderとFileを受け取り、ファイバーサイズ4096*32で初期化
2. **48-71行目**: `send(ResponseMessage)`でJSON-RPCレスポンスを組み立て送信
3. **97-103行目**: `send(RequestMessage)`でJSON-RPCリクエストを組み立て送信
4. **139-145行目**: `sendRawPacket`でContent-Lengthヘッダ付きのパケットをstdoutに書き出し

#### Step 3: ファイルリーダーを理解する

プラットフォーム固有のstdin読み込み処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | filereader.d | `lsp/source/served/lsp/filereader.d` | WindowsStdinReader（13-79行目）: Win32 APIベースのイベント駆動読み込み |

**主要処理フロー**:
- **35行目**: `GetStdHandle(STD_INPUT_HANDLE)`でstdinハンドル取得
- **40行目**: `WaitForSingleObject(stdin, 1000)`で1秒タイムアウト付きで待機
- **46行目**: `ReadFile`でバッファにデータ読み込み
- **57行目**: `synchronized(mutex)`でスレッドセーフにデータ追加

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

```
RPCProcessor (Fiber)
    │
    ├─ FileReader.read (stdinからの読み込み)
    │      ├─ WindowsStdinReader (Win32 API)
    │      └─ PosixFileReader (POSIX)
    │
    ├─ send(ResponseMessage) ──▶ sendRawPacket ──▶ stdout書き出し
    ├─ send(RequestMessage) ──▶ sendRawPacket ──▶ stdout書き出し
    │
    └─ TextDocumentManager
           ├─ Document (インメモリドキュメント)
           ├─ didOpen / didChange / didClose
           └─ 位置計算 (行列 <-> バイトオフセット)
```

### データフロー図

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

stdin ────────────────▶ FileReader ──────────▶ バイトバッファ
バイトバッファ ────────▶ RPCProcessor ────────▶ JSONメッセージ解析
JSONメッセージ ────────▶ ディスパッチャ ───────▶ ハンドラ呼び出し
レスポンス ────────────▶ send() ──────────────▶ stdout
テキスト変更通知 ──────▶ TextDocumentManager ──▶ Document更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| jsonrpc.d | `lsp/source/served/lsp/jsonrpc.d` | ソース | JSON-RPC通信の中核（RPCProcessor、メッセージ送受信） |
| filereader.d | `lsp/source/served/lsp/filereader.d` | ソース | プラットフォーム固有のstdin読み込み実装 |
| textdocumentmanager.d | `lsp/source/served/lsp/textdocumentmanager.d` | ソース | テキストドキュメントのインメモリ管理 |
| protocol.d | `protocol/source/served/lsp/protocol.d` | ソース | メッセージ型定義（ResponseMessage, RequestMessage等） |
