# 機能設計書 10-補完項目解決 (completionItem/resolve)

## 概要

本ドキュメントは、lua-language-serverにおける補完項目解決機能の設計を記載したものである。補完候補が選択された際に`completionItem/resolve`リクエストを受信し、詳細情報（ドキュメント、追加編集等）を提供する。

### 本機能の処理概要

**業務上の目的・背景**：補完候補は多数存在することがあり、すべての候補に対して詳細なドキュメントや追加編集情報を事前に計算するとパフォーマンスが低下する。`completionItem/resolve`は、ユーザーが補完候補を選択（またはフォーカス）した時点で詳細情報を遅延取得するための仕組みである。これにより、補完リストの初期表示は高速に行いつつ、必要な時に詳細情報を提供できる。

**機能の利用シーン**：
- 補完候補リストで特定の候補にカーソルを合わせた時
- 補完候補を選択してドキュメントを表示しようとした時
- 補完候補を確定する前に詳細情報を確認したい時

**主要な処理内容**：
1. resolveリクエストの受信とパラメータ解析
2. 補完アイテムのdata.idからスタック情報を取得
3. 遅延計算されたコールバックを実行
4. 詳細情報（detail、documentation、additionalTextEdits）を補完
5. 更新されたCompletionItemを返却

**関連システム・外部連携**：LSPクライアント、補完コア処理

**権限による制御**：特になし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | コード補完 | 補助機能 | 補完候補の詳細情報を提供 |

## 機能種別

コードインテリジェンス / 補完項目解決

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| label | string | Yes | 補完候補の表示ラベル | - |
| kind | integer | No | 補完候補の種類 | - |
| detail | string | No | 詳細情報（既存） | - |
| documentation | MarkupContent | No | ドキュメント（既存） | - |
| data | any | No | resolve用追加データ | - |
| data.id | integer | No | スタックID | - |
| data.uri | string | No | ドキュメントURI | - |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| label | string | 補完候補の表示ラベル |
| kind | integer | 補完候補の種類 |
| detail | string | 詳細情報（更新後） |
| documentation | MarkupContent | ドキュメント（更新後） |
| additionalTextEdits | TextEdit[] | 追加のテキスト編集（auto-require等） |
| その他 | - | 入力された他のプロパティはそのまま返却 |

### 出力先

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

## 処理フロー

### 処理シーケンス

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

2. dataの確認
   └─ item.dataが存在しない場合はそのまま返却

3. パラメータの抽出
   └─ data.idとdata.uriを取得

4. 構文状態の確認
   └─ files.getState(uri)で構文状態を取得
   └─ 取得できない場合はそのまま返却

5. 解決処理の実行
   └─ core.resolve(id)を呼び出し
   └─ resolveStack(id)でコールバックを取得・実行

6. 結果のマージ
   └─ resolved.detailがあればitem.detailを更新
   └─ resolved.descriptionがあればitem.documentationを更新
   └─ resolved.additionalTextEditsがあれば変換して設定

7. レスポンスの返却
   └─ 更新されたitemを返却
