# 機能設計書 3-スクリーン管理

## 概要

本ドキュメントは、Ghosttyターミナルエミュレータにおける端末画面のバッファ管理（メイン画面と代替画面の切り替え含む）を行う「スクリーン管理」機能の設計を記述する。

### 本機能の処理概要

スクリーン管理機能は、端末画面の状態を管理するScreen構造体と、複数画面（プライマリ/代替）を管理するScreenSet構造体で構成される。Screen構造体は、カーソル位置、選択範囲、文字セット状態、Kittyキーボード設定、セマンティックプロンプト状態などを保持し、PageListを通じて実際の画面データを管理する。

**業務上の目的・背景**：ターミナルエミュレータでは、通常の端末画面（プライマリ画面）と、vim等のフルスクリーンアプリケーションが使用する代替画面（alternate screen）の2種類の画面を切り替えて使用する必要がある。この切り替えにより、アプリケーション終了後に元の画面状態を復元できる。また、画面サイズ変更時のリフロー処理や、スクロールバック履歴の効率的な管理も必要となる。

**機能の利用シーン**：
- vim、less、htop等のTUIアプリケーションがSMCUP/RMCUPで代替画面に切り替える場面
- 画面サイズ変更時に既存のテキストをリフローする場面
- カーソル位置の保存・復元（DECSC/DECRC）を行う場面
- 選択範囲の管理とトラッキングを行う場面

**主要な処理内容**：
1. Screen構造体の初期化とリソース管理
2. プライマリ画面と代替画面の切り替え（ScreenSet）
3. カーソル位置の管理とページピンとの同期
4. 選択範囲のトラッキング
5. 画面リセット（DEC RIS）処理
6. 画面クローン（読み取り専用コピー）

**関連システム・外部連携**：
- PageList（ページリスト管理）との連携
- Terminal構造体からの呼び出し
- Kittyグラフィックス統合
- レンダラーへの描画要求

**権限による制御**：特になし。スクリーン管理は全ユーザーに対して同一の動作を提供する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | メインターミナルウィンドウ | 主画面 | 端末画面のバッファ管理、メイン画面と代替画面の切り替え |
| 2 | クイックターミナル | 主画面 | 端末画面のバッファ管理 |
| 3 | スプリットビュー | 主画面 | 各分割ペインのスクリーン管理 |

## 機能種別

状態管理 / データ構造管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| cols | size.CellCountInt | Yes | 画面の列数 | 1以上の正の整数 |
| rows | size.CellCountInt | Yes | 画面の行数 | 1以上の正の整数 |
| max_scrollback | usize | No | スクロールバック最大サイズ（バイト） | デフォルト0（無制限） |
| kitty_image_storage_limit | usize | No | Kitty画像ストレージ制限 | デフォルト320MB |

### 入力データソース

- Terminal構造体からの初期化パラメータ
- 設定ファイルからの画面サイズ、スクロールバック設定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| cursor | Cursor | カーソル位置とスタイル |
| pages | PageList | ページリスト（画面データ） |
| selection | ?Selection | 選択範囲（存在する場合） |
| charset | CharsetState | 文字セット状態 |
| kitty_keyboard | KeyFlagStack | Kittyキーボード設定 |
| semantic_prompt | SemanticPrompt | セマンティックプロンプト状態 |

### 出力先

- レンダラーへの描画データ提供
- Terminal構造体への状態通知

## 処理フロー

### 処理シーケンス

```
1. Screen初期化
   └─ PageList初期化
   └─ カーソルピン作成とトラッキング
   └─ Kittyグラフィックスストレージ設定（該当時）

2. 文字書き込み
   └─ カーソル位置のセルに文字を書き込み
   └─ スタイル適用
   └─ カーソル移動

3. 画面切り替え（SMCUP/RMCUP）
   └─ ScreenSet.switchTo()でactive切り替え
   └─ 代替画面は遅延初期化

4. 画面リセット（DEC RIS）
   └─ PageList.reset()
   └─ カーソルを左上に移動
   └─ 選択、Kittyグラフィックス等クリア

5. 画面クローン
   └─ PageListのクローン
   └─ カーソル位置のリマップ
   └─ 選択範囲の保持（可能な場合）
```

