# 画面設計書 4-DCD更新確認ダイアログ

## 概要

本ドキュメントは、serve-d LSPサーバーにおけるDCD更新確認ダイアログの画面設計書である。DCD（D Completion Daemon）が古い場合にエディタにエラーメッセージを表示し、コンパイル/ダウンロードまたは無視の選択肢を提示する。

### 本画面の処理概要

**業務上の目的・背景**：DCDはD言語のコード補完を担う中核コンポーネントであり、最新バージョンでないと正しく補完が動作しない場合がある。DCDが古いまたは未インストールの場合にユーザーに更新を促し、開発体験を維持するために本ダイアログが存在する。ユーザーは即座に更新するか、更新をスキップして制限付きで継続するかを選択できる。

**画面へのアクセス方法**：No.2 グローバルスタートアップの中で、`DCDComponent.isOutdated` が `true` かつ `config.d.aggressiveUpdate` が `false` の場合に自動的に表示される。`aggressiveUpdate` が `true` の場合はダイアログを表示せず自動更新が実行される。

**主要な操作・処理内容**：
1. DCDの現在のバージョンと期待バージョンを比較し、古い場合にエラーメッセージを構築
2. ソースからのビルドかバイナリダウンロードかに応じて適切な選択肢ボタンを表示
3. ユーザーの選択に応じて更新処理を開始または無視する

**画面遷移**：
- 遷移元：No.2 グローバルスタートアップ（DCD古い場合）
- 遷移先：No.39 DCD更新（served/updateDCD）（更新選択時）

**権限による表示制御**：なし。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 63 | DCD更新 (served/updateDCD) | 主機能 | DCDが古い場合にユーザーにコンパイル/ダウンロードの選択肢を表示し、選択に応じてDCD更新を実行する |
| 81 | 翻訳・多言語対応 | 補助機能 | ダイアログメッセージの翻訳にtranslate機能を使用する |

## 画面種別

LSPダイアログ（`window/showMessageRequest` によるエラーメッセージ + アクションボタン）

## URL/ルーティング

LSPメソッド名: `window/showMessageRequest`（サーバーからクライアントへの要求）

## 入出力項目

### 入力（内部パラメータ）

| 項目名 | 型 | 必須 | 説明 |
|--------|------|------|------|
| DCDComponent.latestKnownVersion | int[] | はい | 期待されるDCDバージョン |
| serverInstalledVersion | string | はい | 現在インストールされているDCDバージョン（未インストールの場合は "none"） |
| isDCDFromSource | bool | はい | ソースからビルドするか否か |

### 出力（ユーザー選択結果）

| 項目名 | 型 | 説明 |
|--------|------|------|
| res | string | ユーザーが選択したアクション文字列（またはnull/空文字列でキャンセル） |

## 表示項目

### ダイアログ内容

| 項目 | 内容 | 説明 |
|------|------|------|
| メッセージ種別 | MessageType.error | エラーレベルのメッセージ |
| メッセージ本文 | "DCD is outdated. (target={期待バージョン}, installed={現在バージョン})" | DCD更新を促すメッセージ |
| ボタン1 | "Compile DCD" または "Download DCD" | ソースビルドかダウンロードかで変わる |
| ボタン2 | "Continue anyway" | DCD更新を無視（DCDが存在する場合のみ表示） |

## イベント仕様

### 1-ダイアログ表示

1. `doGlobalStartup` 内でDCDの `isOutdated` チェックを実行
2. インストール済みバージョンを取得（未インストールなら "none"）
3. `translate!"d.served.outdatedDCD"` でメッセージを生成
4. `isDCDFromSource` に基づきボタンテキストを決定:
   - `true`: `translate!"d.ext.compileProgram"("DCD")` → "Compile DCD"
   - `false`: `translate!"d.ext.downloadProgram"("DCD")` → "Download DCD"
5. DCDComponentが存在しない場合、"Continue anyway" ボタンは非表示（選択肢から除外）
6. `rpc.window.requestMessage(MessageType.error, message, actions)` でダイアログを表示

### 2-コンパイル/ダウンロード選択

1. ユーザーが "Compile DCD" または "Download DCD" を選択
2. `spawnFiber("updateDCD", (&updateDCD).toDelegate)` でDCD更新処理をバックグラウンドで開始
3. No.39 DCD更新（served/updateDCD）に遷移

### 3-Continue anyway選択

1. ユーザーが "Continue anyway" を選択
2. `backend.get!DCDComponent.ignoreOutdatedForSession()` でセッション中の古さチェックを無効化
3. `dcdUpdating = false` を設定
4. 全バックエンドインスタンスに対して、保留中でないDCDサーバーを起動

### 4-キャンセル（ダイアログを閉じる）

1. ユーザーがダイアログを閉じた場合（resがnullまたは一致しない場合）
2. DCD更新も無視も行われず、`dcdUpdating = true` のまま保持される
3. コード補完は利用不可の状態が続く

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

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

本画面ではデータベースへのアクセスは発生しない。

