# 画面設計書 6-サブプロジェクト読み込み確認ダイアログ

## 概要

本ドキュメントは、serve-d LSPサーバーにおけるサブプロジェクト読み込み確認ダイアログの画面設計書である。`manyProjectsThreshold` を超えるサブプロジェクトがある場合に、Load/Skipの選択肢を表示する。

### 本画面の処理概要

**業務上の目的・背景**：大規模なD言語プロジェクトでは、ワークスペース内に多数のサブプロジェクト（それぞれが独自のdub.json/dub.sdlを持つ）が存在する場合がある。全てのサブプロジェクトを読み込むとメモリ使用量と初期化時間が大幅に増加するため、閾値を設けてユーザーに読み込み可否を確認する仕組みが必要である。本ダイアログは、過剰なプロジェクト読み込みを防ぎ、パフォーマンスとユーザビリティのバランスを取るために存在する。

**画面へのアクセス方法**：No.3 ワークスペーススタートアップの `delayedProjectActivation` 関数内で、`totalLoadedProjects` が `manyProjectsThreshold`（デフォルト: 6）を超え、かつ `manyProjectsAction` が `ask` の場合に自動表示される。

**主要な操作・処理内容**：
1. 読み込み済みプロジェクト数が閾値を超えた場合に警告ダイアログを表示
2. ユーザーに Load（読み込み続行）/ Skip（読み込みスキップ）の選択肢を提示
3. Skip選択時はインスタンスを削除し、`coded/skippedLoads` 通知をクライアントに送信

**画面遷移**：
- 遷移元：No.3 ワークスペーススタートアップ（delayedProjectActivation内）
- 遷移先：No.67 プロジェクト強制読み込み（served/forceLoadProjects）（スキップ後にクライアントからの再読み込み要求）

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

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | プロジェクト強制ロード (served/forceLoadProjects) | 遷移先機能 | Loadを選択した場合にプロジェクトの読み込みが続行される |
| 81 | 翻訳・多言語対応 | 補助機能 | ダイアログメッセージ（Load/Skip）の翻訳にtranslate機能を使用する |

## 画面種別

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

## URL/ルーティング

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

## 入出力項目

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

| 項目名 | 型 | 必須 | 説明 |
|--------|------|------|------|
| root.dir | string | はい | 読み込み対象のサブプロジェクトパス |
| totalLoadedProjects | int | はい | 現在までに読み込まれたプロジェクト数 |
| config.d.manyProjectsThreshold | int | はい | プロジェクト読み込み閾値（デフォルト: 6） |
| config.d.manyProjectsAction | ManyProjectsAction | はい | 閾値超過時の動作設定（ask/load/skip） |

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

| 項目名 | 型 | 説明 |
|--------|------|------|
| res | string | ユーザーが選択したアクション文字列 |

## 表示項目

### ダイアログ内容

| 項目 | 内容 | 説明 |
|------|------|------|
| メッセージ種別 | MessageType.warning | 警告レベルのメッセージ |
| メッセージ本文 | "There are too many subprojects in this project according to d.manyProjectsThreshold\n\nDo you want to load `{パス}`?" | 読み込み確認メッセージ |
| ボタン1 | "Load" | 読み込みを続行 |
| ボタン2 | "Skip" | 読み込みをスキップ |

## イベント仕様

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

1. `delayedProjectActivation` 内で `totalLoadedProjects` を `atomicOp!"+="`でインクリメント
2. `manyProjectsThreshold > 0` かつ `numLoaded > manyThreshold` の場合に判定ブロックに入る
3. `manyProjectsAction` が `ask` の場合:
   - `bundleAskLoads` が `true` の場合: askをskipとして扱い、`skippedRoots` に追加
   - `bundleAskLoads` が `false` の場合: ダイアログを表示
4. `rpc.window.requestMessage(MessageType.warning, msg, [loadButton, skipButton])` でダイアログ表示

### 2-Load選択

1. ユーザーが "Load" を選択
2. ダイアログ処理を抜け、通常のプロジェクト初期化が続行される

### 3-Skip選択（またはLoad以外を選択）

1. `backend.removeInstance(workspaceRoot)` でインスタンスを削除
2. "skipping load of this instance" メッセージで例外をスロー
3. プロジェクトの初期化は中断される

### 4-manyProjectsAction=load の場合

1. ダイアログを表示せず、そのまま読み込みを続行する

### 5-manyProjectsAction=skip の場合

1. ダイアログを表示せず、直接インスタンスを削除してスキップする

### 6-bundleAskLoads=true の場合

1. askをskipとして扱い、`skippedRoots` に追加
2. `notifySkippedRoots()` を呼び出し、500ms後に `coded/skippedLoads` 通知をクライアントに送信

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

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

