# 画面設計書 20-コードレンズ（textDocument/codeLens）

## 概要

ソースコード上にインラインで表示する情報（DMDインポートタイミング情報、ProfileGCアロケーション情報等）を提供するLSPメソッドの設計書である。

### 本画面の処理概要

本画面は、LSP標準の `textDocument/codeLens` リクエストを処理し、ソースコード上のimport文に対するDMDインポートコンパイル時間測定のコードレンズを返却する処理を担当する。codeLens/resolveで実際のコンパイル時間を計測し、結果をインラインテキストとして表示する。

**業務上の目的・背景**：D言語のコンパイル時間はインポートするモジュール数に大きく影響を受ける。各import文のコンパイル時間を可視化することで、開発者がコンパイル時間のボトルネックとなるインポートを特定し、最適化できるようにする。

**画面へのアクセス方法**：エディタでD言語ファイルを開くと、設定 `d.enableDMDImportTiming` がtrueの場合にtextDocument/codeLensリクエストが自動的に送信される。各import文の上部にインラインテキスト（コンパイル時間）が表示される。

**主要な操作・処理内容**：
1. クライアントからtextDocument/codeLensリクエストを受信
2. D言語ファイルのみ処理
3. `d.enableDMDImportTiming` 設定がtrueの場合のみ処理
4. ドキュメント内の全import文を正規表現で検出
5. 各import文に対してCodeLensを生成（data内にtype, code, module, fileを格納）
6. codeLens/resolveで実際のコンパイル時間を計測し、Commandのtitleとして返却

**画面遷移**：エディタがファイルを開いた時点で自動的にリクエストされる。ユーザーの明示的な画面遷移はない。

**権限による表示制御**：`d.enableDMDImportTiming` 設定がfalseの場合、コードレンズは生成されない。

## 関連機能

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

## 画面種別

LSPレスポンス（コードレンズリスト）

## URL/ルーティング

LSP標準メソッド: `textDocument/codeLens`

- リクエスト: `CodeLensParams`
- レスポンス: `CodeLens[]`

解決メソッド: `codeLens/resolve`
- リクエスト: `CodeLens`
- レスポンス: `CodeLens`（解決済み）

## 入出力項目

| 項目名 | 型 | 入力/出力 | 説明 |
|--------|-----|----------|------|
| textDocument.uri | DocumentUri | 入力 | 対象ドキュメントのURI |
| codeLens | CodeLens[] | 出力 | import文ごとのコードレンズ配列 |
| codeLens[].range | TextRange | 出力 | import文の位置 |
| codeLens[].data | JsonValue | 出力 | メタデータ（type, code, module, file） |
| codeLens[].command | Command | 出力 | 解決後のインライン表示テキスト（コンパイル時間） |

## 表示項目

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| インポートコンパイル時間 | インラインテキスト | "~{N}ms for importing this" または "no noticable effect for importing this" |

## イベント仕様

### 1-コードレンズ生成（textDocument/codeLens）

provideCodeLens関数:

1. **23行目**: ドキュメント取得
2. **25行目**: D言語以外は空配列返却
3. **28行目**: `d.enableDMDImportTiming` 設定チェック
4. **33行目**: importRegex（code_actions.dからインポート）でドキュメント内の全import文を検出
5. **35-47行目**: 各マッチに対してCodeLensを生成
   - data.type: "importcompilecheck"
   - data.code: マッチしたimport文テキスト
   - data.module: インポートモジュール名
   - data.file: ファイルパス

### 2-コードレンズ解決（codeLens/resolve）

resolveCodeLens関数:

1. **55-57行目**: dataの検証
2. **60-61行目**: type取得
3. **64行目**: type="importcompilecheck" の場合の処理
4. **82行目**: getImportCompilationTime関数でコンパイル時間を計測
5. **83-84行目**: 結果に応じてCommand.titleを設定
   - 10ms未満: "no noticable effect for importing this"
   - 10ms以上: "~{N}ms for importing this"

### 3-インポートコンパイル時間計測

getImportCompilationTime関数:

1. **110-125行目**: キャッシュチェック（コード一致・時間経過確認）
2. **127-131行目**: importCompilationTimeRunning排他制御（Fiber.yieldで待機）
3. **133行目**: DMDComponent.measureSyncでDMDを使用した実測（20回試行、500msタイムアウト）
4. **136行目**: 5ms単位で丸め
5. **137行目**: キャッシュに保存
6. **140-141行目**: 100msのパススルー待機（連続リクエスト制御）

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| なし | なし | なし | データベースアクセスなし |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 条件 |
|-------------|------|---------------|------|
| なし | インライン表示 | "no noticable effect for importing this" | コンパイル時間が10ms未満の場合 |
| なし | インライン表示 | "~{N}ms for importing this" | コンパイル時間が10ms以上の場合 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| D言語以外のファイル | 空の配列を返却 |
| enableDMDImportTimingがfalse | 空の配列を返却 |
| dataが無効 | Exception "Invalid Lens Object" をスロー |
| typeが不明 | Exception "Unknown lens type" をスロー |
| コンパイル失敗 | Exception "Compilation failed" をスロー |
| code/module/fileが空 | 各フィールドごとにException "No valid {field} provided" をスロー |

