# 画面設計書 32-ドキュメントシンボル（textDocument/documentSymbol）

## 概要

本ドキュメントは、serve-d LSPサーバーが提供する `textDocument/documentSymbol` リクエストハンドラの画面設計書である。エディタのアウトライン表示やパンくず表示に利用される、ドキュメント内のシンボル一覧を返却する機能を定義する。

### 本画面の処理概要

本機能は、D言語ソースファイル内の全シンボル（クラス、関数、変数、enum等）を検出し、階層的またはフラットな形式でクライアントに返却する。

**業務上の目的・背景**：開発者がD言語ソースファイルの構造を素早く把握するために、エディタのアウトライン（Outline）ビューやパンくずナビゲーション（Breadcrumbs）が必要である。本機能はファイル内の全シンボルを構造化された形式で提供し、コードナビゲーションの効率化を実現する。クラスの入れ子構造、関数のパラメータ情報、非推奨マーク等の付加情報も含む。

**画面へのアクセス方法**：エディタがD言語ファイルを開いた際にクライアントが `textDocument/documentSymbol` リクエストをサーバーに送信する。アウトラインビューの表示更新時にも呼び出される。

**主要な操作・処理内容**：
1. クライアントから `textDocument/documentSymbol` リクエストを受信する
2. クライアントの階層的シンボルサポートの有無を確認する
3. 階層サポートありの場合は `provideDocumentSymbolsHierarchical` を呼び出す
4. 階層サポートなしの場合は `provideDocumentSymbolsOld` をフラット形式で呼び出す
5. DscannerComponentの `listDefinitions` を使用してシンボルを検出する
6. 各シンボルの位置情報をバイトオフセットからPositionに変換する
7. シンボル種別（SymbolKind）やタグ（deprecated等）を設定する
8. キャッシュを活用してパフォーマンスを最適化する

**画面遷移**：本機能は単独のリクエスト・レスポンスである。エディタのアウトライン表示でシンボルを選択すると、エディタ内でカーソル移動が発生するが、これはクライアント側の処理である。

**権限による表示制御**：特別な権限制御はない。クライアントのケイパビリティ（`hierarchicalDocumentSymbolSupport`）に応じてレスポンス形式が切り替わる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 20 | ドキュメントシンボル (textDocument/documentSymbol) | 主機能 | 現在のドキュメント内の全シンボルを階層的またはフラットに返却する（アウトライン表示用） |

## 画面種別

LSPリクエスト・レスポンス（ドキュメントシンボル情報提供）

## URL/ルーティング

LSPメソッド: `textDocument/documentSymbol`

## 入出力項目

### 入力（リクエストパラメータ）

| 項目名 | 型 | 必須 | 説明 |
|--------|------|------|------|
| textDocument.uri | DocumentUri | Yes | 対象ドキュメントのURI |

### 出力（レスポンス - 階層形式）

| 項目名 | 型 | 説明 |
|--------|------|------|
| (配列要素).name | string | シンボル名 |
| (配列要素).kind | SymbolKind | シンボル種別（class_, function_, variable等） |
| (配列要素).range | TextRange | シンボルの全体範囲 |
| (配列要素).selectionRange | TextRange | シンボル名の範囲 |
| (配列要素).children | DocumentSymbol[] | 子シンボルの配列 |
| (配列要素).tags | SymbolTag[] | タグ情報（deprecated等） |
| (配列要素).detail | string | 詳細情報（シグネチャ等） |

### 出力（レスポンス - フラット形式）

| 項目名 | 型 | 説明 |
|--------|------|------|
| (配列要素).name | string | シンボル名 |
| (配列要素).kind | SymbolKind | シンボル種別 |
| (配列要素).location.uri | DocumentUri | ドキュメントURI |
| (配列要素).location.range | TextRange | シンボルの位置範囲 |
| (配列要素).containerName | string | 親コンテナ名 |
| (配列要素).tags | SymbolTag[] | タグ情報 |

## 表示項目

エディタのアウトラインビューに表示される項目。

| 表示項目 | 説明 |
|----------|------|
| シンボル名 | 各シンボルの名前（クラス名、関数名等） |
| シンボルアイコン | シンボル種別に応じたアイコン |
| シンボル階層 | 親子関係のツリー表示 |
| 非推奨マーク | deprecated タグ付きシンボルの取り消し線表示 |

## イベント仕様

### 1-documentSymbolリクエスト

1. `provideDocumentSymbols` 関数がエントリーポイントとして呼び出される
2. クライアントのケイパビリティ `hierarchicalDocumentSymbolSupport` を確認
3. 階層サポートありの場合：`provideDocumentSymbolsHierarchical` を実行
4. 階層サポートなしの場合：`provideDocumentSymbolsOld` をフラット形式で実行
5. 内部的にDscannerComponentの `listDefinitions` を呼び出してシンボル一覧を取得
6. 各シンボルについてバイトオフセットからPositionへの変換、SymbolKind変換、属性（containerName, tags, detail）の設定を行う
7. 階層形式の場合は親子関係の構築（`containerName` に基づく再帰的な割り当て）を行う
8. キャッシュ（`PerDocumentCache`）に結果を格納し、次回以降の高速化を図る

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

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

本機能はデータベースへの更新を行わない（読み取り専用）。

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| documentSymbolリクエスト | なし | SELECT | ドキュメントストアとキャッシュからの読み取りのみ |

## メッセージ仕様

