# 画面設計書 3-ワークスペーススタートアップ

## 概要

本ドキュメントは、serve-d LSPサーバーにおけるワークスペーススタートアップ処理の画面設計書である。各ワークスペースルートに対してdubプロジェクトまたはfsworkspaceの初期化を行い、DCDサーバーの起動まで実行する。

### 本画面の処理概要

**業務上の目的・背景**：エディタで開かれたワークスペース（プロジェクトフォルダ）ごとに、D言語の開発環境を正しく構成する必要がある。ワークスペーススタートアップは、各プロジェクトルートを検出し、DUBプロジェクトまたはファイルシステムベースのワークスペースとして初期化し、コード補完に必要なDCDサーバーを起動する。サブプロジェクトの自動検出や閾値を超えた場合のユーザー確認も本処理の範囲である。

**画面へのアクセス方法**：`changedConfig` -> `ensureStartedUp` の後、ワークスペースが未初期化の場合に `doStartup` が自動的に呼び出される。また、`changedConfig` 関数の95-98行目で `proj.initialized` が `false` の場合に直接呼び出される。

**主要な操作・処理内容**：
1. ワークスペースのプロジェクトルート候補を検出する（`rootsForProject`）
2. 各ルートに対してワークスペースインスタンスを作成・登録する
3. DUBプロジェクトまたはfsworkspaceの初期化を行う（`delayedProjectActivation`）
4. DCDサーバーを各ルートに対して起動する（`lazyStartDCDServer`）
5. 各段階でプログレス通知をクライアントに送信する

**画面遷移**：
- 遷移元：No.2 グローバルスタートアップ（ensureStartedUp経由）、No.7 設定変更通知（ワークスペース未初期化時）
- 遷移先：No.5 DUB依存関係ダウンロード確認ダイアログ、No.6 サブプロジェクト読み込み確認ダイアログ、No.9 DCD起動失敗通知、No.10 dubスタートアップ失敗通知

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

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | 設定変更処理 | 補助機能 | 設定変更時にワークスペースが未初期化の場合にdoStartupが呼び出される |
| 66 | バックグラウンドインデックス | 遷移先機能 | DCDサーバー起動後にバックグラウンドインデックスを開始する |
| 82 | 進捗レポート | 補助機能 | ワークスペーススタートアップの各段階の進捗をクライアントに通知する |

## 画面種別

サーバー内部処理（バックグラウンド初期化 + プログレス通知 + ダイアログ遷移）

## URL/ルーティング

明示的なLSPメソッドではない。内部関数 `doStartup` で実装される。

## 入出力項目

### 入力

| 項目名 | 型 | 必須 | 説明 |
|--------|------|------|------|
| workspaceUri | string | はい | ワークスペースのURI |
| userConfig | UserConfiguration | はい | ユーザー設定 |

### 出力（クライアントへの通知）

| 項目名 | 種別 | 説明 |
|--------|------|------|
| workspaceStartup進捗 | ログ出力 | 各ルートの初期化進捗 |
| dubReload進捗 | ログ出力 | DUB読み込み進捗 |
| completionStartup進捗 | ログ出力 | DCD補完サーバー起動進捗 |
| importUpgrades進捗 | ログ出力 | 依存関係アップグレード進捗 |
| coded/initDubTree | 通知 | DUBプロジェクト初回読み込み時のツリー初期化通知 |

## 表示項目

### ルート候補検出結果

| 項目 | 説明 |
|------|------|
| root.dir | プロジェクトルートの絶対パス |
| root.useDub | DUBレシピが存在するかどうか |

## イベント仕様

### 1-ルート候補検出

1. `rootsForProject` でワークスペースルートからプロジェクト候補を検出
2. `config.d.scanAllFolders` が `true` の場合、再帰的にdub.json/dub.sdlを探索
3. `config.d.disabledRootGlobs` にマッチするパスは除外
4. `config.d.extraRoots` に指定されたパスを追加

### 2-インスタンス登録

