# 機能設計書 4-ワークスペースフォルダ変更

## 概要

本ドキュメントは、serve-d LSPサーバーにおけるワークスペースフォルダ変更機能の設計を記述する。ワークスペースフォルダの追加・削除通知を処理し、対応するプロジェクトインスタンスを起動・停止する。

### 本機能の処理概要

LSPプロトコルの `workspace/didChangeWorkspaceFolders` 通知を処理する。クライアント（エディタ）がワークスペースにフォルダを追加・削除した際に、serve-dの内部ワークスペース管理を同期させる。削除されたフォルダのバックエンドインスタンスを停止し、追加されたフォルダに対して新たなプロジェクトインスタンスを起動する。

**業務上の目的・背景**：VSCode等のマルチルートワークスペース機能に対応するため、エディタのワークスペース構成変更をserve-dがリアルタイムに追従する必要がある。フォルダの追加時には新たなDUBプロジェクトの解析やDCDサーバーの起動が必要であり、削除時にはリソースの適切な解放が必要である。

**機能の利用シーン**：ユーザーがVSCodeでワークスペースにフォルダを追加・削除した際に自動的に通知される。

**主要な処理内容**：
1. 削除されたフォルダのワークスペースインスタンスをremoveWorkspaceで停止
2. 追加されたフォルダをworkspaces配列に追加
3. 追加フォルダの設定同期（syncConfiguration）を実行
4. 追加フォルダに対してdoStartupを実行（プロジェクト初期化）

**関連システム・外部連携**：LSPクライアント。バックエンドのWorkspaceD（DUB, DCD, FSWorkspace等のコンポーネント管理）。

**権限による制御**：特に権限制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | LSPサーバー初期化（initialize） | 補助機能 | 初期化時にワークスペースフォルダを取得・設定する処理 |

## 機能種別

データ連携（ワークスペース管理・プロジェクトライフサイクル制御）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| params | DidChangeWorkspaceFoldersParams | Yes | ワークスペースフォルダ変更イベント | LSPプロトコル仕様に準拠 |
| params.event.added | WorkspaceFolder[] | Yes | 追加されたワークスペースフォルダ一覧 | なし |
| params.event.removed | WorkspaceFolder[] | Yes | 削除されたワークスペースフォルダ一覧 | なし |

### 入力データソース

LSPクライアントからのJSON-RPC通知（メソッド名: "workspace/didChangeWorkspaceFolders"）

## 出力仕様

### 出力データ

通知処理のため、レスポンスは返却しない。

### 出力先

内部状態（workspaces配列、バックエンドインスタンス）の更新。

## 処理フロー

### 処理シーケンス

```
1. 削除フォルダの処理
   └─ params.event.removedの各フォルダに対してremoveWorkspace(uri)を呼び出し
      └─ バックエンドからインスタンスを削除
      └─ workspace.disabledをtrueに設定
2. 追加フォルダの処理
   └─ params.event.addedの各フォルダに対して:
      a. workspaces配列にWorkspace(toAdd)を追加
      b. syncConfiguration(toAdd.uri, i, length, true)で設定同期
      c. doStartup(toAdd.uri, anyConfig)でプロジェクト初期化
```

### フローチャート

