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

## 概要

本ドキュメントは、Lua Language Serverにおける「ドキュメントハイライト」機能の設計を記述する。この機能は、LSPの`textDocument/documentHighlight`リクエストに対応し、同一シンボルのハイライト表示を提供する。

### 本機能の処理概要

ドキュメントハイライト機能は、カーソル位置のシンボル（変数、関数、フィールドなど）と同じシンボルを現在のファイル内で検索し、その位置情報とハイライト種別（読み取り/書き込み）を返す機能である。また、キーワードのペア（if-end、function-end等）もハイライト対象となる。

**業務上の目的・背景**：コードを読む際に、変数がどこで使用されているかを視覚的に把握したいというニーズがある。この機能により、同一シンボルの全出現箇所がハイライトされ、コードの流れや変数のスコープを理解しやすくなる。

**機能の利用シーン**：
- 変数の使用箇所を視覚的に確認したい場合
- 変数が読み取りか書き込みかを確認したい場合
- if-then-else-endのブロック構造を確認したい場合
- region/endregionのペアを確認したい場合

**主要な処理内容**：
1. カーソル位置のソースノードを特定
2. 同一シンボルの全参照を検索（ローカル変数またはグローバル参照）
3. 各参照に対して読み取り/書き込みの種別を判定
4. キーワードのペア（if-end等）をハイライト
5. region/endregionコメントをハイライト

**関連システム・外部連携**：
- LSPプロトコルの`textDocument/documentHighlight`リクエストハンドラ
- 参照検索システム（vm.getRefs）

**権限による制御**：特になし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 9 | ドキュメントハイライト | 主機能 | カーソル位置のシンボルを同一ファイル内でハイライトする主処理 |

## 機能種別

コードナビゲーション / 視覚化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | uri | Yes | 対象ファイルのURI | 有効なファイルURI |
| offset | integer | Yes | カーソルのオフセット位置 | 正の整数 |

### 入力データソース

- 対象ファイルのAST状態（files.getState）
- 対象ファイルのテキスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| start | integer | ハイライト開始位置 |
| finish | integer | ハイライト終了位置 |
| kind | DocumentHighlightKind | ハイライト種別（Read/Write/Text） |

### DocumentHighlightKind

| 値 | 説明 |
|----|------|
| Read (2) | 読み取りアクセス |
| Write (3) | 書き込みアクセス |
| Text (1) | テキスト（キーワード等） |

### 出力先

LSPレスポンスとしてクライアントに返される

## 処理フロー

### 処理シーケンス