## 備考

- codeLensProviderのresolveProviderはtrueに設定されている（initialize関数283-285行目）
- コンパイル時間のキャッシュは、500ms以上は20分、30ms以上は5分、それ未満は2分の有効期限を持つ
- std.モジュールのインポートはキャッシュが常に有効（再計測しない）
- importCompilationTimeRunningフラグにより、同時に複数のコンパイル計測が並列実行されることを防止
- importRegexはcode_actions.dで定義されたパッケージレベルのパターンを共有使用している

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | code_lens.d | `source/served/commands/code_lens.d` | CompileCacheの構造体（102-107行目）: SysTime at, string code, int ret |
| 1-2 | code_actions.d | `source/served/commands/code_actions.d` | importRegex（30行目）: import文の正規表現パターン |

**読解のコツ**: code_lens.dはcode_actions.dをインポートしてimportRegexを使用している。

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

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

**主要処理フロー**:
1. **23行目**: `auto document = documents[params.textDocument.uri]` ドキュメント取得
2. **25行目**: D言語チェック
3. **28行目**: `enableDMDImportTiming` 設定チェック
4. **33行目**: `document.rawText.matchAll(importRegex)` でimport文検出
5. **40-46行目**: CodeLens生成（type, code, module, fileをdataに格納）

#### Step 3: resolve処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | code_lens.d | `source/served/commands/code_lens.d` | resolveCodeLens関数（52-95行目）がcodeLens/resolveのハンドラ |

**主要処理フロー**:
1. **55-57行目**: dataの検証
2. **64行目**: type="importcompilecheck" の分岐
3. **82行目**: `getImportCompilationTime(code, module_, file)` 呼び出し
4. **83-84行目**: 結果に応じたCommand設定

#### Step 4: コンパイル時間計測を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | code_lens.d | `source/served/commands/code_lens.d` | getImportCompilationTime関数（98-143行目）: キャッシュ、排他制御、DMD計測 |

**主要処理フロー**:
- **113-125行目**: キャッシュヒット判定（コード一致・有効期限チェック）
- **127-129行目**: importCompilationTimeRunningによる排他制御
- **133行目**: `backend.best!DMDComponent(file).measureSync(code, null, 20, 500)` DMD実測
- **136行目**: 5ms単位で丸め

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

```
textDocument/codeLens
    |
    +-- provideCodeLens() [code_lens.d:20]
            |
            +-- document.rawText.matchAll(importRegex)
            +-- CodeLens生成（data: type/code/module/file）

codeLens/resolve
    |
    +-- resolveCodeLens() [code_lens.d:52]
            |
            +-- [importcompilecheck] getImportCompilationTime() [code_lens.d:98]
                    |
                    +-- キャッシュチェック [code_lens.d:113]
                    +-- importCompilationTimeRunning排他制御 [code_lens.d:127]
                    +-- DMDComponent.measureSync() [code_lens.d:133]
                    +-- 結果キャッシュ保存 [code_lens.d:137]
```

### データフロー図

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

CodeLensParams         +-- provideCodeLens()            +-- CodeLens[]
(textDocument.uri)          |                                  (range, data)
                             +-- importRegex検出
                             +-- CodeLens構築

CodeLens               +-- resolveCodeLens()            +-- CodeLens (解決済み)
(data: type/code/           |                                  |
 module/file)               +-- getImportCompilationTime      +-- command.title
                             |       +-- キャッシュ確認              ("~Nms for importing this"
                             |       +-- DMD実測                     or "no noticable effect")
                             |       +-- 結果キャッシュ
                             +-- Command設定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| code_lens.d | `source/served/commands/code_lens.d` | ソース | メイン実装（provideCodeLens, resolveCodeLens, getImportCompilationTime） |
| code_actions.d | `source/served/commands/code_actions.d` | ソース | importRegex正規表現パターン（30行目） |
| extension.d | `source/served/extension.d` | ソース | codeLensProviderケイパビリティ設定（283-285行目） |
| types.d | `source/served/types.d` | ソース | Configuration.D.enableDMDImportTiming設定（94行目） |
