# 機能設計書 8-ドキュメントシンボル

## 概要

本ドキュメントは、Clojure LSP サーバーにおけるドキュメントシンボル機能の設計仕様を記載する。この機能は LSP プロトコルの `textDocument/documentSymbol` リクエストに対応し、ファイル内のシンボル一覧を階層的に表示する。

### 本機能の処理概要

**業務上の目的・背景**：開発者がファイル内の構造を素早く把握し、目的のシンボルに移動することを支援する。アウトラインビュー、ブレッドクラム、シンボル一覧など、エディタの様々なUI要素で活用される。特にClojureのような名前空間ベースの言語では、ファイル内のdefn、defmulti、defprotocol等の定義を一目で把握できることが重要である。

**機能の利用シーン**：開発者がエディタのアウトラインビューやシンボル一覧を開いた際、または「ファイル内のシンボルに移動」コマンドを実行した際に本機能が呼び出される。EDNファイルの場合は、キーワードとシンボルの階層構造が表示される。

**主要な処理内容**：
1. 対象ファイルの全シンボル定義を取得
2. 各シンボルを DocumentSymbol に変換
3. 位置順にソート
4. EDNファイルの場合は階層構造を構築
5. DocumentSymbol 配列として返却

**関連システム・外部連携**：特になし

**権限による制御**：本機能に権限による実行制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトは LSP サーバー実装であり、UI 画面は存在しない。エディタのアウトラインビューから呼び出される。 |

## 機能種別

データ検索処理 / UI 表示補助

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| text-document.uri | string | Yes | 対象ドキュメントの URI | 有効な file:// URI |

### 入力データソース

- clj-kondo による静的解析結果（db の :analysis）
- ファイルの AST（EDN の場合）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (配列) | DocumentSymbol[] | シンボル情報のリスト |
| [].name | string | シンボル名 |
| [].kind | integer | シンボルの種類 |
| [].range | Range | シンボルのスコープ範囲 |
| [].selection-range | Range | シンボル名の範囲 |
| [].detail | string | 補足情報（private, reg 等） |
| [].tags | integer[] | タグ（deprecated 等） |
| [].children | DocumentSymbol[] | 子シンボル（EDN の場合） |

### 出力先

LSP プロトコルを通じてエディタクライアントへ DocumentSymbol 配列として返却

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ handlers/document-symbol が textDocument/documentSymbol を受信

2. ファイル種別判定
   └─ URI からファイル種別（clj/cljs/cljc/edn）を判定

3-A. Clojure ファイルの場合
   ├─ q/find-element-definitions で定義を取得
   ├─ element->document-symbol で変換
   └─ symbol-order でソート

3-B. EDN ファイルの場合
   ├─ zloc からデータ構造を取得
   └─ edn->element-tree で階層構造を構築

4. レスポンス返却
   └─ DocumentSymbol 配列を返却
```

### フローチャート

```mermaid
flowchart TD
    A[documentSymbol リクエスト受信] --> B{ファイル種別?}
    B -->|EDN| C[zloc から sexpr 取得]
    B -->|Clojure| D[find-element-definitions]
    C --> E[edn->element-tree]
    D --> F[element->document-symbol]
    E --> G[DocumentSymbol 配列返却]
    F --> H[symbol-order ソート]
    H --> I[vec 変換]
    I --> G
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ファイル種別分岐 | EDN ファイルは階層構造、Clojure ファイルはフラット構造 | URI による判定 |
| BR-02 | 位置順ソート | selection-range の開始位置でソート | 全シンボル |
| BR-03 | スコープ範囲 | range はシンボルのスコープ全体、selection-range は名前部分 | 全シンボル |
| BR-04 | private タグ | :private が true の場合、detail に "private" を設定 | var-definitions |
| BR-05 | deprecated タグ | :deprecated が true の場合、tags に 1 を追加 | 全シンボル |

### 計算ロジック

- シンボル種別: q/element->symbol-kind により要素から LSP SymbolKind を決定
- シンボル名: defmethod の場合は dispatch-val-str を名前に追加

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| シンボル検索 | db :analysis[uri] | SELECT | ファイル内の全定義を取得 |

### テーブル別操作詳細

#### db :analysis[uri]

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | :namespace-definitions | uri で取得 | 名前空間定義 |
| SELECT | :var-definitions | uri で取得 | 変数定義 |
| SELECT | :keyword-definitions | uri で取得 | キーワード定義 |
| SELECT | :var-usages | uri, :defmethod で取得 | defmethod |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | nil 返却 | ファイル解析エラー | nil を返却（ログ出力） |

