# 機能設計書 27-コードレンズ (textDocument/codeLens)

## 概要

本ドキュメントは、serve-d LSPサーバーにおけるコードレンズ機能（textDocument/codeLens）の設計を記述する。DMDインポートのコンパイル時間情報およびProfileGCのGCアロケーション情報をコードレンズとしてエディタに表示する機能である。

### 本機能の処理概要

**業務上の目的・背景**：D言語のimport文はコンパイル時間に大きな影響を与える場合がある。各import文のコンパイルコストを可視化することで、開発者がビルド時間の最適化を行えるようにする。また、GCプロファイラの情報をコード上に直接表示することで、メモリアロケーションのホットスポットを容易に把握できる。

**機能の利用シーン**：エディタがD言語ファイルを表示する際に自動的に呼び出される。インポートタイミング情報はenableDMDImportTimingが有効な場合に、GCプロファイラ情報はenableGCProfilerDecorationsが有効な場合にそれぞれ表示される。

**主要な処理内容**：
1. DMDインポートタイミング: ドキュメント内のimport文を正規表現で検出し、各import文にコードレンズメタデータを付与する
2. ProfileGC: profilegc.logのキャッシュデータから該当ファイルのエントリを取得し、各行にGCアロケーション情報のコードレンズを付与する
3. コードレンズの解決（codeLens/resolve）は別機能（No.28）で処理される

**関連システム・外部連携**：DMDComponent（インポートコンパイル時間計測）、ProfileGCCache（GCプロファイリングデータ）

**権限による制御**：設定 `config.d.enableDMDImportTiming` でDMDインポートタイミングを制御、`config.d.enableGCProfilerDecorations` でProfileGC表示を制御。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 20 | コードレンズ（textDocument/codeLens） | 主画面 | DMDインポートタイミング情報・ProfileGCアロケーション情報をコードレンズとして表示する |
| 20 | コードレンズ（textDocument/codeLens） | 補助機能 | ProfileGCデータをパースしてコードレンズに表示するデータを取得する |
| 20 | コードレンズ（textDocument/codeLens） | 補助機能 | profilegc.logの情報をコードレンズとしてエディタに表示する処理 |

## 機能種別

情報表示（インライン表示による開発支援情報の提供）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| textDocument.uri | DocumentUri | Yes | 対象ドキュメントのURI | 有効なドキュメントURIであること |

### 入力データソース

- LSPクライアントからのtextDocument/codeLensリクエストのCodeLensParams
- ドキュメントマネージャに保持されたドキュメントのテキストデータ
- ProfileGCCache（profilegc.logの解析結果キャッシュ）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| range | TextRange | コードレンズの表示位置 |
| command | Command | 表示テキストとコマンド情報（ProfileGCの場合は即時解決済み） |
| data | JsonValue | 遅延解決用データ（type, code, module, file）。DMDインポートタイミングの場合のみ |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. textDocument/codeLensリクエスト受信（2つのハンドラが呼ばれる）

[code_lens.d - DMDインポートタイミング]
2. D言語ファイルチェック
   └─ D言語でない場合は空配列
3. enableDMDImportTiming設定チェック
   └─ 無効の場合はスキップ
4. importRegex正規表現でimport文を検索
   └─ ドキュメント全文をmatchAll
5. 各import文にCodeLens構築
   └─ data: {type: "importcompilecheck", code, module, file}

[profilegc.d - ProfileGCコードレンズ]
6. enableGCProfilerDecorations設定チェック
   └─ 無効の場合はnull
7. profileGCCacheから該当URIのエントリ取得
   └─ 全キャッシュを走査
8. 各エントリにCodeLens構築（即時解決済み）
   └─ command: "{bytes} bytes allocated / {count} allocations"

9. 両方の結果を結合して返却
```

### フローチャート

```mermaid
flowchart TD
    A[codeLens リクエスト受信] --> B{D言語ファイル?}
    B -->|No| C[空配列]
    B -->|Yes| D{enableDMDImportTiming?}
    D -->|Yes| E[import文を正規表現で検出]
    D -->|No| F[スキップ]
    E --> G[各import文にCodeLens構築 data付き]
    G --> H[DMD結果]

    A --> I{enableGCProfilerDecorations?}
    I -->|No| J[null]
    I -->|Yes| K[profileGCCacheから該当エントリ取得]
    K --> L[各エントリにCodeLens構築 command付き]
    L --> M[ProfileGC結果]

    H --> N[結果結合して返却]
    M --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-27-01 | 言語チェック | D言語ファイルでない場合は空配列を返す | DMDインポートタイミング処理 |
| BR-27-02 | DMDタイミング設定 | enableDMDImportTimingが無効の場合はスキップ | DMDインポートタイミング処理（28行目） |
| BR-27-03 | ProfileGC設定 | enableGCProfilerDecorationsが無効の場合はnullを返す | ProfileGC処理（102行目） |
| BR-27-04 | 遅延解決パターン | DMDインポートタイミングはdata付きで返し、codeLens/resolveで解決する | DMD結果 |
| BR-27-05 | 即時解決パターン | ProfileGCはcommand付きで返し、解決不要 | ProfileGC結果 |
| BR-27-06 | URI一致フィルタ | ProfileGCエントリのうち、リクエストされたURIに一致するもののみを返す | ProfileGC処理（110行目） |

### 計算ロジック

