# 帳票設計書 12-diagnostics

## 概要

本ドキュメントは、Ghosttyターミナルエミュレータの内部診断情報レポートの設計仕様を定義する。この診断情報は設定ファイルのパース時に自動生成され、Ghostty起動時またはGUIダイアログを通じてユーザーに提示される。

### 本帳票の処理概要

diagnostics（診断情報）は、設定ファイルの読み込みおよびパース処理中に検出されたエラーや警告を収集し、ユーザーに報告するための内部データ構造とその表示機能を提供する。CLI環境ではテキスト形式で出力され、GTK環境では専用のダイアログを通じて表示される。

**業務上の目的・背景**：Ghosttyの設定ファイルは多くの設定項目を持ち、ユーザーが誤った設定を行う可能性がある。診断情報システムは、設定の問題点を明確かつ具体的にユーザーに伝え、迅速な問題解決を支援する。これにより、設定のデバッグ時間を短縮し、ユーザーエクスペリエンスを向上させる。また、エラー発生箇所（ファイルパス、行番号）を含めることで、問題の特定を容易にする。

**帳票の利用シーン**：
- Ghostty起動時に設定エラーが検出された場合の通知
- 設定ファイルのリロード時のエラー表示
- `+validate-config` コマンドの実行結果として
- GTK環境での「Configuration Errors」ダイアログ表示
- 開発・デバッグ時の設定問題の調査

**主要な出力内容**：
1. エラー発生箇所（location）: CLI引数のインデックス、またはファイルパスと行番号
2. 問題のある設定キー（key）: エラーが発生した設定項目名
3. エラーメッセージ（message）: 問題の詳細説明
4. 複数エラーの一括表示対応

**帳票の出力タイミング**：
- Ghostty起動時（設定ロード完了後）
- 設定ファイルのリロード時
- `+validate-config` コマンド実行時
- GTK環境でのConfiguration Errorsダイアログ表示時

**帳票の利用者**：Ghosttyのエンドユーザー、システム管理者、開発者

## 帳票種別

内部診断レポート / エラー通知メッセージ

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| CLI-内部 | ターミナル出力 | N/A（CLI） | Ghostty起動時自動、または `+validate-config` |
| GTK-01 | Configuration Errorsダイアログ | N/A（GUIダイアログ） | 設定エラー検出時に自動表示 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（CLI）/ GTK TextBuffer（GUI） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | N/A（メモリ内データ構造） |
| 出力方法 | 標準出力（CLI）/ GUIダイアログ（GTK） |
| 文字コード | UTF-8 |

### GTK固有設定

| 項目 | 内容 |
|-----|------|
| ダイアログタイトル | Configuration Errors |
| ダイアログ幅 | 最小500px |
| ダイアログ高さ | 最小100px |
| アクションボタン | Ignore / Reload Configuration |

## 帳票レイアウト

### レイアウト概要

診断情報は、Diagnostic構造体のリストとして内部的に管理され、表示時にフォーマットされる。

```
┌─────────────────────────────────────────────────────────────┐
│  [location]:[key]: [message]                                │
│  [location]:[key]: [message]                                │
│  ...                                                        │
└─────────────────────────────────────────────────────────────┘
```

### CLIフォーマット詳細

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | Location (cli) | CLI引数のインデックス | Diagnostic.location.cli | `cli:{index}:` |
| 2 | Location (file) | ファイルパスと行番号 | Diagnostic.location.file | `{path}:{line}:` |
| 3 | キー名 | 問題のある設定キー | Diagnostic.key | `{key}: ` または空白 |
| 4 | メッセージ | エラーの詳細 | Diagnostic.message | 文字列 |

### 出力例

#### CLI環境での出力例
```
cli:3:font-size: invalid value "abc"
/home/user/.config/ghostty/config:15:unknown-key: unknown field
/home/user/.config/ghostty/config:23:window-theme: invalid value "xyz", valid values are: auto, system, light, dark
```