```
1. ASTとテキストを取得
   └─ files.getState(uri)、files.getText(uri)
2. カーソル位置のソースを特定
   └─ findSource(ast, offset, accept)で該当ノードを検索
3. ソースノードの処理
   └─ local: ローカル変数の参照を収集
   └─ getlocal/setlocal: ノードのローカル変数を参照
   └─ field/method: 親ノードの参照を収集
   └─ getindex/setindex/tableindex: 参照を収集
   └─ setglobal/getglobal: グローバル参照を収集
   └─ goto/label: ラベル参照を収集
   └─ string: インデックスキーの場合は参照を収集
   └─ リテラル: 自身のみをハイライト
4. 各参照に対してハイライト種別を判定
   └─ getXXX → Read
   └─ setXXX/local/label → Write
   └─ リテラル → Text
5. キーワードのペアをチェック
   └─ do/function/loop/in/while/repeat: keywordリストをハイライト
   └─ if: 各ブロックのkeywordをハイライト
6. region/endregionをチェック
   └─ コメント内のregion/endregionのペアをハイライト
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[AST/テキスト取得]
    B --> C{取得成功?}
    C -->|No| D[nil を返す]
    C -->|Yes| E[ソースノード特定]
    E --> F{ソース存在?}
    F -->|Yes| G[シンボル参照収集]
    F -->|No| H[キーワードチェック]
    G --> I[各参照をループ]
    I --> J{同一URI?}
    J -->|No| I
    J -->|Yes| K[ハイライト種別判定]
    K --> L[結果に追加]
    L --> M{全参照処理完了?}
    M -->|No| I
    M -->|Yes| H
    H --> N[キーワードペア検索]
    N --> O[region/endregion検索]
    O --> P{結果あり?}
    P -->|No| D
    P -->|Yes| Q[結果を返す]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 同一ファイル限定 | 現在のファイル内の参照のみをハイライト | 全参照 |
| BR-02 | グローバル一致 | グローバル変数は同じグローバル変数のみマッチ | グローバル参照時 |
| BR-03 | リテラル一致 | リテラル値は同じリテラル値のみマッチ | リテラル参照時 |
| BR-04 | キーワードペア | do-end、function-end、while-end等のペアをハイライト | キーワード位置時 |
| BR-05 | region対応 | --region/--endregionまたは--#region/--#endregionをペアとしてハイライト | コメント位置時 |

### ハイライト種別判定ルール

| ソース型 | 種別 |
|---------|------|
| getfield | Read |
| setfield/tablefield | Write |
| getmethod | Read |
| setmethod | Write |
| getindex | Read |
| setindex/tableindex | Write |
| getlocal/getglobal/goto | Read |
| setlocal/local/setglobal/label | Write |
| string/boolean/number/integer/nil | Text |

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

この機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 無視 | ASTが取得できない | nilを返す |
| - | 無視 | ハイライト対象がない | nilを返す |

### リトライ仕様

リトライは行わない。

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

該当なし

## パフォーマンス要件

- 参照検索は非同期処理（@async）で実行
- 現在のファイルのみが対象のため、高速に処理可能

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

特になし

## 備考

- ローカル変数は最も効率的に処理される（node.refを直接使用）
- グローバル変数/フィールドはvm.getRefsを使用
- キーワードハイライトはsource.keywordリストを使用

---

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

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

### 推奨読解順序

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

ハイライト結果の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | highlight.lua | `script/core/highlight.lua` | accept テーブル（215-231行目）で対象ノード型を定義 |
| 1-2 | define.lua | `script/proto/define.lua` | DocumentHighlightKind定義 |

**読解のコツ**: `accept`には通常のシンボル型に加え、リテラル型（string, boolean, number, integer, nil）も含まれる。

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

メイン関数の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | highlight.lua | `script/core/highlight.lua` | メイン関数（244-368行目）がモジュールの戻り値 |
| 2-2 | provider.lua | `script/provider/provider.lua` | textDocument/documentHighlight ハンドラ（530-557行目） |

**主要処理フロー**:
1. **245-249行目**: AST/テキスト取得
2. **253行目**: ソースノード特定
3. **254-346行目**: シンボル参照収集と種別判定
4. **348-354行目**: キーワードペア検索
5. **356-362行目**: region/endregion検索

#### Step 3: シンボル参照収集を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | highlight.lua | `script/core/highlight.lua` | eachRef関数（9-16行目） - グローバル参照収集 |
| 3-2 | highlight.lua | `script/core/highlight.lua` | eachLocal関数（18-25行目） - ローカル参照収集 |
| 3-3 | highlight.lua | `script/core/highlight.lua` | find関数（28-58行目） - 型別参照収集 |

**主要処理フロー**:
- **eachLocal**: node.refを直接走査（効率的）
- **eachRef**: vm.getRefsを使用（グローバル/フィールド用）
- **find**: ソース型に応じてeachLocalまたはeachRefを選択

#### Step 4: キーワードハイライトを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | highlight.lua | `script/core/highlight.lua` | checkInIf関数（60-80行目） - if文のキーワード判定 |
| 4-2 | highlight.lua | `script/core/highlight.lua` | makeIf関数（82-98行目） - if文のキーワード収集 |
| 4-3 | highlight.lua | `script/core/highlight.lua` | findKeyWord関数（100-131行目） - キーワードペア検索 |

#### Step 5: region/endregionを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | highlight.lua | `script/core/highlight.lua` | isRegion/isEndRegion関数（133-147行目） |
| 5-2 | highlight.lua | `script/core/highlight.lua` | checkRegion関数（149-213行目） |

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

```
provider.lua ('textDocument/documentHighlight' ハンドラ)
    │
    └─ highlight.lua (メイン関数)
           │
           ├─ files.getState() [AST取得]
           ├─ files.getText() [テキスト取得]
           ├─ findSource() [ソースノード特定]
           │
           ├─ find()
           │      ├─ eachLocal() [ローカル参照収集]
           │      │      └─ source.node.ref 走査
           │      └─ eachRef() [グローバル/フィールド参照収集]
           │             └─ vm.getRefs()
           │
           ├─ findKeyWord()
           │      ├─ checkInIf() [if文チェック]
           │      └─ makeIf() [if文キーワード収集]
           │
           └─ checkRegion()
                  ├─ isRegion() [region判定]
                  └─ isEndRegion() [endregion判定]
```

### データフロー図

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

URI ─────────────────────┐
                         │
オフセット位置 ───────────┼──▶ highlight() ──▶ results[]
                         │         │
                         │         ▼
                         │   ┌────────────────┐
                         │   │ ソースノード特定 │
                         │   └────────────────┘
                         │         │
                         │   ┌─────┴─────┐
                         │   ▼           ▼
                         │ [シンボル]  [その他]
                         │   │           │
                         │   ▼           ▼
                         │ [参照収集]  [キーワード/region]
                         │   │           │
                         │   ▼           ▼
                         │ [種別判定]   [ペア検索]
                         │   │           │
                         │   └─────┬─────┘
                         │         ▼
                         └─ [{ start, finish, kind }]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| highlight.lua | `script/core/highlight.lua` | ソース | ドキュメントハイライトのメイン実装 |
| provider.lua | `script/provider/provider.lua` | ソース | LSPハンドラ、ハイライトリクエストを処理 |
| find-source.lua | `script/core/find-source.lua` | ソース | カーソル位置のソースノード特定 |
| define.lua | `script/proto/define.lua` | ソース | DocumentHighlightKind定義 |
| vm/init.lua | `script/vm/init.lua` | ソース | getRefs関数を提供 |
| guide.lua | `script/parser/guide.lua` | ソース | AST操作ユーティリティ |
