# 通知設計書 66-WINDOW_ASK_APPLY_LIBRARY

## 概要

本ドキュメントは、Lua Language Server における `WINDOW_ASK_APPLY_LIBRARY` 通知の設計仕様を定義する。この通知は、サードパーティライブラリが検出された際に、ユーザーに対して作業環境をそのライブラリ用に設定するかどうかを確認するダイアログメッセージとして使用される。

### 本通知の処理概要

**業務上の目的・背景**：Lua Language Serverは、ユーザーが使用しているサードパーティライブラリ（例：Love2D、Defold、OpenResty、Cocos2d-x等）を自動検出する機能を持つ。検出は、ファイル内の特定キーワード（`love.`、`cc.`など）やファイル名パターンに基づいて行われる。検出された場合、ユーザーに対してそのライブラリ用の設定（補完定義ファイルの追加、プラグインの有効化など）を適用するかどうかを確認する。本通知はその確認ダイアログのメインメッセージとして使用される。

**通知の送信タイミング**：ファイルの保存・更新時にサードパーティライブラリのキーワードやファイル名パターンが検出され、かつ`checkThirdParty`設定が'Ask'の場合に送信される。

**通知の受信者**：IDEやエディタを使用している開発者（ユーザー）に対して、確認ダイアログとして表示される。

**通知内容の概要**：「作業環境を`{ライブラリ名}`に設定しますか？」という確認メッセージ。

**期待されるアクション**：ユーザーは3つの選択肢から選択する：(1) 設定を変更して適用、(2) 設定を変更せずに適用、(3) 再度表示しない。

## 通知種別

アプリ内通知（LSP window/showMessageRequest）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（ユーザー入力待ち） |
| 優先度 | 中（Info） |
| リトライ | 無 |

### 送信先決定ロジック

LSPプロトコルを通じて、接続中のクライアント（IDE/エディタ）に直接送信される。

## 通知テンプレート

### メール通知の場合

該当なし（LSP通知のみ）

### 本文テンプレート

英語:
```
Do you need to configure your work environment as `{}`?
```

