# 機能設計書 22-ドキュメントハイライト (textDocument/documentHighlight)

## 概要

本ドキュメントは、serve-d LSPサーバーにおけるドキュメントハイライト機能（textDocument/documentHighlight）の設計を記述する。カーソル位置のシンボルのローカル使用箇所をハイライト情報として返却する機能であり、DCDによる主実装とDCDExt（libdparse）によるフォールバックの二段構えで実現されている。

### 本機能の処理概要

**業務上の目的・背景**：コード編集時に、カーソル位置のシンボルがドキュメント内のどこで使用されているかを視覚的に把握することは、変数のスコープ理解やリファクタリング前の影響範囲確認において重要である。本機能はエディタのシンボルハイライト表示に対応する。

**機能の利用シーン**：開発者がエディタ上でシンボル（変数名・関数名等）にカーソルを置いた際に自動的に呼び出され、同一ドキュメント内での当該シンボルの全使用箇所をハイライト表示する。

**主要な処理内容**：
1. カーソル位置のバイトオフセットを計算する
2. DCD（D Completion Daemon）のfindLocalUse APIを使用してシンボルのローカル使用箇所を検索する
3. DCDが結果を返さない場合、DCDExt（libdparse拡張）のhighlightRelated APIでフォールバック検索を行う
4. 各使用箇所をDocumentHighlight形式（write/read/text種別付き）に変換して返却する

**関連システム・外部連携**：DCDComponent（D Completion Daemon）、DCDExtComponent（libdparse拡張コンポーネント）

**権限による制御**：設定 `config.d.enableDCDHighlight` でDCDハイライトの有効/無効を制御し、`config.d.enableFallbackHighlight` でフォールバックハイライトの有効/無効を制御する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | ドキュメントハイライト（textDocument/documentHighlight） | 主画面 | カーソル位置のシンボルのローカル使用箇所をハイライト情報として返却する（DCD・DCDExtの二段構え） |

## 機能種別

データ検索（シンボル使用箇所のローカル検索）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| textDocument.uri | DocumentUri | Yes | 対象ドキュメントのURI | 有効なドキュメントURIであること |
| position | Position | Yes | カーソル位置（行・列） | ドキュメント範囲内であること |

### 入力データソース

- LSPクライアントからのtextDocument/documentHighlightリクエストのDocumentHighlightParams
- ドキュメントマネージャに保持されたドキュメントのテキストデータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| range | TextRange | ハイライト対象の位置範囲 |
| kind | DocumentHighlightKind | ハイライト種別（write: 宣言箇所、read: 使用箇所、text: フォールバック） |

### 出力先

LSPクライアント（JSON-RPCレスポンスとして返却）

## 処理フロー

### 処理シーケンス