1. 各ルートに対してバックエンドインスタンスを作成（`backend.addInstance`）
2. DCD client/server パスとDMDパスの設定を適用
3. `onProjectAvailable` イベントを発行
4. `LazyInstance` の場合は遅延ロードコールバックを設定

### 3-プロジェクト初期化（delayedProjectActivation）

1. `manyProjectsThreshold` を超えた場合、ユーザーにLoad/Skipの確認（No.6へ）
2. DUBプロジェクトの場合:
   - `backend.attachEager(instance, "dub")` でDUBコンポーネントをアタッチ
   - `dub.validateConfiguration()` で設定を検証
   - 依存関係不足時にダウンロード確認ダイアログ（No.5へ）
3. DUBの初期化失敗時またはDUB不使用時:
   - fsworkspaceにフォールバック（`proj.startupError` でエラー記録）
4. DUBプロジェクト初回読み込み時: `coded/initDubTree` 通知を送信

### 4-DCDサーバー起動

1. 各ルートに対して `lazyStartDCDServer` を呼び出し
2. DCDの起動に失敗した場合はエラーメッセージを表示（No.9へ）
3. 起動成功時に `backgroundIndex()` を呼び出し

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

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

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

| 操作（イベント） | 対象データ | 操作種別 | 概要 |
|----------------|-----------|---------|------|
| インスタンス登録 | backend.instances | 追加 | ワークスペースインスタンスをバックエンドに追加 |
| DUB初期化 | DubComponent | アタッチ | DUBコンポーネントをインスタンスにアタッチ |
| fsworkspaceフォールバック | FSWorkspaceComponent | アタッチ | ファイルシステムワークスペースをインスタンスにアタッチ |
| DCDサーバー起動 | DCDComponent | 起動 | DCDサーバープロセスを起動 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|------------|------|--------------|----------|
| d.ext.dubFail | error | "Could not initialize dub for {0}. Falling back to limited functionality!\n\n{1}" | DUB初期化失敗時 |
| d.ext.fsworkspaceFail | error | "Could not initialize fsworkspace for {0}. See console for details!" | fsworkspace初期化失敗時 |
| d.ext.dcdFail | error | "Could not initialize DCD for {0}.{1}" | DCD起動失敗時 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| 未知のワークスペースURI | エラーログ出力し、処理を中断する |
| DUB初期化失敗 | fsworkspaceにフォールバックし、`startupError` にエラーを記録 |
| fsworkspace初期化失敗 | `startupError` にエラーを記録 |
| DCDサーバー起動失敗 | `showErrorMessage` でクライアントにエラー通知（No.9） |
| manyProjectsThresholdでSkip選択 | `backend.removeInstance` でインスタンスを削除し例外をスロー |

## 備考

- `LazyWorkspaceD.LazyInstance` を使用することで、必要になるまでコンポーネントの実際の初期化を遅延できる
- `totalLoadedProjects` はアトミック操作で管理され、スレッドセーフにプロジェクト数をカウントする
- `bundleAskLoads` が `true` の場合、"ask" アクションは "skip" として扱われ、後で `coded/skippedLoads` 通知がまとめて送信される
- DUBプロジェクトの初回読み込み時のみ `coded/initDubTree` が送信される（`loadedDub` static変数で制御）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | extension.d | `source/served/extension.d` | `RootSuggestion` 構造体（487-493行目）- プロジェクトルート候補の表現 |
| 1-2 | types.d | `source/served/types.d` | `Workspace` 構造体（270行目）、`ManyProjectsAction`（57行目）、`DubUpgradeAction`（64行目） |
| 1-3 | types.d | `source/served/types.d` | `Configuration.D` の `scanAllFolders`, `manyProjectsThreshold`, `manyProjectsAction` フィールド |

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

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

**主要処理フロー**:
1. **558行目**: `ensureStartedUp` でグローバル初期化を保証
2. **577-578行目**: `rootsForProject` でプロジェクトルート候補を取得
3. **580-617行目**: 各ルートのインスタンス登録とdelayedProjectActivation
4. **619-631行目**: DCDサーバー起動ループ

