# 画面設計書 67-プロジェクト強制読み込み（served/forceLoadProjects）

## 概要

本ドキュメントは、serve-d LSPサーバーのカスタムリクエスト `served/forceLoadProjects` の画面設計書である。指定されたパスのプロジェクトを、manyProjectsThreshold制限を無視して強制的に読み込む機能を提供する。

### 本画面の処理概要

本リクエストは、通常はサブプロジェクト数の閾値超過によりスキップされたプロジェクトを、強制的にロードする機能を提供する。

**業務上の目的・背景**：serve-dは `manyProjectsThreshold` 設定により、サブプロジェクト数が閾値を超えた場合にプロジェクトの自動読み込みをスキップする。しかし、ユーザーが特定のプロジェクトを必要とする場合に、この制限を無視して強制的にプロジェクトを読み込む手段が必要である。`coded/skippedLoads` 通知でスキップされたプロジェクトの情報がクライアントに通知された後、ユーザーが明示的にこのリクエストを送信することでプロジェクトのロードを実行する。

**画面へのアクセス方法**：LSPクライアントから `served/forceLoadProjects` カスタムリクエストを送信する。通常は、スキップ済みプロジェクト通知を受けたクライアントのUIから呼び出される。

**主要な操作・処理内容**：
1. クライアントからプロジェクトルートパスの配列を受信する
2. 各パスについてワークスペースを特定する
3. dubレシピの存在確認を行い、DUBプロジェクトかfsworkspaceかを判定する
4. バックエンドにインスタンスを追加する
5. プロジェクトの初期化処理（DUB初期化、依存関係解決等）を実行する
6. DCDサーバーを起動する
7. 各パスの読み込み成否をbool配列で返却する

**画面遷移**：
- 遷移元：スキップ済みプロジェクト通知（coded/skippedLoads）のUI
- 遷移先：DUB依存関係ダウンロード確認ダイアログ（依存関係不足時）

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

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | プロジェクト強制ロード (served/forceLoadProjects) | 主機能 | 指定パスのプロジェクトをmanyProjectsの制限に関わらず強制的にロードする |

## 画面種別

カスタムLSPリクエスト（操作実行型）

## URL/ルーティング

LSPカスタムメソッド: `served/forceLoadProjects`

## 入出力項目

### リクエストパラメータ

| 項目名 | 型 | 必須 | 説明 |
|--------|------|------|------|
| rootPaths | string[] | はい | 強制読み込みするプロジェクトのルートパスの配列 |

### レスポンス

| 項目名 | 型 | 説明 |
|--------|------|------|
| (戻り値) | bool[] | 各パスの読み込み成否。成功: true、失敗: false |

## 表示項目

クライアント側でプロジェクト読み込みの進捗と結果を表示するUIに使用される。進捗通知（ProgressType.workspaceStartup, completionStartup）がクライアントに送信される。

## イベント仕様

### 1-プロジェクト強制読み込みリクエスト受信

1. クライアントから `served/forceLoadProjects` リクエストを受信する
2. 各rootPathについて以下を実行：
   a. `rootPath.uriFromFile` でURIに変換する
   b. `workspace(rootUri, false)` でワークスペースを特定する
   c. ワークスペースが見つからない場合は `success = false` を設定しスキップする
   d. `dubRecipeExists(rootPath, true)` でdub.json/dub.sdlの存在を確認する
   e. `RootSuggestion` を構築する
   f. 進捗レポート `ProgressType.workspaceStartup` を送信する
   g. バックエンド設定（DCD, DMDパス等）を構築し、`backend.addInstance(rootPath, config)` でインスタンスを追加する
   h. `emitExtensionEvent!onProjectAvailable` でプロジェクト利用可能イベントを発行する
   i. LazyInstanceの場合は遅延読み込みコールバックを設定する。通常インスタンスの場合は `delayedProjectActivation` を直ちに実行する
   j. `success = true` を設定する
3. 全インスタンスに対してDCDサーバーを起動する：
   a. 進捗レポート `ProgressType.completionStartup` を送信する
   b. `lazyStartDCDServer` でDCDサーバーを起動する