#### GTK環境での表示
```
┌─────────────────────────────────────────────────────────────┐
│  Configuration Errors                                       │
├─────────────────────────────────────────────────────────────┤
│  One or more configuration errors were found. Please review │
│  the errors below, and either reload your configuration or  │
│  ignore these errors.                                       │
├─────────────────────────────────────────────────────────────┤
│  ┌───────────────────────────────────────────────────────┐  │
│  │ /home/user/.config/ghostty/config:15:font: unknown   │  │
│  │ field                                                 │  │
│  └───────────────────────────────────────────────────────┘  │
├─────────────────────────────────────────────────────────────┤
│  [Ignore]                      [Reload Configuration]       │
└─────────────────────────────────────────────────────────────┘
```

## 出力条件

### 生成条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 設定パースエラー | 設定ファイルのパース中にエラーが発生 | 自動 |
| 無効なフィールド | 存在しない設定キーが指定された | 自動 |
| 無効な値 | フィールドの型に合わない値が指定された | 自動 |
| ファイル読込エラー | config-fileで指定されたファイルが開けない | 自動 |
| ファイルタイプエラー | config-fileがファイルではない（ディレクトリ等） | 自動 |

### Location種別

| 種別 | 説明 | フォーマット |
|-----|------|------------|
| none | 発生箇所不明 | (空) |
| cli | CLI引数からの設定 | `cli:{index}:` |
| file | 設定ファイルからの設定 | `{path}:{line}:` |

### 改ページ条件

N/A（CLIテキスト出力/GUIダイアログのため改ページなし）

## データベース参照仕様

N/A（データベースを使用しない）

## データ構造仕様

### Diagnostic構造体

```zig
pub const Diagnostic = struct {
    location: Location = .none,
    key: [:0]const u8 = "",
    message: [:0]const u8,
};
```

### Location共用体

```zig
pub const Location = union(enum) {
    none,
    cli: usize,           // CLI引数のインデックス（1-indexed）
    file: struct {
        path: []const u8,  // ファイルパス
        line: usize,       // 行番号（1-indexed）
    },
};
```

### DiagnosticList構造体

```zig
pub const DiagnosticList = struct {
    list: std.ArrayListUnmanaged(Diagnostic) = .{},
    precompute: Precompute = precompute_init,  // libghostty用の事前計算
};
```

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| 診断件数 | `DiagnosticList.list.items.len` | N/A | エラー/警告の総数 |
| 空判定 | `list.items.len == 0` | N/A | empty()メソッド |

## 処理フロー

### 診断情報生成フロー

```mermaid
flowchart TD
    A[設定ロード開始] --> B[デフォルト設定初期化]
    B --> C[設定ファイル読込]
    C --> D{パースエラー?}
    D -->|Yes| E[Diagnostic生成]
    E --> F[DiagnosticListに追加]
    D -->|No| G[次の設定項目]
    F --> G
    G --> H{全項目処理完了?}
    H -->|No| D
    H -->|Yes| I[finalize処理]
    I --> J{追加エラー?}
    J -->|Yes| K[Diagnostic追加]
    K --> L[診断情報完成]
    J -->|No| L
```

### 診断情報表示フロー（GTK）

```mermaid
flowchart TD
    A[Config読込完了] --> B{diagnostics.empty()?}
    B -->|Yes| C[正常起動]
    B -->|No| D[GhosttyConfigErrorsDialog表示]
    D --> E[diagnosticsBuffer生成]
    E --> F[TextViewに表示]
    F --> G{ユーザー操作}
    G -->|Ignore| H[ダイアログを閉じて起動継続]
    G -->|Reload| I[設定リロード]
    I --> A
```

## エラー処理

### 診断メッセージ種別一覧