#### Step 3: プロジェクトルート検出を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | `rootsForProject` 関数（514行目〜554行目）- dubレシピファイルの再帰探索 |
| 3-2 | extension.d | `source/served/extension.d` | `dubRecipeExists` 関数（495行目〜512行目）- dub.json/dub.sdl存在チェック |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | extension.d | `source/served/extension.d` | `delayedProjectActivation` 関数（727行目〜912行目）- manyProjects判定、DUB初期化、fsworkspaceフォールバック |

**主要処理フロー**:
- **741-773行目**: manyProjectsThreshold判定とLoad/Skip選択
- **787-876行目**: DUBプロジェクト初期化（依存関係チェック含む）
- **878-898行目**: fsworkspaceフォールバック
- **901行目**: `didLoadDubProject()` 呼び出し（DUBツリー初期化通知）

#### Step 5: DCDサーバー起動を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | extension.d | `source/served/extension.d` | `startDCDServer` 関数（999行目〜1026行目）- DCDサーバー起動とインポートパス設定 |
| 5-2 | extension.d | `source/served/extension.d` | `lazyStartDCDServer` 関数（1028行目〜1055行目）- 遅延DCDサーバー起動 |

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

```
doStartup(workspaceUri, userConfig)  [556行目]
    │
    ├─ ensureStartedUp(userConfig)  [558行目]
    │
    ├─ rootsForProject(...)  [577行目]
    │      └─ dubRecipeExists(root)  [495行目]
    │
    ├─ [ルートごとのループ]
    │      ├─ reportProgress(workspaceStartup)  [582行目]
    │      ├─ backend.addInstance(workspaceRoot, config)  [597行目]
    │      ├─ emitExtensionEvent!onProjectAvailable  [602行目]
    │      └─ delayedProjectActivation(...)  [615行目]
    │             ├─ manyProjectsAction判定  [741-773行目]
    │             ├─ backend.attachEager(instance, "dub")  [796行目]
    │             │      ├─ dub.validateConfiguration()  [803行目]
    │             │      └─ dub.missingDependencies → ダイアログ  [806-856行目]
    │             ├─ [失敗時] fsworkspace初期化  [885-898行目]
    │             ├─ didLoadDubProject()  [901行目]
    │             │      └─ rpc.notifyMethod("coded/initDubTree")  [929行目]
    │             └─ emitExtensionEvent!onAddedProject  [908行目]
    │
    └─ [ルートごとのDCD起動ループ]
           └─ lazyStartDCDServer(instance, uri)  [627行目]
                  └─ startDCDServer(instance, uri)  [999行目]
                         ├─ dcd.startServer(stdlibPath)  [1012行目]
                         ├─ dcd.refreshImports()  [1014行目]
                         └─ backgroundIndex()  [1015行目]
```

### データフロー図

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

workspaceUri ──────▶ doStartup() ──────────────────────▶ 進捗通知（workspaceStartup）
userConfig             │                                    進捗通知（dubReload）
                       ├─ rootsForProject()                 進捗通知（completionStartup）
                       │      └─ RootSuggestion[]           coded/initDubTree通知
                       ├─ backend.addInstance()              エラー通知（失敗時）
                       ├─ delayedProjectActivation()
                       │      ├─ DUB初期化
                       │      └─ fsworkspaceフォールバック
                       └─ lazyStartDCDServer()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.d | `source/served/extension.d` | ソース | doStartup, delayedProjectActivation, startDCDServer, lazyStartDCDServer, rootsForProject等の実装 |
| types.d | `source/served/types.d` | ソース | Workspace構造体、Configuration構造体、ManyProjectsAction, DubUpgradeAction列挙型 |
| progress.d | `source/served/utils/progress.d` | ソース | ProgressType列挙型（workspaceStartup, dubReload, completionStartup, importUpgrades） |
| translate.d | `source/served/utils/translate.d` | ソース | 翻訳機能 |
| en.txt | `views/en.txt` | リソース | エラーメッセージ翻訳（dubFail, fsworkspaceFail, dcdFail等） |