### リトライ仕様

リトライは行わない。

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

本機能は読み取り専用であり、トランザクション管理は不要。

## パフォーマンス要件

- 応答時間: 通常 50ms 以内
- 単一ファイルのみ対象のため高速

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

- 外部ネットワーク通信なし
- 対象ファイルのシンボル情報のみを返却

## 備考

- EDN ファイルでは keyword-usages と symbols を使用して階層構造を構築
- redefines-test など特殊なシンボルも正しく表示

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | document_symbol.clj | `lib/src/clojure_lsp/feature/document_symbol.clj` | element->document-symbol（14-23行目）で出力データ構造を確認 |

**読解のコツ**: DocumentSymbol は range（スコープ全体）と selection-range（名前部分）の2つの範囲を持つ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | handlers.clj | `lib/src/clojure_lsp/handlers.clj` | document-symbol 関数（320-326行目）が LSP リクエストのエントリーポイント |
| 2-2 | document_symbol.clj | `lib/src/clojure_lsp/feature/document_symbol.clj` | document-symbols 関数（107-119行目）がメインロジック |

**主要処理フロー**:
1. **108行目**: uri-file-type で EDN かどうか判定
2. **109-114行目**: EDN の場合は zloc から sexpr を取得し edn->element-tree で階層構造構築
3. **116-118行目**: Clojure の場合は find-element-definitions で定義取得、変換、ソート

#### Step 3: EDN 階層構造構築を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | document_symbol.clj | `lib/src/clojure_lsp/feature/document_symbol.clj` | edn->element-tree（45-105行目）で EDN の階層構造構築を確認 |

**主要処理フロー**:
- **47-48行目**: コレクションでない場合は nil
- **49-104行目**: reduce でマップやベクタを再帰的に処理
- **69-77行目**: 値の型に応じて kind を決定（string, keyword, boolean, number, array, struct）

#### Step 4: シンボル定義の収集を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | queries.clj | `lib/src/clojure_lsp/queries.clj` | find-element-definitions（736-742行目）でファイル内定義取得を確認 |

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

```
handlers/document-symbol
    │
    └─ f.document-symbol/document-symbols
           │
           ├─ [EDN の場合]
           │      ├─ parser/safe-zloc-of-file
           │      ├─ parser/safe-zloc-sexpr
           │      └─ edn->element-tree
           │             └─ element->document-symbol (再帰)
           │
           └─ [Clojure の場合]
                  ├─ q/find-element-definitions
                  │      ├─ find-namespace-definition-by-uri
                  │      ├─ find-var-definitions
                  │      ├─ find-keyword-definitions
                  │      └─ find-defmethods
                  │
                  ├─ element->document-symbol
                  │      ├─ element->name
                  │      └─ q/element->symbol-kind
                  │
                  └─ symbol-order ソート
```

### データフロー図

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

textDocument/documentSymbol ──▶ handlers/document-symbol ──▶ DocumentSymbol[]
  - uri                          │
                                 ▼
                           document-symbols
                                 │
                                 ├──▶ [EDN]
                                 │      ├─ zloc 取得
                                 │      ├─ sexpr 取得
                                 │      └─ edn->element-tree
                                 │
                                 └──▶ [Clojure]
                                        ├─ find-element-definitions
                                        │      └─ db :analysis[uri]
                                        ├─ element->document-symbol
                                        └─ symbol-order ソート
                                               │
                                               ▼
                                          DocumentSymbol[]
                                            {name, kind, range,
                                             selection-range, detail,
                                             tags, children}
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| document_symbol.clj | `lib/src/clojure_lsp/feature/document_symbol.clj` | ソース | ドキュメントシンボルのメインロジック |
| handlers.clj | `lib/src/clojure_lsp/handlers.clj` | ソース | LSP リクエストハンドラー |
| queries.clj | `lib/src/clojure_lsp/queries.clj` | ソース | シンボル定義の収集、種別判定 |
| parser.clj | `lib/src/clojure_lsp/parser.clj` | ソース | ファイル解析 |
| shared.clj | `lib/src/clojure_lsp/shared.clj` | ソース | 範囲変換ユーティリティ |
| document_symbol_test.clj | `lib/test/clojure_lsp/feature/document_symbol_test.clj` | テスト | ユニットテスト |
| document_symbol_test.clj | `cli/integration-test/integration/document_symbol_test.clj` | テスト | 統合テスト |