| 操作（イベント） | 対象データ | 操作種別 | 概要 |
|----------------|-----------|---------|------|
| Continue anyway選択 | dcdUpdating（フラグ） | 更新 | falseに設定 |
| Continue anyway選択 | DCDComponent | 設定 | ignoreOutdatedForSession() |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|------------|------|--------------|----------|
| d.served.outdatedDCD | error | "DCD is outdated. (target={0}, installed={1})" | 常に表示 |
| d.ext.compileProgram | アクションボタン | "Compile DCD" | isDCDFromSource=true |
| d.ext.downloadProgram | アクションボタン | "Download DCD" | isDCDFromSource=false |
| d.served.ignoreDCDUpdate | アクションボタン | "Continue anyway" | DCDComponentが存在する場合 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| DCDComponent未インストール | "Continue anyway" ボタンが非表示になる（actions配列の長さを減らす） |
| ダイアログ応答がタイムアウト | resがnullとなり、何も実行されない |

## 備考

- `dcdUpdating` フラグが `true` の間、DCDサーバーの起動は抑制される（`wantsDCDServer` で確認される）
- ダイアログは `spawnFiber` で非同期に実行されるため、他のサーバー処理をブロックしない
- `aggressiveUpdate` が `true` の場合は本ダイアログを経由せず直接 `updateDCD` が呼ばれる
- `isDCDFromSource` はプラットフォームやDCDの取得方法に依存するグローバル変数

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.d | `source/served/types.d` | `Configuration.D.aggressiveUpdate`（107行目）のデフォルト値（false）を確認 |

**読解のコツ**: `rpc.window.requestMessage` は LSPの `window/showMessageRequest` に対応し、クライアントにダイアログを表示してユーザーの選択を待機する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | extension.d | `source/served/extension.d` | DCD更新判定ブロック（426行目〜473行目）内の `spawnFiber("Request DCD update", ...)` （442行目〜）がダイアログ表示のエントリーポイント |

**主要処理フロー**:
1. **426行目**: `!backend.has!DCDComponent || backend.get!DCDComponent.isOutdated` で判定
2. **428-429行目**: インストール済みバージョン取得
3. **431-432行目**: `translate!"d.served.outdatedDCD"` でメッセージ生成
4. **444-448行目**: ボタンテキスト決定（isDCDFromSourceで分岐）
5. **450-452行目**: DCDComponent未存在時にactionsを縮小
6. **454行目**: `rpc.window.requestMessage(MessageType.error, ...)` でダイアログ表示
7. **456-457行目**: コンパイル/ダウンロード選択時 → `updateDCD` をspawnFiber
8. **458-469行目**: Continue anyway選択時 → ignoreOutdatedForSession() + DCDサーバー起動

#### Step 3: 翻訳メッセージの解決を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | translate.d | `source/served/utils/translate.d` | `translate!` テンプレート関数（41行目〜）の仕組み |
| 3-2 | en.txt | `views/en.txt` | 174行目: d.served.outdatedDCD, 101行目: d.ext.compileProgram, 102行目: d.ext.downloadProgram, 175行目: d.served.ignoreDCDUpdate |

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

```
doGlobalStartup(config)  [363行目]
    │
    └─ [DCD古い判定]  [426行目]
           │
           ├─ aggressiveUpdate=true
           │      └─ spawnFiber("updateDCD")  [439行目]
           │
           └─ aggressiveUpdate=false
                  └─ spawnFiber("Request DCD update")  [442行目]
                         │
                         ├─ translate!"d.served.outdatedDCD"  [431行目]
                         ├─ translate!"d.ext.compileProgram" / "d.ext.downloadProgram"  [445-447行目]
                         ├─ translate!"d.served.ignoreDCDUpdate"  [448行目]
                         │
                         └─ rpc.window.requestMessage(error, msg, actions)  [454行目]
                                │
                                ├─ [Compile/Download] → spawnFiber("updateDCD")  [457行目]
                                │
                                └─ [Continue anyway]
                                       ├─ ignoreOutdatedForSession()  [462行目]
                                       ├─ dcdUpdating = false  [463行目]
                                       └─ startDCDServer(各インスタンス)  [467行目]
```

### データフロー図

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

DCDComponent.isOutdated ───▶ doGlobalStartup()              ダイアログ表示
DCDComponent.latestKnownVersion     │                        （window/showMessageRequest）
isDCDFromSource                     ├─ メッセージ生成              │
config.d.aggressiveUpdate           └─ ボタン構築             ユーザー選択
                                                                  │
                                                            ├─ updateDCD起動
                                                            ├─ ignoreOutdated + DCD起動
                                                            └─ 何もしない（キャンセル）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.d | `source/served/extension.d` | ソース | DCD更新確認ダイアログの実装（doGlobalStartup内426-473行目） |
| dcd_update.d | `source/served/commands/dcd_update.d` | ソース | updateDCD関数（DCD更新処理本体） |
| translate.d | `source/served/utils/translate.d` | ソース | 翻訳機能 |
| en.txt | `views/en.txt` | リソース | ダイアログメッセージとボタンテキストの翻訳 |
| types.d | `source/served/types.d` | ソース | Configuration.D.aggressiveUpdate設定 |
