# 機能設計書 82-設定の読み込み・保存

## 概要

本ドキュメントは、Windows Terminal の設定ファイル（settings.json）からの読み込み（デシリアライズ）と、設定ファイルへの保存（シリアライズ）の処理を記述する。CascadiaSettings クラスと SettingsLoader クラスが中核を担う。

### 本機能の処理概要

**業務上の目的・背景**：Windows Terminal のすべての設定（プロファイル、カラースキーム、キーバインド、テーマなど）は JSON ファイルで管理される。本機能はアプリケーション起動時のデフォルト設定と ユーザー設定のマージ、動的プロファイルの統合、フラグメント（拡張設定）の適用、および変更後の設定の永続化を行う。

**機能の利用シーン**：アプリケーション起動時の初回設定読み込み、設定UIからの保存操作、settings.json 変更後の自動リロード時に利用される。

**主要な処理内容**：
1. settings.json と defaults.json の JSON パース
2. SettingsLoader による設定のレイヤリング（InBox → User → Fragment）
3. 動的プロファイルジェネレータの実行とマージ
4. バリデーション（カラースキーム存在確認、キーバインド検証、メディアリソース検証等）
5. 設定の JSON シリアライズと settings.json への書き出し
6. ファイルハッシュ計算による変更検知

**関連システム・外部連携**：ファイルシステム（settings.json / defaults.json）、フラグメントディレクトリ（拡張機能からの設定断片）、Windows レジストリ（デフォルトターミナル設定）。

**権限による制御**：設定ファイルへの書き込みはユーザー権限で行われる。ポータブルモードの場合はアプリケーションディレクトリに保存される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 21 | MainPage（設定ナビゲーション） | 主画面 | SaveButton/ResetButtonによる設定の保存・リセット操作 |
| 22 | Launch（起動設定） | 参照画面 | 起動設定の読み込みと保存 |
| 23 | Interaction（操作設定） | 参照画面 | 操作設定の読み込みと保存 |
| 24 | GlobalAppearance（外観設定） | 参照画面 | 外観設定の読み込みと保存 |
| 25 | Rendering（レンダリング設定） | 参照画面 | レンダリング設定の読み込みと保存 |
| 26 | Compatibility（互換性設定） | 参照画面 | 互換性設定の読み込みと保存 |
| 27 | ColorSchemes（配色一覧） | 参照画面 | 配色スキーム設定の読み込みと保存 |
| 29 | Actions（アクション一覧） | 参照画面 | キーバインドとアクション設定の読み込みと保存 |

## 機能種別

データ連携 / シリアライズ・デシリアライズ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| userJSON | std::string_view | Yes | ユーザーの settings.json の内容 | 有効な JSON 文字列 |
| inboxJSON | std::string_view | No | defaults.json の内容 | 有効な JSON 文字列 |

### 入力データソース

- settings.json：ユーザー設定ファイル（`%LOCALAPPDATA%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json` またはポータブルモード時のアプリディレクトリ）
- defaults.json：ビルトインのデフォルト設定（アプリリソース IDR_DEFAULTS に埋め込み）
- フラグメント：`%LOCALAPPDATA%\Microsoft\Windows Terminal\Fragments` および `%ProgramData%\Microsoft\Windows Terminal\Fragments`

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| CascadiaSettings | Model::CascadiaSettings | パース済みの設定オブジェクト |
| settings.json | ファイル | シリアライズされた JSON 文字列 |
| ハッシュ | winrt::hstring | 設定ファイルの変更検知用ハッシュ |

### 出力先

- メモリ：CascadiaSettings オブジェクトとしてアプリケーション内で保持
- ファイル：settings.json

## 処理フロー

### 処理シーケンス

```
1. CascadiaSettings::LoadAll() が呼び出される
   └─ settings.json をファイルから読み込み（til::io::read_file_as_utf8_string_if_exists）
2. SettingsLoader コンストラクタで JSON をパース
   └─ inboxSettings（defaults.json）と userSettings（settings.json）をパース
3. SettingsLoader::GenerateProfiles() で動的プロファイルを生成
   └─ WSL / PowerShell / SSH / VisualStudio / Azure のジェネレータを実行
4. SettingsLoader::MergeInboxIntoUserSettings() でデフォルト設定をユーザー設定にマージ
5. SettingsLoader::FindFragmentsAndMergeIntoUserSettings() でフラグメントを統合
6. SettingsLoader::FinalizeLayering() でレイヤリングを完了
7. SettingsLoader::FixupUserSettings() で設定の修正
8. CascadiaSettings コンストラクタで設定を構築
9. 必要に応じて WriteSettingsToDisk() で settings.json に書き出し
```

