# 機能設計書 71-選択クリップボード

## 概要

本ドキュメントは、Ghosttyターミナルエミュレータにおける選択クリップボード（X11 Selection Clipboard）機能の設計について記載する。この機能はX11環境特有の「PRIMARY」選択バッファへのアクセスを提供し、テキスト選択時の即座の共有を可能にする。

### 本機能の処理概要

**業務上の目的・背景**：
X11ウィンドウシステムでは、通常のクリップボード（CLIPBOARD）とは別に、PRIMARY選択バッファという機構が存在する。これはテキストを選択した瞬間にその内容がバッファに格納され、中クリックでペーストできる仕組みである。UnixおよびLinuxユーザーにとって馴染み深いワークフローであり、Ghosttyがこの慣例に対応することで、既存のXターミナルユーザーからの移行を容易にする。

**機能の利用シーン**：
- X11/Wayland環境でテキストを選択し、他のアプリケーションへ中クリックでペーストする場合
- 他のアプリケーションで選択されたテキストをGhostty内に中クリックまたはキーバインドでペーストする場合
- `paste_from_selection`アクションをキーバインドに設定して使用する場合

**主要な処理内容**：
1. キーバインドアクション`paste_from_selection`の受付とトリガー
2. アプリケーションランタイム（apprt）を通じた選択クリップボードの読み取り要求
3. 取得したテキストデータのPTYへの書き込み
4. ブラケットペーストモード有効時の適切なエスケープシーケンス付与

**関連システム・外部連携**：
- X11 PRIMARY選択バッファ
- Wayland primary_selection_device_manager プロトコル
- GTKのクリップボードAPI（Linux環境）
- macOS NSPasteboard（選択クリップボードはデフォルトで無効）

**権限による制御**：
- 設定項目`clipboard-read`により、アプリケーションからのクリップボード読み取りを制御可能
- `ask`, `allow`, `deny`の3段階の権限設定

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | メインターミナルウィンドウ | 主画面 | 選択クリップボードからのペースト操作 |
| 6 | クリップボード確認ダイアログ | 参照画面 | クリップボードアクセス確認（設定による） |

## 機能種別

データ連携 / ペースト操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| なし | - | - | アクションパラメータなし | - |

### 入力データソース

- システム選択クリップボード（X11 PRIMARY / Wayland primary_selection）
- GTK/AppKitのクリップボードAPI経由で取得

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ペーストテキスト | []u8 | 選択クリップボードから取得したテキストデータ |
| ブラケット開始 | []u8 | `\x1b[200~`（ブラケットペーストモード時） |
| ブラケット終了 | []u8 | `\x1b[201~`（ブラケットペーストモード時） |

### 出力先

- PTY（擬似端末）へのデータ書き込み

## 処理フロー

### 処理シーケンス

```
1. キーバインドアクション受付
   └─ paste_from_selectionアクションがトリガーされる
2. クリップボード要求開始
   └─ startClipboardRequest(.selection, .paste)を呼び出し
3. ランタイムへのクリップボード読み取り要求
   └─ rt_surface.setClipboard経由でOS APIを呼び出し
4. クリップボードデータ取得（非同期）
   └─ OSからのコールバックでデータを受信
5. ペースト処理
   └─ ブラケットペーストモードに応じてデータをPTYに送信
```

### フローチャート