| エラー種別 | 発生条件 | メッセージ例 | 生成元 |
|----------|---------|-------------|-------|
| unknown field | 存在しない設定キー | `unknown field` | args.zig:162 |
| value required | 値が必要なフィールドに値がない | `value required` | args.zig:163 |
| invalid value | 型に合わない値 | `invalid value "<value>"` | args.zig:164 |
| config-file循環 | 循環参照が検出された | `config-file {path}: would cause a cycle` | Config.zig:4195 |
| ファイルオープンエラー | ファイルが開けない | `error opening config-file {path}: {err}` | Config.zig:4211 |
| ファイルタイプエラー | ファイルでない | `config-file {path}: not reading because file type is {kind}` | Config.zig:4231 |
| コマンド不足 | -e後にコマンドがない | `missing command after {arg}` | Config.zig:4674 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 0〜100件程度（通常は少数） |
| 目標処理時間 | ミリ秒単位（設定ロードの一部として） |
| メモリ使用量 | DiagnosticList + 各メッセージ文字列 |

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

- 設定ファイルパスがそのまま出力されるため、機密性の高いパス情報が露出する可能性がある
- 設定値自体は出力されない（キー名とエラーメッセージのみ）
- libghostty使用時はprecompute機能により、メッセージの事前計算が行われる

## 備考

- DiagnosticList.precomputeはlibghostty（ライブラリビルド）時に有効になり、C APIからの効率的なアクセスを可能にする
- 診断情報はConfig構造体の`_diagnostics`フィールドに格納され、設定の寿命と同じライフタイムを持つ
- GTK環境では、GhosttyConfig GObjectがdiagnostics-bufferプロパティを提供し、UIバインディングを可能にする

---

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

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

### 推奨読解順序

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

診断情報の中核となるDiagnostic構造体とその関連型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | diagnostics.zig | `src/cli/diagnostics.zig` | Diagnostic構造体（13-45行目）: 診断情報の基本単位 |
| 1-2 | diagnostics.zig | `src/cli/diagnostics.zig` | Location共用体（49-85行目）: エラー発生箇所の表現 |
| 1-3 | diagnostics.zig | `src/cli/diagnostics.zig` | DiagnosticList構造体（94-197行目）: 診断情報のコレクション |

**読解のコツ**:
- Diagnostic.format関数（19-36行目）が実際の出力フォーマットを決定する
- Location.fromIter関数（59-71行目）がイテレータから位置情報を取得する方法を示す

#### Step 2: 診断情報の生成箇所を理解する

設定パース中に診断情報がどのように生成されるかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | args.zig | `src/cli/args.zig` | parse関数の診断生成（112-123行目, 174-178行目） |
| 2-2 | Config.zig | `src/config/Config.zig` | _diagnosticsフィールド（3761行目） |
| 2-3 | Config.zig | `src/config/Config.zig` | loadRecursiveFiles内の診断生成（4195, 4211, 4231行目） |
| 2-4 | Config.zig | `src/config/Config.zig` | addDiagnosticFmt関数（4825-4839行目） |

**主要処理フロー**:
1. **args.zig:112-123行目**: `--`で始まらない引数をエラーとして診断追加
2. **args.zig:174-178行目**: パースエラー発生時に診断情報を生成
3. **Config.zig:4195行目**: config-fileの循環参照を検出して診断追加
4. **Config.zig:4211行目**: ファイルオープンエラーを診断追加
5. **Config.zig:4231行目**: ファイルタイプエラーを診断追加

#### Step 3: 診断情報の表示を理解する

診断情報がどのように表示されるかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | validate_config.zig | `src/cli/validate_config.zig` | CLI表示（70-74行目） |
| 3-2 | config.zig (GTK) | `src/apprt/gtk/class/config.zig` | GhosttyConfig GObject（23-164行目） |
| 3-3 | config.zig (GTK) | `src/apprt/gtk/class/config.zig` | hasDiagnostics関数（102-106行目） |
| 3-4 | config.zig (GTK) | `src/apprt/gtk/class/config.zig` | diagnosticsBuffer関数（110-134行目） |
| 3-5 | config-errors-dialog.blp | `src/apprt/gtk/ui/1.2/config-errors-dialog.blp` | GTKダイアログ定義 |