| 操作（イベント） | 対象データ | 操作種別 | 概要 |
|----------------|-----------|---------|------|
| Skip選択 | backend.instances | 削除 | ワークスペースインスタンスを削除 |
| Skip選択 | skippedRoots | 追加 | スキップされたルートパスを記録 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|------------|------|--------------|----------|
| d.served.tooManySubprojects.path | warning | "There are too many subprojects in this project according to d.manyProjectsThreshold\n\nDo you want to load `{0}`?" | manyProjectsAction=ask時 |
| d.served.tooManySubprojects.load | アクションボタン | "Load" | 常に表示 |
| d.served.tooManySubprojects.skip | アクションボタン | "Skip" | 常に表示 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| 無効なmanyProjectsAction値 | エラーログ出力後、skipとして扱う |
| Skip選択時 | "skipping load of this instance" 例外をスロー（呼び出し元で処理） |

## 備考

- `manyProjectsThreshold` のデフォルト値は 6
- `manyProjectsAction` のデフォルト値は `ask`
- `totalLoadedProjects` はアトミック変数であり、並行処理に対応
- `bundleAskLoads` が `true` の場合は個別ダイアログを表示せず、まとめて通知する
- `notifySkippedRoots()` は500msのデバウンスタイマーで複数のスキップ通知をまとめる
- スキップされたプロジェクトは後から `served/forceLoadProjects` で強制読み込み可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.d | `source/served/types.d` | `ManyProjectsAction` 列挙型（57-62行目）: ask, skip, load |
| 1-2 | types.d | `source/served/types.d` | `Configuration.D.manyProjectsAction`（113行目）デフォルトask、`manyProjectsThreshold`（114行目）デフォルト6 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | extension.d | `source/served/extension.d` | `delayedProjectActivation` 関数内のmanyProjects判定ブロック（741行目〜773行目） |

**主要処理フロー**:
1. **739行目**: `atomicOp!"+="(totalLoadedProjects, 1)` でプロジェクト数インクリメント
2. **743-745行目**: `manyProjectsAction` と `manyProjectsThreshold` の取得、閾値チェック
3. **747行目**: `manyProjectsAction` でswitch分岐
4. **749-762行目**: `ask` の場合 - bundleAskLoads判定 + ダイアログ表示
5. **756-760行目**: ダイアログ表示と選択処理
6. **764行目**: `load` の場合 - そのまま続行
7. **769-771行目**: `skip` の場合 - インスタンス削除と例外スロー

#### Step 3: スキップ通知を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | `notifySkippedRoots` 関数（914行目〜921行目）- 500msデバウンスでcoded/skippedLoads通知 |

#### Step 4: 翻訳メッセージを確認する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | en.txt | `views/en.txt` | 177行目: d.served.tooManySubprojects.path, 178行目: d.served.tooManySubprojects.load, 179行目: d.served.tooManySubprojects.skip |

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

```
delayedProjectActivation(...)  [727行目]
    │
    ├─ atomicOp!"+="(totalLoadedProjects, 1)  [739行目]
    │
    └─ [閾値超過判定]  [743-745行目]
           │
           └─ switch(manyProjectsAction)
                  │
                  ├─ ask
                  │      ├─ bundleAskLoads=true
                  │      │      ├─ skippedRoots ~= workspaceRoot  [752行目]
                  │      │      └─ notifySkippedRoots()  [753行目]
                  │      │             └─ rpc.notifyMethod("coded/skippedLoads")  [919行目]
                  │      │
                  │      └─ bundleAskLoads=false
                  │             └─ rpc.window.requestMessage(warning, msg, [Load, Skip])
                  │                    ├─ [Load] → 続行
                  │                    └─ [Skip] → removeInstance + throw
                  │
                  ├─ load → 続行
                  │
                  └─ skip → backend.removeInstance() + throw
```

### データフロー図

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

totalLoadedProjects ─────▶ delayedProjectActivation()     ダイアログ表示
manyProjectsThreshold          │                            （warning）
manyProjectsAction             ├─ 閾値チェック                     │
root.dir                       └─ ダイアログ/自動判定      ├─ 読み込み続行
                                                            ├─ インスタンス削除
                                                            └─ coded/skippedLoads通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.d | `source/served/extension.d` | ソース | delayedProjectActivation内のmanyProjects判定、notifySkippedRoots関数 |
| types.d | `source/served/types.d` | ソース | ManyProjectsAction列挙型、manyProjectsThreshold設定 |
| translate.d | `source/served/utils/translate.d` | ソース | 翻訳機能 |
| en.txt | `views/en.txt` | リソース | ダイアログメッセージ翻訳 |
