# 機能設計書 1-初期化 (initialize)

## 概要

本ドキュメントは、lua-language-serverにおけるLSP初期化機能の設計を記載したものである。クライアントからの`initialize`リクエストを受信し、サーバーの能力（capabilities）を返却する処理の詳細を定義する。

### 本機能の処理概要

**業務上の目的・背景**：LSP（Language Server Protocol）において、サーバーとクライアント間の通信を開始する前に、双方の機能をネゴシエーションする必要がある。initialize機能は、クライアントがサーバーに接続した際に最初に呼び出される必須のリクエストであり、サーバーがサポートする機能（コード補完、定義へ移動、診断など）をクライアントに通知し、適切なエディタ連携を実現する。

**機能の利用シーン**：エディタ（VSCode、Neovim等）がLuaファイルを含むプロジェクトを開いた際、またはLua Language Serverが起動した際に自動的に呼び出される。ユーザーが明示的に操作することはなく、バックグラウンドで実行される。

**主要な処理内容**：
1. クライアント情報（capabilities、rootUri、workspaceFolders等）の受信と解析
2. クライアント情報の初期化（client.init）
3. ワークスペースルートの設定（workspace.initRoot）
4. 複数ワークスペースフォルダのサポート（マルチルート対応）
5. サーバーのcapabilities（対応機能）の構築と返却
6. サーバー情報（名前、バージョン）の返却

**関連システム・外部連携**：LSPクライアント（VSCode、Neovim、Emacs等の各種エディタ）との連携。JSON-RPCプロトコルに基づく通信。

**権限による制御**：特になし。すべてのクライアントが初期化リクエストを送信可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 37 | バージョン表示 | 補助機能 | バージョン情報の取得元 |

## 機能種別

プロトコルハンドシェイク / サーバー初期化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| processId | integer \| null | Yes | クライアントプロセスのID | - |
| clientInfo | object | No | クライアント名とバージョン情報 | - |
| clientInfo.name | string | Yes | クライアント名（例: "Visual Studio Code"） | - |
| clientInfo.version | string | No | クライアントバージョン | - |
| locale | string | No | ユーザーのロケール（例: "ja", "en"） | - |
| rootUri | string \| null | Yes | ワークスペースのルートURI | 有効なURI形式 |
| workspaceFolders | WorkspaceFolder[] \| null | No | マルチルートワークスペースのフォルダ一覧 | - |
| capabilities | ClientCapabilities | Yes | クライアントがサポートする機能 | - |
| initializationOptions | any | No | カスタム初期化オプション | - |

### 入力データソース

LSPクライアントからのJSON-RPCリクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| capabilities | ServerCapabilities | サーバーがサポートする機能一覧 |
| capabilities.textDocumentSync | object | テキスト同期設定（openClose: true, change: 2） |
| capabilities.completionProvider | object | コード補完プロバイダ設定 |
| capabilities.hoverProvider | boolean | ホバー情報サポート |
| capabilities.definitionProvider | boolean | 定義へ移動サポート |
| capabilities.referencesProvider | boolean | 参照検索サポート |
| capabilities.documentSymbolProvider | boolean | ドキュメントシンボルサポート |
| capabilities.workspaceSymbolProvider | boolean | ワークスペースシンボルサポート |
| capabilities.codeActionProvider | object | コードアクションプロバイダ設定 |
| capabilities.codeLensProvider | object | コードレンズプロバイダ設定 |
| capabilities.documentFormattingProvider | boolean | フォーマットサポート |
| capabilities.renameProvider | object | リネームサポート |
| capabilities.foldingRangeProvider | boolean | 折りたたみサポート |
| capabilities.semanticTokensProvider | object | セマンティックトークンサポート |
| capabilities.inlayHintProvider | object | インレイヒントサポート |
| serverInfo | object | サーバー情報 |
| serverInfo.name | string | サーバー名（"sumneko.lua"） |
| serverInfo.version | string | サーバーバージョン |

### 出力先

LSPクライアントへのJSON-RPCレスポンス

## 処理フロー

### 処理シーケンス

```
1. initializeリクエストの受信
   └─ JSON-RPCでクライアントからパラメータを受信

2. クライアント情報の初期化
   └─ client.init(params)でクライアント情報を保存

3. ワークスペースルートの設定
   └─ params.rootUriが存在する場合、workspace.initRoot(params.rootUri)を実行
   └─ capabilityのROOT_PATHを解決

4. ワークスペースフォルダの登録
   └─ workspaceFoldersが存在する場合、各フォルダをworkspace.create()で登録
   └─ workspaceFoldersがなくrootUriのみの場合、rootUriをワークスペースとして登録

5. サーバーcapabilitiesの構築
   └─ cap.getProvider()でサポート機能一覧を取得

6. レスポンスの返却
   └─ capabilities + serverInfoをクライアントに返却
```

### フローチャート