import文の検出にはcode_actions.dで定義されたimportRegex正規表現を使用する：
```
import\s+(?:[a-zA-Z_]+\s*=\s*)?([a-zA-Z_]\w*(?:\.\w*[a-zA-Z_]\w*)*)?(\s*\:\s*(?:[a-zA-Z_,\s=]*(?://.*?[\r\n]|/\*.*?\*/|/\+.*?\+/)?)+)?;?
```

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 空結果 | D言語ファイルでない場合 | 空配列を返却 |
| - | 空結果 | 設定が無効の場合 | 空配列またはnullを返却 |

### リトライ仕様

リトライは不要。

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

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

## パフォーマンス要件

- import文の正規表現マッチはドキュメント全文に対して実行されるが、一般的に高速
- ProfileGCキャッシュの走査は全キャッシュエントリに対して行われる
- コードレンズ自体は軽量で、重い処理はcodeLens/resolve時に遅延実行される

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

特になし。

## 備考

- textDocument/codeLensプロトコルメソッドには2つのハンドラが登録されている：code_lens.dのprovideCodeLensとprofilegc.dのprovideProfileGCCodeLens
- importRegexはcode_actions.dからpackageスコープでインポートされている（code_lens.d 4行目）
- DMDインポートタイミングのコードレンズは遅延解決パターンを使用し、実際のコンパイル時間計測はcodeLens/resolve（No.28）で行われる
- ProfileGCコードレンズはprofilegc.log監視（workspace/didChangeWatchedFiles）と連携してキャッシュを更新する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | profilegc.d | `source/served/workers/profilegc.d` | ProfileGCEntry構造体（15-22行目）とProfileGCCache構造体（24-95行目）のデータ構造 |
| 1-2 | code_actions.d | `source/served/commands/code_actions.d` | importRegex正規表現パターン（30行目）の定義 |

**読解のコツ**: ProfileGCCacheはPerDocumentCache（内部構造体）をURI別にDictionaryで保持するキャッシュ構造。process関数でprofilegc.logの各行をパースしてProfileGCEntryに変換する。

#### Step 2: DMDインポートタイミングのエントリーポイント

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | code_lens.d | `source/served/commands/code_lens.d` | provideCodeLens関数（20-50行目）がDMDインポートタイミングのハンドラ |

**主要処理フロー**:
1. **23行目**: ドキュメント取得とファイルパス変換
2. **25行目**: D言語チェック
3. **28行目**: enableDMDImportTiming設定チェック
4. **33行目**: `document.rawText.matchAll(importRegex)` import文検出
5. **36行目**: バイトオフセットから位置変換（movePositionBytes）
6. **40-47行目**: CodeLens構築（data付き、command未設定）

#### Step 3: ProfileGCコードレンズのエントリーポイント

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | profilegc.d | `source/served/workers/profilegc.d` | provideProfileGCCodeLens関数（99-120行目）がProfileGCのハンドラ |

**主要処理フロー**:
- **102行目**: enableGCProfilerDecorations設定チェック
- **106-118行目**: profileGCCacheの全キャッシュからURI一致エントリを収集
- **112-115行目**: CodeLens構築（command付き、即時解決済み）

#### Step 4: ProfileGCキャッシュ更新の仕組み

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | profilegc.d | `source/served/workers/profilegc.d` | onChangeProfileGC関数（158-172行目）でprofilegc.logの変更を監視してキャッシュ更新 |
| 4-2 | profilegc.d | `source/served/workers/profilegc.d` | setupProfileGCWatchers関数（131-150行目）でファイルウォッチャーを動的登録 |

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

```
[textDocument/codeLens ハンドラ1]
provideCodeLens (code_lens.d:21)
    |
    +-- matchAll(importRegex) (import文検出)
    +-- document.movePositionBytes (位置変換)
    +-- CodeLens構築 (data: importcompilecheck)

[textDocument/codeLens ハンドラ2]
provideProfileGCCodeLens (profilegc.d:100)
    |
    +-- profileGCCache.caches (キャッシュ走査)
    +-- CodeLens構築 (command: "N bytes allocated / M allocations")

[キャッシュ更新]
onChangeProfileGC (profilegc.d:159)
    |
    +-- profileGCCache.update (profilegc.d:67)
    |       +-- ProfileGCCache.PerDocumentCache.process (profilegc.d:30)
    +-- profileGCCache.clear (profilegc.d:90)
```

### データフロー図

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

CodeLensParams -----------> provideCodeLens -----------------> CodeLens[]
  (textDocument.uri)              |                          (data: importcompilecheck)
                                  v
                            matchAll(importRegex)

CodeLensParams -----------> provideProfileGCCodeLens --------> CodeLens[]
  (textDocument.uri)              |                          (command: 即時解決済み)
                                  v
                            profileGCCache走査

profilegc.log -----------> onChangeProfileGC ----------------> profileGCCache更新
  (ファイルウォッチ)              |
                                  v
                            ProfileGCCache.PerDocumentCache.process
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| code_lens.d | `source/served/commands/code_lens.d` | ソース | DMDインポートタイミングのコードレンズ提供（provideCodeLens: 20-50行目） |
| profilegc.d | `source/served/workers/profilegc.d` | ソース | ProfileGCコードレンズ提供とキャッシュ管理（provideProfileGCCodeLens: 99-120行目） |
| code_actions.d | `source/served/commands/code_actions.d` | ソース | importRegex正規表現パターンの定義元（30行目） |
| types.d | `source/served/types.d` | ソース | LSP型定義（CodeLens, CodeLensParams, Command等） |