**主要処理フロー**:
- **validate_config.zig:70-74行目**: 診断情報をイテレートしてformat関数で出力
- **config.zig:110-134行目**: GTK TextBufferに診断情報を書き込み
- **config-errors-dialog.blp**: diagnostics-bufferプロパティとTextViewをバインド

#### Step 4: CLI関連モジュールの構造を理解する

CLI関連のモジュール構造とエクスポートを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | cli.zig | `src/cli.zig` | モジュールエクスポート（1-14行目） |

**主要処理フロー**:
- **cli.zig:1-10行目**: diagnostics, args, action, ghosttyモジュールのインポートとエクスポート

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

```
設定ロード処理
    │
    ├─ Config.zig: load()
    │      │
    │      ├─ Config.zig: loadDefaultFiles()
    │      │      │
    │      │      └─ args.zig: parse() ──▶ DiagnosticList.append()
    │      │
    │      ├─ Config.zig: loadCliArgs()
    │      │      │
    │      │      └─ args.zig: parse() ──▶ DiagnosticList.append()
    │      │
    │      ├─ Config.zig: loadRecursiveFiles()
    │      │      │
    │      │      ├─ 循環参照検出 ──▶ DiagnosticList.append()
    │      │      ├─ ファイルオープンエラー ──▶ DiagnosticList.append()
    │      │      └─ ファイルタイプエラー ──▶ DiagnosticList.append()
    │      │
    │      └─ Config.zig: finalize()
    │             │
    │             └─ 追加エラー検出 ──▶ DiagnosticList.append()
    │
    ▼
CLI表示
    │
    └─ validate_config.zig: runInner()
           │
           └─ Diagnostic.format() ──▶ stdout

GTK表示
    │
    ├─ gtk/class/config.zig: GhosttyConfig
    │      │
    │      ├─ hasDiagnostics() ──▶ bool
    │      │
    │      └─ diagnosticsBuffer() ──▶ TextBuffer
    │
    └─ config-errors-dialog.blp
           │
           └─ TextViewにバインド
```

### データフロー図

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

設定ファイル ───────▶ args.parse() ───────▶ _diagnostics
    │                       │
CLI引数 ────────────▶ parseIntoField()
                            │
                            ├─(エラー)─▶ Diagnostic生成
                            │               │
                            │               ▼
                            │         DiagnosticList.append()
                            │               │
                            ▼               ▼
                    Config.loadRecursiveFiles()
                            │
                            ├─(循環参照)─▶ Diagnostic生成
                            ├─(ファイルエラー)─▶ Diagnostic生成
                            │
                            ▼
                    _diagnostics (完成)
                            │
            ┌───────────────┼───────────────┐
            ▼               ▼               ▼
        CLI出力         GTK出力       libghostty API
            │               │               │
            ▼               ▼               ▼
    Diagnostic.format() diagnosticsBuffer() precompute.messages
            │               │               │
            ▼               ▼               ▼
        stdout          TextBuffer      C API返却
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| diagnostics.zig | `src/cli/diagnostics.zig` | ソース | Diagnostic/DiagnosticList/Location構造体の定義 |
| args.zig | `src/cli/args.zig` | ソース | CLI引数パーサー、診断情報の生成 |
| Config.zig | `src/config/Config.zig` | ソース | 設定管理、_diagnosticsフィールドの所有者 |
| validate_config.zig | `src/cli/validate_config.zig` | ソース | CLI診断情報表示の実装 |
| cli.zig | `src/cli.zig` | ソース | CLIモジュールのエクスポート |
| config.zig (GTK) | `src/apprt/gtk/class/config.zig` | ソース | GTK用GhosttyConfig GObject |
| config-errors-dialog.blp | `src/apprt/gtk/ui/1.2/config-errors-dialog.blp` | UI定義 | GTKエラーダイアログのBlueprint定義 |