```mermaid
flowchart TD
    A[initializeリクエスト受信] --> B[client.init実行]
    B --> C{rootUri存在?}
    C -->|Yes| D[workspace.initRoot実行]
    C -->|No| E{workspaceFolders存在?}
    D --> E
    E -->|Yes| F[各フォルダをworkspace.create]
    E -->|No| G{rootUri存在?}
    F --> H[capabilitiesを構築]
    G -->|Yes| I[rootUriでworkspace.create]
    G -->|No| H
    I --> H
    H --> J[serverInfoを設定]
    J --> K[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 初期化の一意性 | initializeリクエストはセッションにつき1回のみ有効 | サーバー起動後 |
| BR-002 | ワークスペース優先順位 | workspaceFoldersがある場合はそれを優先、なければrootUriを使用 | 常時 |
| BR-003 | URI正規化 | files.getRealUri()でURIを正規化してから使用 | URI処理時 |

### 計算ロジック

特になし

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

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

本機能はデータベースを使用しない（インメモリ処理のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| -32600 | InvalidRequest | 不正なJSONリクエスト | エラーレスポンスを返却 |
| -32602 | InvalidParams | 必須パラメータの欠落 | エラーレスポンスを返却 |

### リトライ仕様

初期化に失敗した場合、クライアント側で再接続を試行

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

トランザクション管理なし（単一リクエスト・レスポンス）

## パフォーマンス要件

初期化処理は1秒以内に完了すること

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

- ファイルシステムアクセスはワークスペース内に限定
- URIの正規化により、シンボリックリンク攻撃を防止

## 備考

- LSP仕様バージョン: 3.17
- 初期化完了後は`initialized`通知が必要

---

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

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

### 推奨読解順序

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

LSP初期化パラメータとサーバーcapabilitiesの構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | capability.lua | `script/provider/capability.lua` | サーバーが返却するcapabilitiesの構造を定義 |
| 1-2 | define.lua | `script/proto/define.lua` | LSPプロトコルで使用される定数や型定義 |

**読解のコツ**: `capability.lua`の`getProvider()`関数で返却されるオブジェクト構造がLSPクライアントに通知される内容である。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | provider.lua | `script/provider/provider.lua` | `m.register 'initialize'`でハンドラを登録 |

**主要処理フロー**:
1. **111-138行目**: `initialize`ハンドラの定義
2. **113行目**: `client.init(params)`でクライアント情報を初期化
3. **115-117行目**: rootUriが存在する場合、ワークスペースルートを初期化
4. **120-126行目**: workspaceFoldersまたはrootUriでワークスペースを作成
5. **128-136行目**: レスポンスオブジェクトを構築して返却

#### Step 3: クライアント初期化処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | client.lua | `script/client.lua` | クライアント情報の管理とcapabilities解析 |

**主要処理フロー**:
- **656-666行目**: `m.init(t)`関数でクライアント情報を保存、ロケール設定、エンコーディング設定を実行
- **49-71行目**: `m.getAbility(name)`でクライアントのcapabilitiesを階層的に取得

#### Step 4: ワークスペース初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | workspace.lua | `script/workspace/workspace.lua` | ワークスペースの作成と管理 |

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

```
m.register 'initialize' (provider.lua:111-138)
    |
    +-- client.init(params) (client.lua:656-666)
    |       +-- lang(locale) - 言語設定
    |       +-- converter.setOffsetEncoding() - エンコーディング設定
    |
    +-- workspace.initRoot(params.rootUri) (workspace.lua)
    |
    +-- workspace.create(uri, name) (workspace.lua)
    |       +-- scope作成
    |       +-- ファイル監視設定
    |
    +-- cap.getProvider() (capability.lua:48-74)
            +-- mergeFillings() - 各機能のcapabilitiesをマージ
            +-- resolve() - プレースホルダを解決
```

### データフロー図

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

InitializeParams ──────> provider.lua                      InitializeResult
  - processId              m.register 'initialize'           - capabilities
  - clientInfo             |                                   - textDocumentSync
  - rootUri        ───────>+-- client.init()                   - completionProvider
  - workspaceFolders       |     (クライアント情報保存)          - hoverProvider
  - capabilities           |                                   - definitionProvider
                           +-- workspace.initRoot()            - etc...
                           |     (ルート設定)                 - serverInfo
                           |                                   - name
                           +-- workspace.create()              - version
                           |     (ワークスペース登録)
                           |
                           +-- cap.getProvider()
                                 (capabilities構築)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| provider.lua | `script/provider/provider.lua` | ソース | LSPリクエストハンドラの登録・実行 |
| capability.lua | `script/provider/capability.lua` | ソース | サーバーcapabilitiesの構築 |
| client.lua | `script/client.lua` | ソース | クライアント情報の管理 |
| workspace.lua | `script/workspace/workspace.lua` | ソース | ワークスペース管理 |
| proto.lua | `script/proto/proto.lua` | ソース | LSPプロトコル通信処理 |
| define.lua | `script/proto/define.lua` | ソース | LSP定数・型定義 |
| version.lua | `script/version.lua` | ソース | サーバーバージョン情報 |
| file-uri.lua | `script/file-uri.lua` | ソース | ファイルURIの変換処理 |