### フローチャート

```mermaid
flowchart TD
    A[LoadAll 開始] --> B[settings.json 読み込み]
    B --> C{初回セットアップ?}
    C -->|Yes| D[デフォルト設定を使用]
    C -->|No| E[SettingsLoader でパース]
    D --> E
    E --> F[GenerateProfiles - 動的プロファイル生成]
    F --> G[MergeInboxIntoUserSettings]
    G --> H[FindFragmentsAndMergeIntoUserSettings]
    H --> I[FinalizeLayering]
    I --> J[FixupUserSettings]
    J --> K[CascadiaSettings 構築]
    K --> L{書き込み必要?}
    L -->|Yes| M[WriteSettingsToDisk]
    L -->|No| N[ハッシュ計算]
    M --> O[終了]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-82-01 | 設定レイヤリング | InBox(defaults.json) → User(settings.json) → Fragment の順で設定がレイヤリングされる | 常時 |
| BR-82-02 | 初回セットアップ | settings.json が存在しない場合、デフォルト設定で初期化される | 初回起動時 |
| BR-82-03 | Preview/Canary フォールバック | Preview/Canary ビルドでは Release 版の settings.json があればそれを使用 | Preview/Canary ビルドの初回起動時 |
| BR-82-04 | 動的プロファイル書き込み | 新しい動的プロファイルが検出された場合は settings.json を更新する | 動的プロファイル変更時 |
| BR-82-05 | アトミック書き込み | 設定ファイルの書き込みはアトミック操作で行う | 保存時 |

### 計算ロジック

- ハッシュ計算：settings.json の内容とファイルの最終更新日時からハッシュを算出し、変更検知に使用する。

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

該当なし（ファイルベースのデータ管理）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SettingsLoadErrors | デシリアライズエラー | JSON のパースに失敗した場合 | エラーメッセージとともにデフォルト設定にフォールバック |
| SettingsLoadWarnings | 警告 | カラースキーム不存在、無効なキーバインド等 | 警告を蓄積しユーザーに表示 |
| FailedToWriteToSettings | 書き込みエラー | settings.json への書き込みに失敗した場合 | 警告として記録 |

### リトライ仕様

読み込み失敗時はデフォルト設定にフォールバック。書き込み失敗時は警告を出力するがリトライは行わない。

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

設定ファイルへの書き込みは til::io::write_utf8_string_to_file_atomic を使用してアトミックに行われる。

## パフォーマンス要件

- 初回読み込みはアプリ起動のクリティカルパスに含まれるため、パース処理は可能な限り高速に行う。
- 動的プロファイル生成はバックグラウンドで実行可能だが、初回起動時はブロッキングで行われる。

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

- settings.json はユーザーのローカルプロファイルディレクトリに保存される。
- フラグメントは ProgramData ディレクトリからも読み込まれるため、管理者権限で配置された拡張設定を適用可能。

## 備考

- 設定ファイルのキー定数：`ProfilesKey="profiles"`, `DefaultSettingsKey="defaults"`, `ProfilesListKey="list"`, `SchemesKey="schemes"`, `ThemesKey="themes"`
- JSON スタイルライタの設定：YAML互換モード有効、インデント4スペース、精度6桁。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CascadiaSettings.h | `src/cascadia/TerminalSettingsModel/CascadiaSettings.h` | ParsedSettings 構造体（68-80行目）でパース結果の構造を理解。SettingsLoader クラス（82-142行目）のメンバとメソッド。CascadiaSettings クラス（144-250行目）の公開API |

**読解のコツ**: ParsedSettings には globals, baseLayerProfile, profiles, colorSchemes が含まれ、これが設定レイヤリングの中間表現となる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CascadiaSettingsSerialization.cpp | `src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp` | CascadiaSettings::LoadAll()（1202行目付近）が読み込みのエントリーポイント |

**主要処理フロー**:
1. **1206行目**: settings.json をファイルから読み込み
2. **1257行目**: GenerateProfiles() で動的プロファイル生成
3. **1267行目**: MergeInboxIntoUserSettings()
4. **1270行目**: FindFragmentsAndMergeIntoUserSettings()
5. **1276行目**: FixupUserSettings()
6. **1286行目**: 必要に応じて WriteSettingsToDisk()

#### Step 3: シリアライズ（保存）処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CascadiaSettingsSerialization.cpp | `src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp` | WriteSettingsToDisk()（1591行目）と ToJson()（1642行目）でシリアライズの流れを理解 |

**主要処理フロー**:
- **1591-1610行目**: WriteSettingsToDisk() が ToJson() を呼び出し、JSON ライタで文字列化、_writeSettingsToDisk で書き込み
- **1642-1701行目**: ToJson() がグローバル設定、プロファイル、カラースキーム、テーマを JSON に変換
- **1612-1618行目**: _writeSettingsToDisk() がアトミック書き込みとハッシュ計算を実行

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

```
CascadiaSettings::LoadAll() (CascadiaSettingsSerialization.cpp:1202)
    │
    ├─ SettingsLoader::SettingsLoader() (CascadiaSettingsSerialization.cpp:145)
    │      ├─ _parse(InBox, defaults.json)
    │      └─ _parse(User, settings.json)
    │
    ├─ SettingsLoader::GenerateProfiles() (CascadiaSettingsSerialization.cpp:208)
    │      ├─ WslDistroGenerator::GenerateProfiles()
    │      ├─ PowershellCoreProfileGenerator::GenerateProfiles()
    │      ├─ SshHostGenerator::GenerateProfiles()
    │      ├─ VisualStudioGenerator::GenerateProfiles()
    │      └─ AzureCloudShellGenerator::GenerateProfiles()
    │
    ├─ SettingsLoader::MergeInboxIntoUserSettings()
    ├─ SettingsLoader::FindFragmentsAndMergeIntoUserSettings()
    ├─ SettingsLoader::FinalizeLayering()
    ├─ SettingsLoader::FixupUserSettings()
    │
    └─ CascadiaSettings::WriteSettingsToDisk() (CascadiaSettingsSerialization.cpp:1591)
           ├─ CascadiaSettings::ToJson()
           └─ _writeSettingsToDisk() → til::io::write_utf8_string_to_file_atomic