```
1. documentHighlightリクエスト受信
   └─ DocumentHighlightParamsからURI・位置を取得
2. ドキュメントのクローンを取得（immutable化）
   └─ cast(immutable)documents[uri].clone()
3. カーソル位置をバイトオフセットに変換
   └─ document.positionToBytes(params.position)
4. ファイル別設定の取得
   └─ config(document.uri)
5. DCDハイライト実行（enableDCDHighlight有効時）
   └─ documentHighlightImpl呼び出し
   5-1. DCDComponent.findLocalUse APIを呼び出す
   5-2. 宣言箇所をDocumentHighlightKind.writeで追加
   5-3. 使用箇所をDocumentHighlightKind.readで追加
6. フォールバックハイライト実行（DCDが結果を返さず、enableFallbackHighlight有効時）
   └─ fallbackDocumentHighlight呼び出し
   6-1. DCDExtComponent.highlightRelated APIを呼び出す
   6-2. 全関連箇所をDocumentHighlightKind.textで追加
7. 結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[documentHighlight リクエスト受信] --> B[ドキュメントクローン取得]
    B --> C[カーソル位置をバイトオフセットに変換]
    C --> D{enableDCDHighlight?}
    D -->|Yes| E[documentHighlightImpl 実行]
    D -->|No| F{enableFallbackHighlight?}
    E --> G{結果あり?}
    G -->|Yes| H[結果返却]
    G -->|No| F
    F -->|Yes| I[fallbackDocumentHighlight 実行]
    F -->|No| J[空配列返却]
    I --> H
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-22-01 | DCD優先 | DCDコンポーネントを優先的に使用する | enableDCDHighlightが有効 |
| BR-22-02 | フォールバック | DCDが結果を返さない場合にDCDExtを使用する | enableFallbackHighlightが有効かつDCD結果が空 |
| BR-22-03 | 宣言箇所判定 | DCD結果でdeclarationFilePath == "stdin"の場合、宣言箇所として扱う | DCD findLocalUse結果の解析時 |
| BR-22-04 | ハイライト種別 | DCD: 宣言=write、使用=read。フォールバック: 全てtext | 各実装内 |
| BR-22-05 | immutableクローン | ドキュメントはimmutableクローンとして取得し、処理中の変更を防ぐ | 処理開始時 |

### 計算ロジック

特になし。バイトオフセットから位置への変換はDocumentクラスのnextPositionBytes/movePositionBytesメソッドを使用する。

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

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

データベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 空結果 | DCDComponentが存在しない場合 | null（空配列）を返却 |
| - | 空結果 | DCDExtComponentが存在しない場合（フォールバック時） | null（空配列）を返却 |
| - | 空結果 | シンボルがローカルスコープに存在しない場合 | 空配列を返却 |

### リトライ仕様

リトライは不要。

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

トランザクションは使用しない（読み取り専用操作）。

## パフォーマンス要件

- DCDのfindLocalUseはFiber内で非同期実行される（getYieldで待機）
- フォールバックのhighlightRelatedはlibdparseによるローカル解析で動作する

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

特になし。

## 備考

- 本機能はリネーム機能（No.24, No.25）からも内部的に利用される。rename.dのprovideRenameおよびprepareRename関数がdocumentHighlightImplを直接呼び出している
- DCDが"stdin"を返すのはカレントドキュメント内のシンボルであることを示す慣例的な値である
- documentHighlightImplとfallbackDocumentHighlightはpackageスコープで公開されており、rename.dからアクセス可能になっている

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.d | `source/served/types.d` | DocumentHighlight, DocumentHighlightKind (write/read/text), TextRange の型定義 |

**読解のコツ**: DocumentHighlightKindのwrite, read, textの3種類が使い分けられている。writeは宣言箇所、readは参照箇所、textはフォールバック時の汎用マッチを表す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | highlight.d | `source/served/commands/highlight.d` | provideDocumentHighlight関数（11-24行目）がLSPプロトコルメソッドのエントリーポイント |

**主要処理フロー**:
1. **14行目**: `cast(immutable)documents[...].clone()` ドキュメントのimmutableクローン取得
2. **15行目**: `document.positionToBytes` カーソル位置のバイトオフセット変換
3. **16行目**: `config(document.uri)` ファイル別設定の取得
4. **18行目**: `documentHighlightImpl` DCD実装への委譲（enableDCDHighlight時）
5. **20-21行目**: フォールバック判定とfallbackDocumentHighlight呼び出し

#### Step 3: DCD実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | highlight.d | `source/served/commands/highlight.d` | documentHighlightImpl関数（26-58行目）でDCDのfindLocalUse APIを呼び出す |

**主要処理フロー**:
- **39行目**: `backend.best!DCDComponent(file).findLocalUse(codeText, currOffset).getYield` DCDへの問い合わせ
- **41-47行目**: 宣言箇所（declarationFilePath == "stdin"）のwrite種別ハイライト追加
- **49-55行目**: 使用箇所のread種別ハイライト追加

#### Step 4: フォールバック実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | highlight.d | `source/served/commands/highlight.d` | fallbackDocumentHighlight関数（60-80行目）でDCDExtのhighlightRelated APIを呼び出す |

**主要処理フロー**:
- **63行目**: `backend.hasBest!DCDExtComponent(file)` DCDExtの存在確認
- **72行目**: `backend.best!DCDExtComponent(file).highlightRelated(codeText, currOffset)` DCDExtへの問い合わせ
- **76行目**: 全結果をtext種別で追加

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

```
provideDocumentHighlight (highlight.d:12)
    |
    +-- documentHighlightImpl (highlight.d:26) [package]
    |       |
    |       +-- DCDComponent.findLocalUse (workspaced/com/dcd.d)
    |       +-- Document.wordRangeAt
    |       +-- Document.nextPositionBytes
    |
    +-- fallbackDocumentHighlight (highlight.d:60) [package]
            |
            +-- DCDExtComponent.highlightRelated (workspaced/com/dcdext.d)
            +-- Document.nextPositionBytes
```

### データフロー図

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

DocumentHighlightParams ----> provideDocumentHighlight --------> DocumentHighlight[]
  (uri, position)                    |
                                     v
                              documentHighlightImpl (DCD)
                              [宣言: write, 使用: read]
                                     |
                             (結果空の場合)
                                     v
                              fallbackDocumentHighlight (DCDExt)
                              [全てtext種別]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| highlight.d | `source/served/commands/highlight.d` | ソース | ドキュメントハイライトのメイン実装（3関数: provideDocumentHighlight, documentHighlightImpl, fallbackDocumentHighlight） |
| types.d | `source/served/types.d` | ソース | LSP型定義（DocumentHighlight, DocumentHighlightKind等） |
| rename.d | `source/served/commands/rename.d` | ソース | 本機能のdocumentHighlightImplを内部利用するリネーム機能 |
| dcd.d (workspaced) | `workspace-d/source/workspaced/com/dcd.d` | ソース | DCDComponent.findLocalUse APIの実装 |
| dcdext.d (workspaced) | `workspace-d/source/workspaced/com/dcdext.d` | ソース | DCDExtComponent.highlightRelated APIの実装 |
