# 機能設計書 20-キーシーケンス

## 概要

本ドキュメントは、Ghosttyのキーシーケンス機能の設計について記述する。複数のキー入力を連続して行うことでアクションを実行するマルチキーシーケンス機能である。

### 本機能の処理概要

**業務上の目的・背景**：
単一のキーバインドでは表現しきれない操作や、より直感的なキー操作を実現するため、Emacsスタイルのマルチキーシーケンスをサポートする。例えば、`Ctrl+W` の後に `Ctrl+C` を押すことで特定のアクションを実行できる。

**機能の利用シーン**：
- Emacs/Vimスタイルのキー操作
- 複雑なアクションの階層的なグループ化
- リーダーキーによるモード切り替え
- キーテーブルの動的切り替え

**主要な処理内容**：
1. シーケンス文字列のパース（">"で区切り）
2. リーダートリガーの検出
3. 中間状態の管理
4. 最終バインディングの実行
5. チェーンアクションの処理
6. キーテーブルの管理

**関連システム・外部連携**：
- キーバインドシステム
- 設定システム
- 入力システム

**権限による制御**：
特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | メインターミナルウィンドウ | 主画面 | キーシーケンスによる操作 |

## 機能種別

入力処理 / キーシーケンス管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | []const u8 | Yes | キーシーケンス設定文字列 | trigger>trigger=action形式 |

### 入力データソース

- 設定ファイル（keybind設定）

### 構文例

```
# 基本シーケンス
ctrl+w>ctrl+c=copy_to_clipboard     # Ctrl+W → Ctrl+C でコピー
ctrl+w>c=copy_to_clipboard          # Ctrl+W → C でコピー

# 多段シーケンス
ctrl+x>ctrl+s>ctrl+a=select_all     # 3キーシーケンス

# チェーンアクション
ctrl+w>h=goto_split:left            # スプリット移動
chain=goto_split:right              # 前のバインドにチェーン追加

# キーテーブル
ctrl+w=activate_key_table:split     # splitテーブルをアクティブ化
ctrl+w=activate_key_table_once:split # 一度だけアクティブ化

# シーケンス終了
ctrl+w>escape=end_key_sequence      # シーケンス中断
```

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| leaders | []Trigger | リーダートリガー配列 |
| binding | Binding | 最終バインディング |

### 出力先

キーバインドセット

## 処理フロー

### 処理シーケンス

```
1. シーケンスパース
   └─ SequenceIterator で ">" 区切りを解析
2. リーダー検出
   └─ 最終要素以外はリーダーとして登録
3. 最終バインディング生成
   └─ 最終トリガー + アクション
4. シーケンス状態管理
   └─ 現在のリーダー位置を追跡
5. キー入力マッチング
   └─ 現在位置のトリガーと比較
6. アクション実行またはシーケンス進行
   └─ 最終到達時にアクション実行
```

### フローチャート

