# 機能設計書 34-シンボル検索

## 概要

本ドキュメントは、OpenCodeにおけるLSPを使用したシンボル検索機能について記載する。この機能により、AIアシスタントはワークスペース全体からシンボル（関数、クラス、変数等）を検索し、コードベースの構造を効率的に把握できる。

### 本機能の処理概要

**業務上の目的・背景**：大規模なコードベースで特定のシンボル（関数、クラス、インターフェース等）を見つけるには、ファイル名だけでなくコード内容に基づく検索が必要である。LSPのシンボル検索機能を活用することで、AIアシスタントはシンボル名やパターンに基づいてコードベース全体を効率的に検索できる。

**機能の利用シーン**：
- 特定の関数名を持つ関数がどこで定義されているか検索する
- クラス名の一部から対象クラスを特定する
- インターフェースやタイプエイリアスをワークスペース全体から探す
- ドキュメント内のシンボル構造（アウトライン）を取得する

**主要な処理内容**：
1. ワークスペースシンボル検索（workspaceSymbol）: ワークスペース全体からクエリに一致するシンボルを検索
2. ドキュメントシンボル取得（documentSymbol）: 特定ファイル内のシンボル構造を取得
3. シンボル種別フィルタリング: Class、Function、Method、Interface等の重要シンボルのみを返却
4. 結果件数制限: 検索結果を上位10件に制限

**関連システム・外部連携**：
- 各言語のLSPサーバー（シンボル情報の提供元）
- LSPツール（エージェントからの利用インターフェース）

**権限による制御**：LSPツール使用時には`lsp`権限の確認が行われる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | セッション | 補助機能 | LSPツールの実行結果表示 |

## 機能種別

データ取得 / コード検索

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| operation | "workspaceSymbol" \| "documentSymbol" | Yes | 実行する操作種別 | - |
| filePath | string | Yes (documentSymbol) | 対象ファイルのパス | ファイルが存在すること |
| query | string | No (workspaceSymbol) | 検索クエリ文字列 | - |

### 入力データソース

- ファイルシステム: 対象ファイルの存在確認
- LSPサーバー: シンボル情報

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Symbol[] | array | ワークスペースシンボル検索結果 |
| Symbol.name | string | シンボル名 |
| Symbol.kind | number | シンボル種別（SymbolKind） |
| Symbol.location | Location | シンボルの位置情報 |
| DocumentSymbol[] | array | ドキュメントシンボル結果 |
| DocumentSymbol.name | string | シンボル名 |
| DocumentSymbol.kind | number | シンボル種別 |
| DocumentSymbol.range | Range | シンボルの範囲 |
| DocumentSymbol.selectionRange | Range | シンボルの選択範囲 |
| DocumentSymbol.detail | string | 追加詳細情報（オプション） |

### 出力先

- ツール実行結果: JSON形式で結果を返却

## 処理フロー

### 処理シーケンス

```
1. workspaceSymbol検索
   └─ 全LSPクライアントに対してクエリ送信
   └─ 結果のシンボル種別フィルタリング
   └─ 上位10件に制限
   └─ 結果を結合して返却

2. documentSymbol取得
   └─ ファイルパスからURIを生成
   └─ 対応LSPクライアントにリクエスト送信
   └─ 結果をフィルタリング（null除去）
   └─ 結果を返却
```

### フローチャート

```mermaid
flowchart TD
    A[シンボル検索呼び出し] --> B{操作種別}
    B -->|workspaceSymbol| C[全クライアント取得]
    B -->|documentSymbol| D[ファイルパスからURI生成]
    C --> E[workspace/symbolリクエスト]
    D --> F[textDocument/documentSymbolリクエスト]
    E --> G[シンボル種別フィルタリング]
    G --> H[上位10件制限]
    H --> I[結果結合]
    F --> J[null除去]
    I --> K[JSON形式で返却]
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-34-01 | シンボル種別フィルタリング | Class, Function, Method, Interface, Variable, Constant, Struct, Enumのみを返却 | workspaceSymbol |
| BR-34-02 | 結果件数制限 | 検索結果を上位10件に制限 | workspaceSymbol |
| BR-34-03 | null除去 | 結果配列からnull/undefinedを除去 | 全操作 |

### 計算ロジック

**SymbolKind定義**（LSP仕様）:
| Kind値 | シンボル種別 |
|-------|------------|
| 1 | File |
| 2 | Module |
| 3 | Namespace |
| 4 | Package |
| 5 | Class |
| 6 | Method |
| 7 | Property |
| 8 | Field |
| 9 | Constructor |
| 10 | Enum |
| 11 | Interface |
| 12 | Function |
| 13 | Variable |
| 14 | Constant |

フィルタ対象: 5 (Class), 6 (Method), 11 (Interface), 12 (Function), 13 (Variable), 14 (Constant), 23 (Struct), 10 (Enum)

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

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| LSPError | 通信エラー | LSPリクエストが失敗 | 空配列を返却（catch句で処理） |
| NoResults | 検索結果なし | シンボルが見つからない | 空配列を返却 |

### リトライ仕様

- LSPリクエスト失敗時のリトライは行わない

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

該当なし

## パフォーマンス要件

- workspaceSymbol検索は全クライアントに並列でリクエストを送信
- 結果件数を10件に制限することで応答サイズを抑制

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

- 検索対象はワークスペース内のファイルに限定される
- lsp権限の確認が必要

## 備考

workspaceSymbol検索では空文字列クエリを指定すると、全シンボルを検索対象とする（LSPサーバーの実装依存）。

---

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

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

### 推奨読解順序

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

シンボル型の定義を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/opencode/src/lsp/index.ts` | Symbol型定義（37-49行目） |
| 1-2 | index.ts | `packages/opencode/src/lsp/index.ts` | DocumentSymbol型定義（51-62行目） |
| 1-3 | index.ts | `packages/opencode/src/lsp/index.ts` | SymbolKind列挙型定義（319-346行目） |