4. 各パスの `success` をbool配列として返却する

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| プロジェクト強制読み込み | backend.instances（インメモリ） | INSERT | 新しいプロジェクトインスタンスの追加 |
| DUB初期化 | ファイルシステム | SELECT/INSERT | dub.jsonの読み込みと依存関係の解決 |
| DCDサーバー起動 | プロセス | INSERT | DCDサーバープロセスの起動 |

## メッセージ仕様

| メッセージID | 種別 | 表示条件 | メッセージ内容 |
|-------------|------|---------|--------------|
| なし | エラー | ワークスペース不明時 | "Trying to do startup on unknown workspace {rootUri}?"（ログ出力のみ） |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| 指定パスのワークスペースが見つからない | error出力し、該当パスの結果をfalseに設定 |
| DUB初期化失敗 | fsworkspaceにフォールバック（delayedProjectActivation内） |
| DCDサーバー起動失敗 | エラー通知がクライアントに送信される |

## 備考

- `skipManyProjectsAction = true` パラメータにより、delayedProjectActivation内のサブプロジェクト数チェックがスキップされる
- LazyInstanceの場合、実際のプロジェクト初期化はインスタンスに初めてアクセスがあった時点で遅延実行される
- activeInstanceが未設定の場合、最初に追加されたインスタンスがactiveInstanceとして設定される
- バックエンド設定にはワークスペースのconfig.dcdClientPath, dcdServerPath, d.dmdPath が含まれる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | extension.d | `source/served/extension.d` | RootSuggestion構造体、Root内部構造体（行636-641） |

**読解のコツ**: Root構造体はforceLoadProjects内部でのみ使用されるローカル構造体。uri, instance, successの3フィールドを持つ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | extension.d | `source/served/extension.d` | `forceLoadProjects` 関数（行633-721）がエントリーポイント |

**主要処理フロー**:
1. **行633-634**: `@protocolMethod("served/forceLoadProjects")` で定義。パラメータは `string[] rootPaths`
2. **行636-641**: 内部Root構造体の定義
3. **行646-701**: 各rootPathに対するインスタンス追加と初期化のループ
4. **行650-655**: ワークスペース特定と不明時のエラー処理
5. **行659-662**: dubレシピ存在確認とRootSuggestion構築
6. **行667-678**: バックエンド設定構築とインスタンス追加
7. **行686-698**: LazyInstanceの遅延読み込み設定または即時プロジェクト初期化
8. **行704-718**: DCDサーバー起動ループ
9. **行720**: `roots.map!"a.success".array` で結果配列を返却

#### Step 3: プロジェクト初期化処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | `delayedProjectActivation` 関数（行727以降） |

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

```
served/forceLoadProjects リクエスト
    |
    +-- forceLoadProjects(string[] rootPaths)        [extension.d:634]
           |
           +-- workspace(rootUri, false)              [ワークスペース特定]
           |
           +-- dubRecipeExists(rootPath, true)        [dubレシピ存在確認]
           |
           +-- reportProgress()                       [進捗通知]
           |
           +-- backend.addInstance()                  [インスタンス追加]
           |
           +-- emitExtensionEvent!onProjectAvailable  [イベント発行]
           |
           +-- delayedProjectActivation()             [プロジェクト初期化]
           |      +-- DUB初期化 / fsworkspace初期化
           |      +-- 依存関係解決
           |
           +-- lazyStartDCDServer()                   [DCDサーバー起動]
```

### データフロー図

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

rootPaths(string[]) ------> forceLoadProjects()            --> bool[] (成否配列)
                                |
                                +-- ワークスペース特定
                                +-- dubレシピ確認
                                +-- インスタンス追加
                                +-- プロジェクト初期化
                                +-- DCDサーバー起動
                                +-- 進捗通知 --> クライアント
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.d | `source/served/extension.d` | ソース | forceLoadProjects関数の実装、delayedProjectActivation |
| types.d | `source/served/types.d` | ソース | ManyProjectsAction等の型定義 |