日本語:
```
作業環境を `{}` に設定しますか？
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| {} (第1引数) | ライブラリ名（例: "love2d", "defold"） | cfg.name | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ファイル更新 | ファイル保存時にサードパーティライブラリのキーワード検出 | checkThirdParty='Ask'、かつ未確認のライブラリ | check3rdByWords関数で検出 |
| ファイル更新 | ファイル名パターンによるサードパーティライブラリ検出 | checkThirdParty='Ask'、かつ未確認のライブラリ | check3rdByFileName関数で検出 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| checkThirdParty='Disable' | サードパーティチェックが無効化されている |
| checkThirdParty='Apply' | 自動適用が有効で、ダイアログ表示しない |
| checkThirdParty='ApplyInMemory' | メモリ内適用が有効で、ダイアログ表示しない |
| hasAsked[cfg.name]=true | 既にそのライブラリについて確認済み |
| ライブラリが既に設定済み | workspace.libraryに既に含まれている |
| canCheckThirdParty=false | スコープでサードパーティチェックが無効 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ファイル更新イベント] --> B[check3rd呼び出し]
    B --> C{ws.isIgnored?}
    C -->|Yes| D[終了]
    C -->|No| E{checkThirdParty設定}
    E -->|Disable/false| D
    E -->|Apply| F[自動適用]
    E -->|ApplyInMemory| G[メモリ内適用]
    E -->|Ask/true| H{canCheckThirdParty?}
    H -->|No| D
    H -->|Yes| I[load3rdConfig]
    I --> J[check3rdByWords/FileName]
    J --> K{ライブラリ検出?}
    K -->|No| D
    K -->|Yes| L{hasAsked?}
    L -->|Yes| D
    L -->|No| M{既に設定済み?}
    M -->|Yes| D
    M -->|No| N[askFor3rd]
    N --> O[WINDOW_ASK_APPLY_LIBRARY表示]
    O --> P{ユーザー選択}
    P -->|適用して設定変更| Q[apply3rd永続化]
    P -->|適用のみ| R[apply3rdメモリ]
    P -->|再度表示しない| S[checkThirdParty無効化]
    P -->|キャンセル| D
    Q --> D
    R --> D
    S --> D
    F --> D
    G --> D
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（データベースは使用しない）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 設定読み込み失敗 | config.jsonの読み込みエラー | エラーログを出力して続行 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（ただしhasAskedで同一ライブラリは抑止） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（随時送信）

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

- サードパーティライブラリの設定変更は、ユーザーの明示的な同意を得てから行われる
- ライブラリ名は内部設定ファイル（config.json）から取得され、外部からの注入リスクは低い
- プラグインの有効化など、コード実行を伴う設定変更には別途信頼確認（PLUGIN_TRUST_LOAD）が必要

## 備考

- サードパーティライブラリの定義は`meta/3rd/`ディレクトリまたはユーザー指定のディレクトリに格納される
- 検出方法は2種類：キーワード検出（cfg.words）とファイル名パターン（cfg.files）
- 3つの選択肢が表示される：WINDOW_APPLY_WHIT_SETTING、WINDOW_APPLY_WHITOUT_SETTING、WINDOW_DONT_SHOW_AGAIN

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | library.lua | `script/library.lua` | サードパーティライブラリの設定構造（cfg）を理解する |

**読解のコツ**: `loadSingle3rdConfig`関数（340-383行目）で読み込まれる設定構造を確認。cfg.name、cfg.words、cfg.filesが重要。

#### Step 2: 検出ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | library.lua | `script/library.lua` | check3rdByWords関数（529-566行目）でキーワード検出を理解 |
| 2-2 | library.lua | `script/library.lua` | check3rdByFileName関数（568-602行目）でファイル名パターン検出を理解 |

**主要処理フロー**:
1. **537-538行**: テキスト取得
2. **552-554行**: キーワードマッチング（wholeMatch関数）
3. **557-559行**: askFor3rd呼び出し

#### Step 3: ダイアログ表示ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | library.lua | `script/library.lua` | askFor3rd関数（476-517行目）でダイアログが表示される |

**主要処理フロー**:
- **493-495行**: WINDOW_ASK_APPLY_LIBRARYをメッセージとしてwindow/showMessageRequest送信
- **490-492行**: 3つのボタンラベルを設定

#### Step 4: 設定適用ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | library.lua | `script/library.lua` | apply3rd関数（420-473行目）で設定が適用される |

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

```
files.watch (658行)
    |
    └─ check3rd (605行)
           |
           ├─ ws.isIgnored (606行)
           |
           ├─ config.get('checkThirdParty') (609行)
           |
           ├─ scope.get('canCheckThirdParty') (617行)
           |
           ├─ load3rdConfig (620行)
           |      └─ loadSingle3rdConfig (392行)
           |
           ├─ check3rdByWords (624行)
           |      |
           |      ├─ files.getText (537行)
           |      |
           |      ├─ wholeMatch (554行)
           |      |
           |      └─ askFor3rd (558行)
           |             |
           |             ├─ WINDOW_ASK_APPLY_LIBRARY (494行)
           |             |
           |             └─ client.awaitRequestMessage (493行)
           |
           └─ check3rdByFileName (625行)
                  └─ askFor3rd (598行)
```

### データフロー図

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

ファイル更新       ───▶  check3rd                 ───▶  (サードパーティ未検出)
                           |
                           v
                    load3rdConfig
                           |
                           v
                    3rdライブラリ設定取得
                           |
                           v
                  check3rdByWords/FileName
                           |
                           v
                    キーワード/パターン検出
                           |
                           v
                    askFor3rd (494行)
                           |
                           v
                lang.script(WINDOW_ASK_APPLY_LIBRARY, cfg.name)
                           |
                           v
                window/showMessageRequest ───▶ ユーザー確認ダイアログ
                           |
                           v
                    ユーザー選択 ───▶ apply3rd / checkThirdParty無効化
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| library.lua | `script/library.lua` | ソース | サードパーティライブラリ検出と設定適用 |
| client.lua | `script/client.lua` | ソース | メッセージリクエスト送信 |
| script.lua | `locale/en-us/script.lua` | ローカライズ | 英語メッセージテンプレート |
| script.lua | `locale/ja-jp/script.lua` | ローカライズ | 日本語メッセージテンプレート |
| config.json | `meta/3rd/*/config.json` | 設定 | サードパーティライブラリ定義 |