```mermaid
flowchart TD
    A[paste_from_selection アクション] --> B[startClipboardRequest]
    B --> C{クリップボード読み取り許可?}
    C -->|allow| D[選択クリップボード読み取り]
    C -->|ask| E[確認ダイアログ表示]
    C -->|deny| F[処理中断]
    E -->|許可| D
    E -->|拒否| F
    D --> G{データ取得成功?}
    G -->|Yes| H{ブラケットペーストモード?}
    G -->|No| I[エラーログ]
    H -->|Yes| J[ブラケット付きでPTY送信]
    H -->|No| K[そのままPTY送信]
    J --> L[終了]
    K --> L
    I --> L
    F --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-71-1 | 選択クリップボード分離 | 選択クリップボードは標準クリップボードとは独立したバッファである | X11/Wayland環境 |
| BR-71-2 | プラットフォーム対応 | macOSでは選択クリップボードは標準クリップボードにフォールバック可能 | macOS環境 |
| BR-71-3 | ブラケットペースト | 端末がブラケットペーストモードの場合、エスケープシーケンスで囲む | モード有効時 |

### 計算ロジック

該当なし

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

該当なし（ローカルメモリおよびOS APIのみ使用）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | クリップボード空 | 選択クリップボードにデータがない | 何もしない |
| - | 権限拒否 | clipboard-read設定がdeny | ログ出力して処理中断 |
| - | 取得失敗 | OS APIエラー | エラーログ出力 |

### リトライ仕様

リトライは行わない。ユーザーによる再操作を想定。

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

該当なし

## パフォーマンス要件

- クリップボード読み取りは非同期で行われ、UIをブロックしない
- 大量のテキストペースト時もストリーミング処理により応答性を維持

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

- `clipboard-read`設定によりアプリケーションからのクリップボードアクセスを制御
- 安全でないペースト（改行を含む等）の場合は確認ダイアログを表示可能
- セキュア入力モード中はペースト内容のログ記録を抑制

## 備考

- X11のPRIMARY選択は、テキスト選択時に自動的に格納される仕組み
- Waylandでは`primary_selection`プロトコルを使用
- macOSでは選択クリップボードの概念がないため、設定により標準クリップボードを使用

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Binding.zig | `src/input/Binding.zig` | `paste_from_selection`アクションの定義（727行目付近） |
| 1-2 | surface.zig | `src/apprt/surface.zig` | Message union内のクリップボード関連メッセージ構造 |

**読解のコツ**: Zigのunion型は値を1つだけ持てるタグ付き共用体。`Message`のケースごとにどんなデータが渡されるか確認する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Surface.zig | `src/Surface.zig` | `performBindingAction`関数内の`paste_from_selection`ケース |

**主要処理フロー**:
1. **5407-5410行目**: `paste_from_selection`アクションの処理。`startClipboardRequest`を`.selection`タイプで呼び出し

#### Step 3: クリップボード要求処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Surface.zig | `src/Surface.zig` | `startClipboardRequest`関数の実装 |

**主要処理フロー**:
- クリップボードタイプ（`.selection`）と目的（`.paste`）を指定してランタイムに要求

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

```
performBindingAction (Surface.zig)
    │
    └─ paste_from_selection
           │
           └─ startClipboardRequest(.selection, .paste)
                  │
                  └─ rt_surface.setClipboard (apprt経由)
                         │
                         ├─ GTK: gdk_clipboard_read (Linux)
                         │
                         └─ AppKit: NSPasteboard (macOS)
```

### データフロー図

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

キーバインド ───▶ paste_from_selection ───▶ startClipboardRequest
                                                    │
OS選択クリップ ◀────────────────────────────────────┘
ボード                                              │
    │                                               ▼
    └────────────────────────▶ clipboardCallback ───▶ PTY書き込み
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Surface.zig | `src/Surface.zig` | ソース | メイン処理、クリップボード要求の開始 |
| Binding.zig | `src/input/Binding.zig` | ソース | アクション定義（paste_from_selection） |
| command.zig | `src/input/command.zig` | ソース | コマンドパレット用のコマンド定義 |
| surface.zig | `src/apprt/surface.zig` | ソース | Messageの定義 |
| application.zig | `src/apprt/gtk/class/application.zig` | ソース | GTK向けクリップボード実装 |
| SurfaceView_AppKit.swift | `macos/Sources/Ghostty/Surface View/SurfaceView_AppKit.swift` | ソース | macOS向けクリップボード実装 |
