# 画面設計書 49-シンボル検索

## 概要

本ドキュメントは、VSCodeのシンボル検索画面の設計を記載したものです。シンボル検索は、ワークスペース全体からクラス、関数、変数などのシンボルを検索できるクイックアクセスインターフェースです。

### 本画面の処理概要

シンボル検索（Go to Symbol in Workspace）は、Visual Studio Codeにおいてワークスペース全体のシンボル（クラス、関数、変数、インターフェース等）をファジー検索し、素早くナビゲートできる機能です。言語サーバーやシンボルプロバイダーと連携して、プロジェクト全体のシンボル情報を取得・表示します。

**業務上の目的・背景**：
大規模なコードベースでは、特定のクラスや関数を見つけることが困難になります。シンボル検索は、ファイル構造を意識せずにシンボル名だけでコードに直接ジャンプできるため、コードナビゲーションの効率を大幅に向上させます。特にリファクタリングや既存コードの理解に役立ちます。

**画面へのアクセス方法**：
- キーボードショートカット `Ctrl+T`（Windows/Linux）または `Cmd+T`（macOS）
- コマンドパレットから「Go to Symbol in Workspace...」
- クイックオープンで `#` プレフィックスを入力

**主要な操作・処理内容**：
1. シンボル検索：ワークスペース内のシンボルをファジー検索
2. シンボルへのジャンプ：選択したシンボルの定義位置を開く
3. サイドで開く：Alt+Enter でサイドエディタで開く
4. シンボル種別フィルター：クラス、関数、変数などでフィルター
5. コンテナ検索：シンボルの所属（クラス名、ファイル名）で絞り込み

**画面遷移**：
- ショートカット/プレフィックス → シンボル検索（オーバーレイ）
- シンボル選択 → エディタでシンボル定義を開く
- HTTP(S)シンボル → 外部URLをブラウザで開く

**権限による表示制御**：
- 全てのユーザーがアクセス可能
- 言語サーバーが対応していない言語はシンボル検索不可

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 49 | シンボル検索 | 主機能 | ワークスペースシンボル検索 |
| 48 | クイックオープン | 補助機能 | `#` プレフィックスで切り替え |

## 画面種別

クイックピック（オーバーレイ）

## URL/ルーティング

プレフィックス: `#` (SymbolsQuickAccessProvider.PREFIX)

## 入出力項目

| 項目名 | 入力/出力 | 型 | 必須 | 説明 |
|--------|----------|-----|------|------|
| 検索クエリ | 入力 | string | No | シンボル名の検索文字列 |
| コンテナクエリ | 入力 | string | No | シンボル所属（クラス名等）の検索 |
| シンボル一覧 | 出力 | ISymbolQuickPickItem[] | Yes | 検索結果のシンボルリスト |
| 選択シンボル | 出力 | IWorkspaceSymbol | Yes | ジャンプ先のシンボル |

## 表示項目

| 項目名 | 表示位置 | 説明 |
|--------|----------|------|
| 検索入力欄 | 上部 | シンボル名検索テキストボックス |
| シンボルアイコン | 行左 | シンボル種別に応じたアイコン（Class, Function等） |
| シンボル名 | 行中央 | シンボル名（ハイライト付き） |
| コンテナ名 | シンボル名右 | 所属クラス/ファイルパス |
| 開くボタン | 行右端 | サイドで開くボタン |
| 非推奨表示 | シンボル名 | 取り消し線（@deprecatedシンボル） |

## イベント仕様

### 1-シンボル検索起動

`Ctrl+T` または `#` プレフィックスで：
1. `SymbolsQuickAccessProvider` がアクティブに
2. `defaultFilterValue` でエディタ選択テキストを初期クエリに
3. 空入力時は「No matching workspace symbols」を表示

### 2-シンボル検索

検索テキストを入力すると：
1. `TYPING_SEARCH_DELAY`（200ms）のデバウンス後に検索開始
2. `getWorkspaceSymbols()` でワークスペースシンボルを取得
3. シンボルクエリとコンテナクエリに分割（スペース区切り）
4. `scoreFuzzy2()` でファジースコアリング
5. グローバルシンボル（Class, Interface等）と非グローバルを区別
6. スコア順、名前順、種別順でソート

### 3-シンボルへのジャンプ

シンボルを選択（Enter）すると：
1. `accept()` コールバックが実行される
2. `openSymbol()` メソッドでシンボルを開く
3. プロバイダーの `resolveWorkspaceSymbol()` でシンボル情報を解決
4. HTTP(S) URIの場合は `openerService.open()` で外部オープン
5. それ以外は `editorService.openEditor()` でエディタを開く
6. シンボルの `location.range` の先頭にカーソルを移動

### 4-サイドで開く

ボタンクリックまたはAlt+Enterで：
1. `trigger()` コールバックが実行される
2. `openSymbol()` を `forceOpenSideBySide: true` で呼び出し
3. `SIDE_GROUP` でサイドエディタグループに開く
4. `TriggerAction.CLOSE_PICKER` でピッカーを閉じる

### 5-バックグラウンドで開く

Ctrl+Enter でシンボルを選択すると：
1. `preserveFocus: true` でエディタを開く
2. `forcePinned: true` で固定タブとして開く
3. クイックピックにフォーカスを維持

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| なし | - | - | シンボル検索は永続化データを更新しない |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| noSymbolResults | メッセージ | "No matching workspace symbols" | 検索結果0件時 |
| openToSide | ツールチップ | "Open to the Side" | 横分割設定時 |
| openToBottom | ツールチップ | "Open to the Bottom" | 縦分割設定時 |

## 例外処理