**読解のコツ**: SymbolはLocation（URI + Range）を持ち、DocumentSymbolはRangeを直接持つ。DocumentSymbolはネスト構造を表現可能。

#### Step 2: シンボル種別フィルタを理解する

検索結果のフィルタリングロジック。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/opencode/src/lsp/index.ts` | kinds配列定義（348-357行目） |

**主要処理フロー**:
- **348-357行目**: フィルタ対象のシンボル種別配列（Class, Function, Method, Interface, Variable, Constant, Struct, Enum）

#### Step 3: workspaceSymbol検索

ワークスペース全体のシンボル検索。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/opencode/src/lsp/index.ts` | workspaceSymbol関数（359-369行目） |

**主要処理フロー**:
- **360-361行目**: runAllで全クライアントに並列リクエスト
- **362-365行目**: workspace/symbolリクエスト送信
- **365行目**: kinds配列でフィルタリング
- **366行目**: slice(0, 10)で上位10件に制限
- **368行目**: flat()で結果を結合

#### Step 4: documentSymbol取得

ファイル内シンボル構造の取得。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.ts | `packages/opencode/src/lsp/index.ts` | documentSymbol関数（371-384行目） |

**主要処理フロー**:
- **372行目**: fileURLToPathでURIをパスに変換
- **373-381行目**: textDocument/documentSymbolリクエスト送信
- **382-384行目**: flat()とfilter(Boolean)で結果を整形

#### Step 5: runAll並列実行

全クライアントへの並列リクエスト。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | index.ts | `packages/opencode/src/lsp/index.ts` | runAll関数（457-461行目） |

**主要処理フロー**:
- **458行目**: 全クライアントの取得
- **459-460行目**: 全クライアントに対してPromise.allで並列実行

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

```
LSP.workspaceSymbol(query)
    │
    └─ runAll(client => ...)
           │
           ├─ state().clients - 全クライアント取得
           │
           └─ Promise.all([...])
                  │
                  └─ client.connection.sendRequest("workspace/symbol", {query})
                         │
                         └─ result.filter(x => kinds.includes(x.kind))
                                │
                                └─ result.slice(0, 10)

LSP.documentSymbol(uri)
    │
    ├─ fileURLToPath(uri) - パス変換
    │
    └─ run(file, client => ...)
           │
           └─ client.connection.sendRequest("textDocument/documentSymbol", {textDocument: {uri}})
                  │
                  └─ result.flat().filter(Boolean)
```

### データフロー図

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

query ───────────────▶ workspace/symbol送信 ───────▶ Symbol[]
                            │
                            ▼
                    シンボル種別フィルタリング
                            │
                            ▼
                    上位10件制限
                            │
                            ▼
                    結果結合 ─────────────────────▶ Symbol[]

uri ─────────────────▶ documentSymbol送信 ─────────▶ DocumentSymbol[]
                            │
                            ▼
                    null除去
                            │
                            ▼
                    結果整形 ─────────────────────▶ DocumentSymbol[]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/opencode/src/lsp/index.ts` | ソース | workspaceSymbol、documentSymbol関数、SymbolKind定義 |
| lsp.ts | `packages/opencode/src/tool/lsp.ts` | ソース | LSPツール定義（workspaceSymbol、documentSymbol操作） |
| client.ts | `packages/opencode/src/lsp/client.ts` | ソース | LSP接続管理、リクエスト送信 |