```mermaid
flowchart TD
    A[didChangeWorkspaceFolders通知受信] --> B[削除フォルダ処理ループ]
    B --> C[removeWorkspace uri]
    C --> D{全削除フォルダ処理完了?}
    D -->|No| B
    D -->|Yes| E[追加フォルダ処理ループ]
    E --> F[workspaces配列に追加]
    F --> G[syncConfiguration]
    G --> H[doStartup]
    H --> I{全追加フォルダ処理完了?}
    I -->|No| E
    I -->|Yes| J[処理完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 削除優先 | 削除処理は追加処理より先に実行される | 常時 |
| BR-02 | インスタンス削除 | removeWorkspaceはbackend.removeInstanceでバックエンドインスタンスを削除し、workspace.disabledをtrueに設定する | フォルダ削除時 |
| BR-03 | 設定同期 | 追加フォルダの設定はsyncConfigurationで同期される（第4引数true=新規追加） | フォルダ追加時 |

### 計算ロジック

特になし。

## データベース操作仕様

本機能ではデータベース操作は発生しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| なし | error | removeWorkspaceでworkspaceRootが空の場合 | 処理をスキップ（何も行わない） |
| なし | error | doStartup内でワークスペースが見つからない場合 | エラーログを出力して戻る |

### リトライ仕様

リトライは行わない。

## トランザクション仕様

トランザクションは存在しない。削除と追加は順次実行される。

## パフォーマンス要件

doStartupはDUBプロジェクトの読み込みやDCDサーバーの起動を含むため、追加フォルダ数に比例して時間がかかる。各プロジェクトの初期化進捗はreportProgressでクライアントに通知される。

## セキュリティ考慮事項

特になし。

## 備考

- removeWorkspace関数（extension.d 933-940行目）はworkspaceRootForでルートパスを特定し、backend.removeInstanceでインスタンスを削除する。
- doStartup関数（extension.d 556-631行目）はプロジェクトルートの探索、DUB/FSWorkspaceの初期化、DCDサーバーの遅延起動を行う。
- initializeの際にもワークスペースフォルダが設定されるが、didChangeWorkspaceFoldersは後続の動的変更に対応するもの。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.d | `source/served/types.d` | Workspace構造体（270-327行目）: folder, initialized, disabled等の状態管理 |
| 1-2 | types.d | `source/served/types.d` | workspaces配列（353行目）: 全ワークスペースを管理するグローバル配列 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | extension.d | `source/served/extension.d` | didChangeWorkspaceFolders関数（1101-1112行目）: メインのハンドラ |

**主要処理フロー**:
1. **1104-1105行目**: 削除フォルダのループ処理。removeWorkspace呼び出し
2. **1106-1111行目**: 追加フォルダのループ処理。workspaces追加、syncConfiguration、doStartup

#### Step 3: 削除処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | removeWorkspace関数（933-940行目）: ワークスペース削除の実装 |

**主要処理フロー**:
- **935-936行目**: workspaceRootForでルートパスを特定。空なら即リターン
- **938行目**: backend.removeInstanceでバックエンドインスタンス削除
- **939行目**: workspace.disabledをtrueに設定

#### Step 4: 追加処理（doStartup）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | extension.d | `source/served/extension.d` | doStartup関数（556-631行目）: プロジェクト初期化の全体フロー |

**主要処理フロー**:
- **558行目**: ensureStartedUpでグローバル初期化を保証
- **577-578行目**: rootsForProjectでプロジェクトルート候補を探索
- **597行目**: backend.addInstanceでバックエンドインスタンス追加
- **619-630行目**: 各ルートに対してlazyStartDCDServerでDCDサーバーを遅延起動

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

```
didChangeWorkspaceFolders(DidChangeWorkspaceFoldersParams)
    |
    +-- [削除] removeWorkspace(uri)
    |       |
    |       +-- workspaceRootFor(uri)
    |       +-- backend.removeInstance(root)
    |       +-- workspace.disabled = true
    |
    +-- [追加] Workspace(toAdd)
    |       |
    |       +-- syncConfiguration(uri, i, len, true)
    |       |
    |       +-- doStartup(uri, anyConfig)
    |               |
    |               +-- ensureStartedUp(config)
    |               +-- rootsForProject(...)
    |               +-- backend.addInstance(root, config)
    |               +-- delayedProjectActivation(...)
    |               +-- lazyStartDCDServer(...)
```

### データフロー図

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

DidChangeWorkspaceFolders ─────> didChangeWorkspaceFolders()
  .event.removed          ─────>   removeWorkspace()      ─────> backend削除
  .event.added            ─────>   workspaces配列追加
                                   syncConfiguration()
                                   doStartup()            ─────> backend追加
                                                          ─────> DCD起動
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.d | `source/served/extension.d` | ソース | didChangeWorkspaceFolders、removeWorkspace、doStartup関数の実装 |
| types.d | `source/served/types.d` | ソース | Workspace構造体、workspaces配列の定義 |
| progress.d | `source/served/utils/progress.d` | ソース | doStartup内の進捗レポート |