| 例外パターン | 処理内容 | 表示メッセージ |
|-------------|---------|---------------|
| シンボルプロバイダーなし | 空リストを返却 | "No matching workspace symbols" |
| 解決失敗 | 元のシンボル情報を使用 | なし |
| キャンセル | 空配列を返却 | なし |

## 備考

- `SymbolsQuickAccessProvider` が `PickerQuickAccessProvider` を継承
- `TYPING_SEARCH_DELAY` は200msのデバウンス
- `TREAT_AS_GLOBAL_SYMBOL_TYPES` でグローバルシンボル（Class, Enum, File, Interface, Namespace, Package, Module）を定義
- `skipLocal` オプションでローカルシンボルをスキップ可能
- `ThrottledDelayer` で検索を制御
- `scoreFuzzy2` でファジーマッチングとスコアリング
- `SymbolTag.Deprecated` で非推奨シンボルを識別し、取り消し線で表示
- 設定 `workbench.editor.openSideBySideDirection` でサイド表示方向を制御
- 設定 `workbench.editor.enablePreviewFromQuickOpen` でプレビュー動作を制御

---

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

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

### 推奨読解順序

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

まず、シンボル検索で扱う主要なデータ構造を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | search.ts | `src/vs/workbench/contrib/search/common/search.ts` | IWorkspaceSymbol, IWorkspaceSymbolProvider |
| 1-2 | languages.ts | `src/vs/editor/common/languages.ts` | SymbolKind, SymbolKinds, SymbolTag |

**読解のコツ**: シンボルの種別（SymbolKind）とその階層（コンテナ）の関係を把握してください。

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

処理の起点となるプロバイダークラスを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | symbolsQuickAccess.ts | `src/vs/workbench/contrib/search/browser/symbolsQuickAccess.ts` | SymbolsQuickAccessProviderクラス |

**主要処理フロー**:
1. **L33-75**: コンストラクタとdefaultFilterValue（エディタ選択テキスト）
2. **L77-84**: configurationでエディタ設定を取得
3. **L86-98**: _getPicks()とgetSymbolPicks()でシンボル取得
4. **L100-224**: doGetSymbolPicks()でシンボル検索とスコアリング
5. **L226-254**: openSymbol()でシンボルを開く
6. **L256-288**: compareSymbols()でソート

#### Step 3: シンボル取得を理解する

ワークスペースシンボルの取得ロジックを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | search.ts | `src/vs/workbench/contrib/search/common/search.ts` | getWorkspaceSymbols関数 |

#### Step 4: スコアリングを理解する

ファジーマッチングのロジックを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | fuzzyScorer.ts | `src/vs/base/common/fuzzyScorer.ts` | scoreFuzzy2, prepareQuery, pieceToQuery |

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

```
Ctrl+T / "#" プレフィックス
    │
    └─ SymbolsQuickAccessProvider
           │
           ├─ defaultFilterValue
           │      └─ getSelectionSearchString()（エディタ選択テキスト）
           │
           ├─ getSymbolPicks()
           │      └─ delayer.trigger()
           │             └─ doGetSymbolPicks()
           │
           └─ doGetSymbolPicks()
                  │
                  ├─ prepareQuery() / pieceToQuery()
                  │      └─ シンボルクエリとコンテナクエリに分割
                  │
                  ├─ getWorkspaceSymbols()
                  │      └─ IWorkspaceSymbolProvider.provideWorkspaceSymbols()
                  │
                  ├─ scoreFuzzy2()
                  │      └─ ファジースコアリング
                  │
                  ├─ シンボルピック構築
                  │      ├─ iconClass（SymbolKinds.toIcon）
                  │      ├─ label（シンボル名）
                  │      ├─ description（コンテナ/パス）
                  │      ├─ strikethrough（@deprecated）
                  │      └─ buttons（サイドで開く）
                  │
                  └─ compareSymbols()
                         └─ スコア→名前→種別でソート
```

### データフロー図

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

Ctrl+T                 ───▶ SymbolsQuickAccessProvider  ───▶ クイックピック表示
                             │
エディタ選択テキスト   ───▶ ├─ defaultFilterValue
                             │
検索クエリ             ───▶ ├─ クエリ分割
                             │      └─ symbolQuery + containerQuery
                             │
IWorkspaceSymbolProvider ──▶ ├─ getWorkspaceSymbols()
  └─ provideWorkspaceSymbols   └─ IWorkspaceSymbol[]
                             │
                       ───▶ ├─ scoreFuzzy2()
                             │      └─ スコアリング
                             │
                       ───▶ ├─ フィルタリング
                             │      └─ skipLocal, containerQuery
                             │
                       ───▶ └─ ソート
                                   └─ スコア→名前→種別

シンボル選択           ───▶ openSymbol()
                             ├─ resolveWorkspaceSymbol()
                             ├─ openerService.open() [HTTP]
                             └─ editorService.openEditor()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| symbolsQuickAccess.ts | `src/vs/workbench/contrib/search/browser/symbolsQuickAccess.ts` | ソース | メインプロバイダー |
| search.ts | `src/vs/workbench/contrib/search/common/search.ts` | ソース | シンボル取得インターフェース |
| fuzzyScorer.ts | `src/vs/base/common/fuzzyScorer.ts` | ソース | ファジースコアリング |
| languages.ts | `src/vs/editor/common/languages.ts` | ソース | SymbolKind, SymbolTag定義 |
| pickerQuickAccess.ts | `src/vs/platform/quickinput/browser/pickerQuickAccess.ts` | ソース | 基底クラス |
| findController.ts | `src/vs/editor/contrib/find/browser/findController.ts` | ソース | getSelectionSearchString |