```

### データフロー図

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

defaults.json ────────▶ SettingsLoader ──────────▶ CascadiaSettings
                            ├─ _parse()                  (メモリ)
settings.json ────────▶     ├─ GenerateProfiles()
                            ├─ MergeInbox()
Fragments/ ───────────▶     ├─ FindFragments()
                            ├─ FinalizeLayering()
                            └─ FixupUserSettings()

CascadiaSettings ─────▶ ToJson() ──▶ WriteSettingsToDisk() ──▶ settings.json
                                                                 (ファイル)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CascadiaSettings.h | `src/cascadia/TerminalSettingsModel/CascadiaSettings.h` | ヘッダ | CascadiaSettings / SettingsLoader / ParsedSettings の定義 |
| CascadiaSettingsSerialization.cpp | `src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp` | ソース | LoadAll / WriteSettingsToDisk / ToJson の実装 |
| CascadiaSettings.cpp | `src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp` | ソース | CascadiaSettings のその他メソッド実装 |
| GlobalAppSettings.h | `src/cascadia/TerminalSettingsModel/GlobalAppSettings.h` | ヘッダ | グローバル設定クラス定義 |
| Profile.h | `src/cascadia/TerminalSettingsModel/Profile.h` | ヘッダ | プロファイルクラス定義 |
| IDynamicProfileGenerator.h | `src/cascadia/TerminalSettingsModel/IDynamicProfileGenerator.h` | ヘッダ | 動的プロファイルジェネレータインターフェース |
| AppLogic.cpp | `src/cascadia/TerminalApp/AppLogic.cpp` | ソース | _TryLoadSettings / ReloadSettings の呼び出し元 |