### フローチャート

```mermaid
flowchart TD
    A[Screen.init] --> B[PageList.init]
    B --> C[カーソルピン作成]
    C --> D[Kittyグラフィックス設定]
    D --> E[Screen使用可能]

    E --> F{操作種別}
    F -->|文字書込| G[セル更新]
    F -->|画面切替| H[ScreenSet.switchTo]
    F -->|リセット| I[Screen.reset]
    F -->|クローン| J[Screen.clone]

    G --> K[カーソル移動]
    H --> L[active画面変更]
    I --> M[全状態クリア]
    J --> N[読み取り専用コピー生成]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | プライマリ画面必須 | プライマリ画面は常に存在し、削除不可 | ScreenSet操作時 |
| BR-002 | 代替画面遅延初期化 | 代替画面は初回使用時に初期化 | SMCUP実行時 |
| BR-003 | トラッキング選択 | 選択範囲は必ずトラッキングピンを使用 | 選択設定時 |
| BR-004 | カーソルピン同期 | カーソルのx/y座標とピンは常に同期 | カーソル操作後 |
| BR-005 | リセット時のピン保持 | リセット時もトラッキングピンは保持 | DEC RIS実行時 |

### 計算ロジック

- カーソル位置: `cursor.x`, `cursor.y` は0-indexed
- ページピン: `cursor.page_pin` でページ内の正確な位置を追跡

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

本機能はデータベースを使用しない。すべての状態はメモリ内のデータ構造で管理される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| E-001 | メモリ不足 | Screen初期化時のメモリ確保失敗 | エラーを呼び出し元に伝播 |
| E-002 | ピントラッキング失敗 | ピンのトラッキング登録失敗 | エラーを呼び出し元に伝播 |

### リトライ仕様

メモリ不足時はリトライせず、エラーを呼び出し元に伝播する。

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

トランザクション処理は使用しない。各操作は即座に適用される。

## パフォーマンス要件

- 画面切り替え: O(1)
- カーソル移動: O(1)
- 画面クローン: O(n) - nはクローン範囲のセル数

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

- Kitty画像ストレージ制限によるメモリ消費制御
- 画面データのクローンは読み取り専用用途に限定

## 備考

- スクロールバックなし設定（max_scrollback=0）の場合、no_scrollbackフラグで最適化
- Kittyグラフィックスはコンパイル時オプションで有効/無効

---

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

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

### 推奨読解順序

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

スクリーン管理の中核となるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Screen.zig | `src/terminal/Screen.zig` | Screen構造体のフィールド定義 |
| 1-2 | Screen.zig | `src/terminal/Screen.zig` | Cursor、SavedCursor、CharsetState構造体 |
| 1-3 | ScreenSet.zig | `src/terminal/ScreenSet.zig` | ScreenSet構造体、Key enum |

**読解のコツ**: Screen構造体には多くのフィールドがあるが、最も重要なのは`pages`（PageList）、`cursor`（Cursor）、`selection`（?Selection）。これらがスクリーン状態の核心。

#### Step 2: 初期化と終了処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Screen.zig | `src/terminal/Screen.zig` | init()関数 - 277-319行目 |
| 2-2 | Screen.zig | `src/terminal/Screen.zig` | deinit()関数 - 321-327行目 |
| 2-3 | ScreenSet.zig | `src/terminal/ScreenSet.zig` | init()、deinit()関数 |

**主要処理フロー**:
- **277-319行目**: `Screen.init()` - PageList初期化、カーソルピン作成、Kittyグラフィックス設定
- **321-327行目**: `Screen.deinit()` - リソース解放
- **32-45行目（ScreenSet）**: `ScreenSet.init()` - プライマリ画面の初期化

#### Step 3: カーソル管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Screen.zig | `src/terminal/Screen.zig` | Cursor構造体 - 121-184行目 |
| 3-2 | Screen.zig | `src/terminal/Screen.zig` | SavedCursor構造体 - 187-195行目 |
| 3-3 | Screen.zig | `src/terminal/Screen.zig` | assertIntegrity() - 333-354行目 |

**主要処理フロー**:
- **121-184行目**: Cursor構造体 - x/y座標、スタイル、ピン情報
- **172-176行目**: page_pin、page_row、page_cellによるページ内位置追跡
- **333-354行目**: assertIntegrity() - カーソル整合性チェック

#### Step 4: 画面切り替えを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ScreenSet.zig | `src/terminal/ScreenSet.zig` | switchTo()関数 - 91-94行目 |
| 4-2 | ScreenSet.zig | `src/terminal/ScreenSet.zig` | getInit()関数 - 62-74行目 |

**主要処理フロー**:
- **91-94行目**: `switchTo()` - active_keyとactiveポインタの更新
- **62-74行目**: `getInit()` - 代替画面の遅延初期化

#### Step 5: リセットとクローンを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Screen.zig | `src/terminal/Screen.zig` | reset()関数 - 367-398行目 |
| 5-2 | Screen.zig | `src/terminal/Screen.zig` | clone()関数 - 431-500行目以降 |

**主要処理フロー**:
- **367-398行目**: `reset()` - DEC RIS相当のリセット処理
- **431-500行目以降**: `clone()` - 読み取り専用コピーの生成

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

```
ScreenSet
    |
    +-- init()
    |      +-- Screen.init()
    |             +-- PageList.init()
    |             +-- trackPin()
    |
    +-- switchTo(key)
    |      +-- active_key = key
    |      +-- active = all.get(key)
    |
    +-- getInit(key)  [代替画面の遅延初期化]
           +-- Screen.init()

