# 機能設計書 18-定義ジャンプ (textDocument/definition)

## 概要

本ドキュメントは、serve-d LSPサーバーにおける「定義ジャンプ」機能の設計を記述する。LSPの `textDocument/definition` リクエストを処理し、カーソル位置のシンボルの定義元位置を返却する機能である。

### 本機能の処理概要

エディタ上でシンボル（変数名・関数名・型名等）に対してGo to Definition操作を行った際に、DCDを使用してシンボルの定義元ファイルと位置を解決し、Location情報として返却する。定義の宣言範囲を解決し、dfmtでフォーマットした宣言テキストも取得する。

**業務上の目的・背景**：コードナビゲーションはIDE/エディタの最も基本的な機能の一つであり、コードベースの理解と保守に不可欠である。特にD言語のように標準ライブラリやサードパーティライブラリへの参照が多い言語では、シンボル定義への即座のジャンプが開発効率に大きく影響する。

**機能の利用シーン**：開発者がエディタ上でシンボルをCtrl+クリック、またはGo to Definitionコマンドを実行した際にトリガーされる。標準ライブラリ、サードパーティライブラリ、プロジェクト内のすべてのシンボルに対応する。

**主要な処理内容**：
1. DCDComponent.findDeclaration でシンボルの定義元ファイル・位置を取得
2. 定義元ファイルのロードとバイトオフセットからPosition変換
3. DCDExtComponent.getDeclarationRange で宣言の範囲を取得
4. DfmtComponentで宣言テキストをフォーマット
5. Location（URI + 範囲）を返却

**関連システム・外部連携**：DCDComponent、DCDExtComponent、DfmtComponent

**権限による制御**：DCDComponentが利用可能である必要がある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 22 | 定義ジャンプ（textDocument/definition） | 主機能 | DCDを使用してカーソル位置のシンボルの定義元位置を返却する |

## 機能種別

データ取得処理 / コードナビゲーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| params | TextDocumentPositionParams | Yes | 定義ジャンプ要求の位置情報 | - |
| params.textDocument.uri | DocumentUri | Yes | 対象ドキュメントのURI | 有効なURI文字列 |
| params.position | Position | Yes | カーソル位置（行・列） | 0ベースの行・列番号 |

### 入力データソース

- LSPクライアントからの `textDocument/definition` リクエスト
- DCDComponentからの定義元解決結果

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (戻り値) | ArrayOrSingle!Location | 定義元のLocation情報（URIと範囲） |
| location.uri | DocumentUri | 定義元ファイルのURI |
| location.range | TextRange | 定義元の位置範囲 |

### 出力先

LSPクライアントへのレスポンスメッセージ

## 処理フロー

### 処理シーケンス

```
1. TextDocumentPositionParams を受信
2. DCDComponent 対応のバックエンドインスタンスを取得
   └─ getBestInstance!DCDComponent で取得、なければ空返却
3. ドキュメント取得と言語ID確認
   └─ "d" 以外は空返却
4. findDeclarationImpl を呼び出し
   4-1. DCDComponent.findDeclaration でシンボル定義位置を取得
   4-2. 結果のファイルパスをURIに変換
        ├─ "stdin" = 現在のドキュメント
        ├─ 絶対パス = uriFromFile で変換
        └─ 相対パス = null（不明）
   4-3. ドキュメントマネージャから定義元ドキュメントをロード
   4-4. DCDExtComponent.getDeclarationRange で宣言範囲を取得（includeDefinition=true）
   4-5. バイトオフセットからPosition変換
   4-6. DfmtComponent で宣言テキストをフォーマット（利用可能な場合）
   4-7. 一時ロードしたドキュメントをアンロード
5. Location を返却
```

### フローチャート