```

### フローチャート

```mermaid
flowchart TD
    A[resolveリクエスト受信] --> B{data存在?}
    B -->|No| C[itemをそのまま返却]
    B -->|Yes| D[id, uriを抽出]
    D --> E[files.getState uri]
    E --> F{state存在?}
    F -->|No| C
    F -->|Yes| G[core.resolve id]
    G --> H{resolved存在?}
    H -->|No| C
    H -->|Yes| I[detail更新]
    I --> J[documentation更新]
    J --> K[additionalTextEdits更新]
    K --> L[更新されたitemを返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 遅延解決 | dataがない場合は解決処理をスキップ | 常時 |
| BR-002 | 状態確認 | URIの構文状態がない場合はスキップ | 常時 |
| BR-003 | スタック管理 | 補完時に保存したコールバックをIDで取得 | 常時 |
| BR-004 | 部分更新 | 解決された項目のみ更新、それ以外は元の値を維持 | 常時 |
| BR-005 | Markdown形式 | documentationはmarkdown形式で返却 | 常時 |

### 計算ロジック

resolveStackはスタック（stacks配列）からIDに対応するコールバック関数を取得し、実行する。コールバック関数は補完候補生成時に登録され、詳細情報の計算ロジックを含む。

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | dataなし | 補完アイテムにdataがない | itemをそのまま返却 |
| - | 構文状態なし | ファイルがまだ解析されていない | itemをそのまま返却 |
| - | 解決失敗 | IDに対応するスタックエントリがない | itemをそのまま返却、警告ログ出力 |

### リトライ仕様

エラー時のリトライは行わない（itemをそのまま返却）

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

トランザクション管理なし

## パフォーマンス要件

- resolve処理は補完選択時に呼ばれるため、即座に応答すること
- スタックからのコールバック取得は O(1) で行う

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

特になし

## 備考

- 補完候補が大量にある場合の最適化として、詳細情報は遅延取得される
- additionalTextEditsは主にauto-require機能で使用される

---

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

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

### 推奨読解順序

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

補完アイテムのdata構造とスタック管理を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | completion.lua | `script/core/completion/completion.lua` | stacksの管理とpushStack/resolveStack |

**読解のコツ**: スタックは補完候補生成時に遅延計算用のコールバックを保存し、resolve時にIDで取得する。

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

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

**主要処理フロー**:
1. **732-771行目**: `completionItem/resolve`ハンドラの定義
2. **736-738行目**: data存在確認、なければそのまま返却
3. **739-740行目**: data.idとdata.uriを抽出
4. **742-745行目**: files.getState(uri)で構文状態を取得
5. **746-749行目**: core.resolve(id)で解決処理を実行
6. **750-768行目**: detail、documentation、additionalTextEditsを更新
7. **769行目**: 更新されたitemを返却

**読解のコツ**: resolve処理では元のitemを直接変更し、新しいフィールドを追加している。

#### Step 3: resolve処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | completion.lua | `script/core/completion/completion.lua` | resolve関数とresolveStack関数 |

**主要処理フロー**:
- **63-71行目**: `resolveStack(id)`関数
  - stacks[id]からコールバックを取得
  - コールバックがなければnilを返却（警告ログ出力）
  - コールバックを実行して結果を返却
- **2400-2403行目**: `resolve(id)`関数
  - resolveStackを呼び出して結果を返却

#### Step 4: スタック管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | completion.lua | `script/core/completion/completion.lua` | pushStackとclearStack |

**主要処理フロー**:
- **48-56行目**: `pushStack(callback)`関数
  - コールバックをスタックに追加
  - stackIDをインクリメントして返却
- **58-60行目**: `clearStack()`関数
  - スタックをクリア

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

```
m.register 'completionItem/resolve' (provider.lua:732-771)
    |
    +-- item.dataの確認
    |
    +-- files.getState(uri) (files.lua)
    |       └─ 構文状態を取得
    |
    +-- core.resolve(id) (completion.lua:2400-2403)
            |
            +-- resolveStack(id) (completion.lua:63-71)
                    |
                    +-- stacks[id] からコールバック取得
                    |
                    +-- callback() を実行
                            |
                            +-- 補完候補固有の処理
                            |   (detail, description, additionalTextEdits計算)
                            |
                            +-- 結果をresolvedとして返却
    |
    +-- item.detailの更新 (resolved.detail)
    |
    +-- item.documentationの更新 (resolved.description -> MarkupContent)
    |
    +-- item.additionalTextEditsの更新 (converter.packRangeで変換)
    |
    +-- itemを返却
```

### データフロー図

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

CompletionItem ───────> provider.lua                      CompletionItem
  - label                 m.register 'completionItem/resolve'   (更新済み)
  - kind                  |                                  - label
  - detail        ───────>+-- data確認                       - kind
  - documentation         |                                  - detail (更新)
  - data                  +-- files.getState()               - documentation (更新)
    - id                  |                                  - additionalTextEdits (追加)
    - uri                 +-- core.resolve(id)
                          |     +-- resolveStack(id)
                          |     +-- callback()
                          |           +-- detail計算
                          |           +-- description計算
                          |           +-- additionalTextEdits計算
                          |
                          +-- 結果をitemにマージ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| provider.lua | `script/provider/provider.lua` | ソース | LSPリクエストハンドラ |
| completion.lua | `script/core/completion/completion.lua` | ソース | 補完処理とresolve処理 |
| files.lua | `script/files.lua` | ソース | ファイル管理 |
| converter.lua | `script/proto/converter.lua` | ソース | 位置情報の変換（packRange） |
| auto-require.lua | `script/core/completion/auto-require.lua` | ソース | additionalTextEditsの生成 |