Screen
    |
    +-- init()
    |      +-- PageList.init()
    |      +-- pages.trackPin()
    |      +-- kitty_images.setLimit()
    |
    +-- reset()
    |      +-- pages.reset()
    |      +-- cursor.deinit()
    |      +-- kitty_images.deinit()
    |      +-- clearSelection()
    |
    +-- clone()
           +-- pages.clone()
           +-- pin_remap処理
```

### データフロー図

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

初期化パラメータ ──> Screen.init()
   (cols, rows)            |
                          v
                    PageList作成 ───────> pages
                          |
                          v
                    カーソルピン作成 ────> cursor.page_pin
                          |
                          v
                    Screen構造体 ───────> Terminal.screens.active

画面切替要求 ─────> ScreenSet.switchTo()
   (SMCUP/RMCUP)          |
                          v
                    active切り替え ─────> 新しいactive画面

リセット要求 ─────> Screen.reset()
   (DEC RIS)              |
                          v
                    全状態クリア ───────> クリーンなScreen
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Screen.zig | `src/terminal/Screen.zig` | ソース | 画面状態管理のメインロジック |
| ScreenSet.zig | `src/terminal/ScreenSet.zig` | ソース | プライマリ/代替画面の管理 |
| PageList.zig | `src/terminal/PageList.zig` | ソース | ページリスト（実データ）管理 |
| page.zig | `src/terminal/page.zig` | ソース | ページ、行、セルのデータ構造 |
| Selection.zig | `src/terminal/Selection.zig` | ソース | 選択範囲管理 |
| cursor.zig | `src/terminal/cursor.zig` | ソース | カーソルスタイル定義 |
| charsets.zig | `src/terminal/charsets.zig` | ソース | 文字セット定義 |
| kitty.zig | `src/terminal/kitty.zig` | ソース | Kitty拡張統合 |