```mermaid
flowchart TD
    A[textDocument/definition 受信] --> B{DCDComponentインスタンスあり?}
    B -->|No| C[空返却]
    B -->|Yes| D[ドキュメント取得]
    D --> E{言語ID == "d"?}
    E -->|No| C
    E -->|Yes| F[findDeclarationImpl 呼び出し]
    F --> G[DCDComponent.findDeclaration]
    G --> H{結果あり?}
    H -->|No| C
    H -->|Yes| I[ファイルパスをURI変換]
    I --> J[定義元ドキュメントロード]
    J --> K[DCDExtComponent.getDeclarationRange]
    K --> L[DfmtComponent でフォーマット]
    L --> M[Location 返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-18-01 | D言語限定 | D言語以外のファイルでは定義ジャンプを提供しない | 全リクエスト |
| BR-18-02 | stdinファイル処理 | DCD結果のファイルが "stdin" の場合は現在のドキュメントURIを使用 | DCD結果処理時 |
| BR-18-03 | 絶対パス変換 | DCD結果が絶対パスの場合はuriFromFileで変換 | DCD結果のファイルが絶対パスの場合 |
| BR-18-04 | 一時ドキュメントアンロード | getOrFromFilesystemで一時ロードしたドキュメントは処理後アンロード | tempLoad == true |
| BR-18-05 | 宣言範囲包含 | provideDefinitionではincludeDefinition=trueで宣言全体の範囲を取得 | 定義ジャンプ時 |
| BR-18-06 | dfmtフォーマット | 宣言テキストはdfmtでフォーマット（行折り返しなし、2スペースインデント等） | DfmtComponent利用可能時 |

### 計算ロジック

dfmtフォーマットオプション:
- `--keep_line_breaks=false`
- `--single_indent=true`
- `--indent_size=2`
- `--indent_style=space`
- `--max_line_length=60`
- `--soft_max_line_length=50`
- `--end_of_line=lf`

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

本機能ではデータベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | インスタンス不在 | DCDComponentのインスタンスがない | 空のArrayOrSingle!Location返却 |
| - | 定義未解決 | DCDが定義位置を見つけられない | 空のArrayOrSingle!Location返却 |
| - | ファイル不在 | 定義元ファイルが存在しない | 空返却 |

### リトライ仕様

リトライなし。

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

トランザクション管理なし。読み取り専用操作。

## パフォーマンス要件

ユーザーのクリック操作に対するリアルタイム応答が必要。DCDのfindDeclarationはgetYieldで非同期結果を取得。定義元ドキュメントの一時ロードが必要になる場合がある。

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

特になし。ローカルファイルへのアクセスのみ。

## 備考

- `findDeclarationImpl` はホバー情報（No.19）でも共有される共通関数
- `includeDefinition` パラメータの違い: 定義ジャンプ=true（宣言全体）、ホバー=false（名前のみ）
- activeInstance グローバル変数が更新される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | definition.d | `source/served/commands/definition.d` | `DeclarationInfo` 構造体（18-22行目）: declaration文字列とLocation情報を保持する型 |

**読解のコツ**: `ArrayOrSingle!Location` はLSPプロトコルの戻り値型で、単一のLocationまたはLocation配列を返却可能。実際には単一のLocationを返却する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | definition.d | `source/served/commands/definition.d` | `provideDefinition` 関数（99-117行目）がLSPメソッドのエントリーポイント |

**主要処理フロー**:
1. **99行目**: `@protocolMethod("textDocument/definition")` でLSPメソッド登録
2. **102-103行目**: DCDComponent対応のベストインスタンス取得
3. **107-109行目**: ドキュメント取得と言語ID確認（D言語以外は空返却）
4. **111-112行目**: `findDeclarationImpl` を呼び出し（includeDefinition=true）
5. **116行目**: Location返却

#### Step 3: 定義解決の共通処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | definition.d | `source/served/commands/definition.d` | `findDeclarationImpl` 関数（24-89行目）のDCD定義解決と宣言範囲取得の共通ロジック |

**主要処理フロー**:
- **27行目**: `DCDComponent.findDeclaration` でシンボル定義位置取得
- **32-38行目**: ファイルパスからURIへの変換（stdin/絶対パス/相対パス）
- **44行目**: `getOrFromFilesystem` で定義元ドキュメントをロード
- **49-55行目**: `DCDExtComponent.getDeclarationRange` で宣言範囲取得
- **67-81行目**: `DfmtComponent.formatSync` で宣言テキストをフォーマット
- **83-84行目**: 一時ドキュメントのアンロード
- **85行目**: Location(uri, range)の構築

#### Step 4: 宣言範囲取得ユーティリティ

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | definition.d | `source/served/commands/definition.d` | `getDeclarationRange` 関数（91-97行目）のDCDExtComponent呼び出しとバイト範囲→テキスト範囲変換 |

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

```
provideDefinition (definition.d:100)
    │
    └─ findDeclarationImpl (definition.d:24)
           │
           ├─ DCDComponent.findDeclaration
           │
           ├─ documents.getOrFromFilesystem
           │
           ├─ getDeclarationRange (definition.d:91)
           │      └─ DCDExtComponent.getDeclarationRange
           │
           ├─ DfmtComponent.formatSync
           │
           └─ documents.unloadDocument (一時ロード分)
```

### データフロー図

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

TextDocumentPosition ──▶ provideDefinition ────────▶ ArrayOrSingle!Location
                              │                         ├─ uri (定義元ファイル)
                              ├─ DCD.findDeclaration    └─ range (定義位置)
                              │    └─ ファイルパス + オフセット
                              ├─ DCDExt.getDeclarationRange
                              │    └─ 宣言範囲
                              └─ Dfmt.formatSync
                                   └─ フォーマット済み宣言テキスト
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| definition.d | `source/served/commands/definition.d` | ソース | provideDefinition, findDeclarationImpl, getDeclarationRange |
| extension.d | `source/served/extension.d` | ソース | コマンド登録 |
| types.d | `source/served/types.d` | ソース | Document, LSP型定義 |