```mermaid
flowchart TD
    A[キー入力] --> B{シーケンス中?}
    B -->|No| C{リーダーキー?}
    B -->|Yes| D{次のトリガーと一致?}
    C -->|No| E[通常バインド処理]
    C -->|Yes| F[シーケンス開始]
    D -->|No| G{catch_all?}
    D -->|Yes| H{最終トリガー?}
    G -->|No| I[シーケンスリセット、キー送信]
    G -->|Yes| J[catch_allアクション実行]
    H -->|No| K[シーケンス進行]
    H -->|Yes| L[アクション実行]
    F --> M[待機状態]
    K --> M
    L --> N[シーケンス終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | シーケンス制限 | global/allフラグはシーケンス不可 | シーケンスパース時 |
| BR-02 | チェーン制限 | chainにはフラグ不可 | chainパース時 |
| BR-03 | end_key_sequence | シーケンス中断、先行キーを送信 | シーケンス中 |
| BR-04 | catch_all | 未マッチキーを捕捉 | シーケンス中 |
| BR-05 | キーテーブル | 名前付きバインドセットを切り替え | テーブルアクション時 |

### キーテーブル関連アクション

| アクション | 説明 |
|-----------|------|
| activate_key_table:name | 指定テーブルをアクティブ化 |
| activate_key_table_once:name | 一度だけアクティブ化（1キー後に解除） |
| deactivate_key_table | 現在のテーブルを非アクティブ化 |
| deactivate_all_key_tables | 全テーブルを非アクティブ化 |

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| InvalidFormat | パースエラー | global/allとシーケンスの組み合わせ | エラー返却 |
| InvalidFormat | パースエラー | chainにフラグ指定 | エラー返却 |
| UnexpectedSequence | パースエラー | parseSingleでシーケンス検出 | エラー返却 |
| UnexpectedChain | パースエラー | parseSingleでチェーン検出 | エラー返却 |

### リトライ仕様

リトライなし。

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

該当なし

## パフォーマンス要件

- シーケンス状態はサーフェスごとに管理
- リーダーマッチングはO(1)（ハッシュマップ）

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

特になし

## 備考

- Emacs/Tmuxスタイルのシーケンスをサポート
- タイムアウトは現在未実装

---

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

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

### 推奨読解順序

#### Step 1: シーケンスパーサーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Binding.zig | `src/input/Binding.zig` | SequenceIterator構造体（220-240行目） |
| 1-2 | Binding.zig | `src/input/Binding.zig` | SequenceIterator.next関数（228-234行目） |

**読解のコツ**: SequenceIteratorは">"で区切られたトリガー文字列を順にパースするイテレータ。input[i..]でスライスを進めながら解析する。

#### Step 2: Parserのシーケンス処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Binding.zig | `src/input/Binding.zig` | Parser.Elem union（80-92行目） |
| 2-2 | Binding.zig | `src/input/Binding.zig` | Parser.next関数（189-209行目） |
| 2-3 | Binding.zig | `src/input/Binding.zig` | chainフラグ処理（129-144行目） |

**主要処理フロー**:
1. **80-92行目**: Elem enumでleader/binding/chainを区別
2. **189-198行目**: next()でリーダーか最終バインディングかを判定
3. **201行目**: chainの場合はActionのみを返す

#### Step 3: キーテーブルアクションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Binding.zig | `src/input/Binding.zig` | activate_key_tableアクション（869-879行目） |
| 3-2 | Binding.zig | `src/input/Binding.zig` | activate_key_table_onceアクション（881-889行目） |
| 3-3 | Binding.zig | `src/input/Binding.zig` | deactivate_key_tableアクション（891-894行目） |
| 3-4 | Binding.zig | `src/input/Binding.zig` | end_key_sequenceアクション（855-867行目） |

**主要処理フロー**:
- **869-879行目**: 名前付きキーテーブルをアクティブ化
- **881-889行目**: 一度だけアクティブ化（1キー後に自動解除）
- **855-867行目**: シーケンスを中断し、先行キーを端末に送信

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

```
設定ロード
    │
    └─ "ctrl+w>c=copy" パース
           │
           └─ Parser.init()
                  │
                  └─ SequenceIterator構築（input: "ctrl+w>c"）

Parser.next() 呼び出しループ
    │
    ├─ 1回目: SequenceIterator.next() ─▶ "ctrl+w"
    │         ├─ Trigger.parse("ctrl+w")
    │         └─ done() = false ─▶ Elem.leader返却
    │
    └─ 2回目: SequenceIterator.next() ─▶ "c"
              ├─ Trigger.parse("c")
              └─ done() = true ─▶ Elem.binding返却

キー入力時
    │
    ├─ [シーケンス未開始]
    │      └─ Ctrl+Wでリーダーマッチ ─▶ シーケンス開始
    │
    └─ [シーケンス中]
           ├─ Cで最終マッチ ─▶ アクション実行
           │
           ├─ 別のキー ─▶ catch_all確認
           │      ├─ catch_allあり ─▶ catch_allアクション
           │      └─ catch_allなし ─▶ シーケンスリセット
           │
           └─ Escape（end_key_sequence）─▶ Ctrl+Wを送信して終了
```

### データフロー図

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

"ctrl+w>c=copy"
        │
        └─▶ SequenceIterator
                │
                ├─▶ next() ─▶ Trigger{ctrl+w}
                │                 │
                │                 └─▶ Elem.leader
                │
                └─▶ next() ─▶ Trigger{c}
                                  │
                                  └─▶ Elem.binding{
                                         trigger: {c},
                                         action: copy_to_clipboard
                                       }

キー入力フロー:
    Ctrl+W ──▶ リーダーマッチ ──▶ シーケンス状態保存
        │
        C ─────▶ 最終マッチ ────▶ copy_to_clipboard実行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Binding.zig | `src/input/Binding.zig` | ソース | シーケンスパーサーとデータ構造 |
| key.zig | `src/input/key.zig` | ソース | キー定義 |

### シーケンス状態遷移図

```mermaid
stateDiagram-v2
    [*] --> Idle: 初期状態
    Idle --> Sequence: リーダーキー入力
    Sequence --> Sequence: 中間キー入力
    Sequence --> Idle: 最終キー入力（アクション実行）
    Sequence --> Idle: end_key_sequence
    Sequence --> Idle: 無効なキー（リセット）
    Sequence --> TableActive: activate_key_table
    TableActive --> Sequence: テーブル内キー
    TableActive --> Idle: deactivate_key_table
```