| メッセージ種別 | 条件 | メッセージ内容 |
|---------------|------|---------------|
| 空応答 | DscannerComponentが利用不可またはD言語以外 | null（空のレスポンス）を返却 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| DscannerComponentが利用不可 | null を返却 |
| D言語以外のドキュメント | null を返却 |
| ドキュメントが見つからない | ドキュメントストアのデフォルト処理によりエラー |

## 備考

- キャッシュ機構（`PerDocumentCache`）により、同一ドキュメントに対する連続リクエストは高速に処理される
- `provideDocumentSymbolsOld` は verbose モードもサポートしており、debug/version/unittest 等の詳細シンボルも返却可能
- 階層形式では `containerName` フィールドに基づいて親子関係が構築される
- `makeSymbolInfoEx` 関数でDScanner型からLSP型への変換が統一的に行われる
- 属性マッピング: struct/class/enum/union → containerName, deprecation → SymbolTag.deprecated_, signature/detail → detail

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | symbol_search.d | `source/served/commands/symbol_search.d` | DocumentSymbolInfo構造体（行130-136）の定義。DocumentSymbolのプロキシであること |
| 1-2 | symbol_search.d | `source/served/commands/symbol_search.d` | OldSymbolsCache構造体（行63-67）。verbose/non-verboseの2つのキャッシュを持つ |

**読解のコツ**: `@serdeProxy!DocumentSymbol` アトリビュートにより、DocumentSymbolInfoはシリアライズ時にDocumentSymbol型として扱われる。`alias symbol this` により、DocumentSymbolInfoはDocumentSymbolとしても使える。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | symbol_search.d | `source/served/commands/symbol_search.d` | `provideDocumentSymbols` 関数（行51-61）。ケイパビリティに応じた分岐 |

**主要処理フロー**:
1. **行51**: `@protocolMethod("textDocument/documentSymbol")` でLSPメソッドとして登録
2. **行54-57**: `hierarchicalDocumentSymbolSupport` の確認
3. **行58**: 階層サポートありの場合 `provideDocumentSymbolsHierarchical` を呼び出し
4. **行60**: フラット形式の場合 `provideDocumentSymbolsOld` を呼び出し

#### Step 3: フラット形式処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | symbol_search.d | `source/served/commands/symbol_search.d` | `provideDocumentSymbolsOld` 関数（行70-106）。DScanner経由でのシンボル取得とキャッシュ処理 |

**主要処理フロー**:
- **行72-73**: DscannerComponent利用可能性チェック
- **行75-77**: キャッシュ確認と返却
- **行79-80**: D言語チェック
- **行82-84**: `DscannerComponent.listDefinitions` 呼び出し
- **行91-102**: 各定義のPosition変換と `makeSymbolInfoEx` による変換
- **行103**: キャッシュ格納

#### Step 4: 階層形式処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | symbol_search.d | `source/served/commands/symbol_search.d` | `provideDocumentSymbolsHierarchical` 関数（行139-178）。フラット形式結果を階層構造に変換 |

**主要処理フロー**:
- **行145**: `provideDocumentSymbolsOld` をverboseモードで呼び出し
- **行146-158**: 各シンボルをDocumentSymbolInfoに変換（selectionRange設定含む）
- **行160-173**: `parent` フィールドに基づいて children に配列を組み立て
- **行175**: トップレベルのシンボル（parent無し）のみをフィルタして返却

#### Step 5: シンボル変換ヘルパーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | symbol_search.d | `source/served/commands/symbol_search.d` | `makeSymbolInfoEx` 関数（行108-128）。DefinitionElementからSymbolInformationExへの変換ロジック |

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

```
provideDocumentSymbols (symbol_search.d:52)
    |
    +-- [階層サポートあり]
    |   +-- provideDocumentSymbolsHierarchical (symbol_search.d:139)
    |       +-- provideDocumentSymbolsOld (verbose=true) (symbol_search.d:70)
    |       |   +-- DscannerComponent.listDefinitions
    |       |   +-- makeSymbolInfoEx (symbol_search.d:108)
    |       +-- 親子関係構築ロジック (symbol_search.d:160-173)
    |
    +-- [階層サポートなし]
        +-- provideDocumentSymbolsOld (verbose=false) (symbol_search.d:70)
            +-- DscannerComponent.listDefinitions
            +-- makeSymbolInfoEx (symbol_search.d:108)
```

### データフロー図

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

DocumentSymbolParams   --->  provideDocumentSymbols         --->  DocumentSymbol[] (階層)
  .textDocument.uri           |                                    または
                              +-- ケイパビリティ確認              SymbolInformation[] (フラット)
                              +-- DScanner listDefinitions          .name
                              +-- makeSymbolInfoEx                  .kind
                              +-- バイト→Position変換              .range
                              +-- [階層] 親子関係構築              .children (階層のみ)
                              +-- キャッシュ格納
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| symbol_search.d | `source/served/commands/symbol_search.d` | ソース | ドキュメントシンボル・ワークスペースシンボル両方のリクエストハンドラ |
| complete.d | `source/served/commands/complete.d` | ソース | convertFromDscannerType 関数（DScanner型→SymbolKind変換）の定義 |
| types.d | `source/served/types.d` | ソース | DocumentSymbol, SymbolInformation 等のLSP型定義 |
| extension.d | `source/served/extension.d` | ソース | backend, documents, capabilities等のグローバル変数 |
