# 機能設計書 50-フォルダ変更 (workspace/didChangeWorkspaceFolders)

## 概要

本ドキュメントは、Lua Language Serverにおけるワークスペースフォルダ変更通知機能（workspace/didChangeWorkspaceFolders）の設計仕様を記述する。この機能は、マルチルートワークスペースでフォルダが追加・削除された際の処理を行う。

### 本機能の処理概要

ワークスペースフォルダ変更通知機能は、VSCode等のマルチルートワークスペース機能を使用している際に、フォルダの追加や削除を検知し、サーバー内のワークスペース状態を更新する。

**業務上の目的・背景**：VSCodeのマルチルートワークスペースでは、1つのウィンドウで複数のプロジェクトフォルダを同時に開くことができる。フォルダが追加された際には、そのフォルダ内のLuaファイルをスキャンして解析対象に含め、フォルダが削除された際には、関連するリソースをクリーンアップする必要がある。この機能により、動的なワークスペース構成の変更に対応できる。

**機能の利用シーン**：
- VSCodeでワークスペースにフォルダを追加した場合
- VSCodeでワークスペースからフォルダを削除した場合
- マルチルートワークスペースの構成を変更した場合

**主要な処理内容**：
1. クライアントからdidChangeWorkspaceFolders通知を受信
2. 追加されたフォルダを処理
   - workspace.create()でフォルダを作成
   - m.updateConfig()で設定を更新
   - workspace.reload()でファイルスキャン実行
3. 削除されたフォルダを処理
   - workspace.remove()でフォルダを削除

**関連システム・外部連携**：
- ワークスペース管理（script/workspace/）
- 設定管理（script/config/）
- LSPクライアントとのJSON-RPC通信

**権限による制御**：特に権限による制御は行われない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | ワークスペース管理の内部処理（画面マッピングなし） |

## 機能種別

ワークスペース管理 / マルチルートワークスペース対応

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| event.added | WorkspaceFolder[] | Yes | 追加されたフォルダの配列 | 有効なURI |
| event.removed | WorkspaceFolder[] | Yes | 削除されたフォルダの配列 | 有効なURI |

WorkspaceFolder構造体:
| 項目名 | 型 | 説明 |
|--------|-----|------|
| uri | string | フォルダのURI |
| name | string | フォルダの表示名 |

### 入力データソース

- LSPクライアントからのJSON-RPC通知

## 出力仕様

### 出力データ

本機能は通知（notification）であり、レスポンスを返さない。

### 出力先

- サーバー内部のワークスペース状態の更新

## 処理フロー

### 処理シーケンス

```
1. 通知受信
   └─ workspace/didChangeWorkspaceFoldersメッセージを受信

2. 追加フォルダ処理
   └─ 各フォルダについて:
      ├─ files.getRealUri()でURI正規化
      ├─ workspace.create()でフォルダ作成
      ├─ m.updateConfig()で設定更新
      └─ workspace.reload()でリロード

3. 削除フォルダ処理
   └─ 各フォルダについて:
      ├─ files.getRealUri()でURI正規化
      └─ workspace.remove()でフォルダ削除
```

### フローチャート

```mermaid
flowchart TD
    A[通知受信] --> B{追加フォルダあり?}
    B -->|Yes| C[workspace.create]
    C --> D[m.updateConfig]
    D --> E[workspace.reload]
    E --> F{次の追加フォルダ}
    F -->|あり| C
    F -->|なし| G{削除フォルダあり?}
    B -->|No| G
    G -->|Yes| H[workspace.remove]
    H --> I{次の削除フォルダ}
    I -->|あり| H
    I -->|なし| J[処理完了]
    G -->|No| J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-50-01 | 追加優先 | 追加フォルダを先に処理し、その後削除フォルダを処理 | 常時 |
| BR-50-02 | URI正規化 | files.getRealUri()でURIを正規化 | 常時 |
| BR-50-03 | スコープ取得 | 追加フォルダのスコープを取得してリロード | フォルダ追加時 |

### 計算ロジック

該当なし。

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

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

本機能は通知であり、エラー応答は返さない。

### リトライ仕様

該当なし（通知のため）。

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

該当なし（メモリ内処理のみ）

## パフォーマンス要件

- フォルダ追加時はファイルスキャンが発生するため、大規模プロジェクトでは時間がかかる可能性あり
- 非同期処理で実行

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

- 特になし

## 備考

- capability定義でworkspaceFolders.supported=true, changeNotifications=trueを設定
- initialize時に渡されたworkspaceFoldersも同様の処理で追加される

---

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

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

### 推奨読解順序

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

LSP通知ハンドラを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | provider.lua | `script/provider/provider.lua` | didChangeWorkspaceFoldersの登録（246-269行目） |

**主要処理フロー**:
1. **247-254行目**: capability定義（supported, changeNotifications）
2. **257-263行目**: 追加フォルダ処理ループ
3. **264-267行目**: 削除フォルダ処理ループ

#### Step 2: capability定義を理解する

workspaceFoldersのcapability定義を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | provider.lua | `script/provider/provider.lua` | capability（247-254行目） |

**capability構造**:
```lua
capability = {
    workspace = {
        workspaceFolders = {
            supported = true,
            changeNotifications = true,
        },
    },
},
```

#### Step 3: workspace.createを理解する

フォルダ作成ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | workspace.lua | `script/workspace/workspace.lua` | create関数（47-58行目） |

**主要処理フロー**:
- **48行目**: ログ出力
- **49行目**: scope.createFolderでスコープ作成
- **50行目**: m.foldersへの追加
- **51-56行目**: ルートディレクトリチェック

#### Step 4: workspace.removeを理解する

フォルダ削除ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | workspace.lua | `script/workspace/workspace.lua` | remove関数（60-74行目） |

**主要処理フロー**:
- **62-65行目**: 対象フォルダの検索
- **66行目**: scp:remove()呼び出し
- **67行目**: m.foldersからの削除
- **68-70行目**: 状態リセット
- **71行目**: flushFilesでファイルクリア

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

```
provider.lua (m.register 'workspace/didChangeWorkspaceFolders')
    │
    ├─ 追加フォルダ処理
    │      │
    │      ├─ files.getRealUri(folder.uri)
    │      │      └─ URI正規化
    │      │
    │      ├─ workspace.create(uri)
    │      │      ├─ scope.createFolder()
    │      │      │      └─ スコープ作成
    │      │      └─ m.folders追加
    │      │
    │      ├─ m.updateConfig()
    │      │      └─ 設定再読み込み
    │      │
    │      └─ workspace.reload(scope)
    │             └─ ファイルスキャン実行
    │
    └─ 削除フォルダ処理
           │
           ├─ files.getRealUri(folder.uri)
           │      └─ URI正規化
           │
           └─ workspace.remove(uri)
                  ├─ scp:remove()
                  ├─ m.foldersから削除
                  ├─ 状態リセット
                  └─ flushFiles()
```

### データフロー図

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

LSP通知
  ├─ event.added  ───▶    追加フォルダ処理
  │     [folder]          ├─ files.getRealUri()
  │                       ├─ workspace.create()
  │                       ├─ m.updateConfig()
  │                       └─ workspace.reload()
  │                              │
  │                              ▼
  │                       ファイルスキャン ──────▶ 解析対象追加
  │
  └─ event.removed ───▶   削除フォルダ処理
        [folder]          └─ workspace.remove()
                                 │
                                 ▼
                          リソースクリア ──────▶ 解析対象削除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| provider.lua | `script/provider/provider.lua` | ソース | LSP通知ハンドラの登録・実行 |
| workspace.lua | `script/workspace/workspace.lua` | ソース | ワークスペース管理（create/remove/reload） |
| scope.lua | `script/workspace/scope.lua` | ソース | スコープ管理（フォルダスコープの作成） |
| files.lua | `script/files.lua` | ソース | ファイル管理・URI正規化 |
| config.lua | `script/config/config.lua` | ソース | 設定管理 |
