# 機能設計書 5-選択とコピー

## 概要

本ドキュメントは、Ghosttyターミナルエミュレータにおけるマウスまたはキーボードでテキストを選択し、クリップボードにコピーする「選択とコピー」機能の設計を記述する。

### 本機能の処理概要

選択とコピー機能は、Selection構造体によって端末画面上のテキスト選択範囲を管理する。選択は開始点と終了点のピンで定義され、通常選択と矩形選択の両モードをサポートする。選択範囲はトラッキングピンを使用してスクロールや画面変更に追従する。

**業務上の目的・背景**：ターミナルユーザーにとって、画面上のテキストをコピーしてコマンドラインや他のアプリケーションに貼り付けることは基本的な操作である。効率的な選択機能とクリップボード連携により、作業の生産性が向上する。矩形選択はログファイルやテーブル形式のデータから特定の列のみを抽出する際に有用である。

**機能の利用シーン**：
- マウスドラッグでテキストを選択しコピーする場面
- ダブルクリックで単語を選択する場面
- トリプルクリックで行全体を選択する場面
- Shift+矢印キーでキーボード選択する場面
- Alt+ドラッグで矩形選択する場面

**主要な処理内容**：
1. 選択範囲の開始点/終了点管理（Bounds構造体）
2. トラッキングピンによる選択位置の追跡
3. 選択方向（forward/reverse）の判定
4. 矩形選択モードの処理
5. 選択範囲のテキスト抽出
6. クリップボードへのコピー

**関連システム・外部連携**：
- Screen構造体との連携
- PageListのピントラッキング機能との連携
- クリップボード操作機能との連携
- マウス操作機能との連携

**権限による制御**：特になし。選択とコピーは全ユーザーに対して同一の動作を提供する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | メインターミナルウィンドウ | 主画面 | マウスまたはキーボードでのテキスト選択とクリップボードへのコピー |

## 機能種別

データ構造管理 / ユーザーインタラクション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| start_pin | Pin | Yes | 選択開始位置 | 有効なピン |
| end_pin | Pin | Yes | 選択終了位置 | 有効なピン |
| rect | bool | No | 矩形選択フラグ | デフォルトfalse |

### 入力データソース

- マウスイベント（クリック、ドラッグ）
- キーボードイベント（Shift+矢印）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| bounds | Bounds | 選択範囲（untracked/tracked） |
| rectangle | bool | 矩形選択フラグ |
| topLeft | Pin | 選択範囲の左上 |
| bottomRight | Pin | 選択範囲の右下 |

### 出力先

- Screen.selection フィールド
- クリップボード（コピー時）

## 処理フロー

### 処理シーケンス

```
1. 選択開始
   └─ init()で開始/終了ピンを設定
   └─ 初期状態はuntracked

2. 選択拡張
   └─ 終了ピンを更新
   └─ 方向（forward/reverse）を自動判定

3. トラッキング変換
   └─ track()でtracked状態に変換
   └─ Screen.pages.trackPin()でピンを登録

4. 選択範囲取得
   └─ topLeft()/bottomRight()で正規化座標取得
   └─ order()で方向を判定

5. テキスト抽出
   └─ 選択範囲内のセルからテキストを抽出

6. クリップボードコピー
   └─ システムクリップボードにテキストを設定

7. 選択解除
   └─ deinit()でピンをアントラック
   └─ Screen.selectionをnullに設定
```

### フローチャート

```mermaid
flowchart TD
    A[マウス/キーボードイベント] --> B{イベント種別}
    B -->|クリック| C[選択開始]
    B -->|ドラッグ| D[選択拡張]
    B -->|リリース| E[選択確定]
    B -->|ダブルクリック| F[単語選択]
    B -->|トリプルクリック| G[行選択]

    C --> H[Selection.init]
    D --> I[endPtr更新]
    E --> J[track]

    H --> K[untracked状態]
    I --> K
    J --> L[tracked状態]

    L --> M{操作}
    M -->|コピー| N[テキスト抽出]
    M -->|解除| O[deinit]
    N --> P[クリップボードへ]
    O --> Q[selection = null]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | トラッキング必須 | 長期保持する選択はtracked状態にする | 選択確定時 |
| BR-002 | 方向自動判定 | forward/reverseは座標比較で自動判定 | 範囲取得時 |
| BR-003 | ミラー選択 | 矩形選択で斜め方向の場合はmirrored状態 | 矩形選択時 |
| BR-004 | ダブルクリック単語 | ダブルクリックで単語境界まで選択を拡張 | ダブルクリック時 |
| BR-005 | トリプルクリック行 | トリプルクリックで行全体を選択 | トリプルクリック時 |

### 計算ロジック

- 選択方向: startとendのピン位置を比較
- 矩形選択: x座標は独立して処理、ミラー状態を考慮

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| E-001 | トラッキング失敗 | ピントラッキング登録失敗 | エラーを呼び出し元に伝播 |

### リトライ仕様

リトライ機構は使用しない。

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

トランザクション処理は使用しない。

## パフォーマンス要件

- 選択操作: O(1)
- テキスト抽出: O(n) - nは選択範囲のセル数

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

- クリップボードへのアクセスはユーザー操作に基づく

## 備考

- 選択範囲はスクロールに追従（トラッキングピン使用）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Selection.zig | `src/terminal/Selection.zig` | Selection構造体、Bounds union |
| 1-2 | Selection.zig | `src/terminal/Selection.zig` | Order enum（forward/reverse/mirrored） |

**読解のコツ**: `Bounds`はuntracked/trackedのタグ付きunionで、trackedはScreen.pages経由でトラッキングされるピンを使用する。

#### Step 2: 主要メソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Selection.zig | `src/terminal/Selection.zig` | init()、deinit()関数 |
| 2-2 | Selection.zig | `src/terminal/Selection.zig` | track()関数 |
| 2-3 | Selection.zig | `src/terminal/Selection.zig` | topLeft()、bottomRight()関数 |

**主要処理フロー**:
- **55-67行目**: `init()` - untracked状態で選択を初期化
- **69-81行目**: `deinit()` - trackedピンのアントラック
- **130-148行目**: `track()` - untracked→tracked変換
- **151-166行目**: `topLeft()` - 選択の左上取得
- **169-184行目**: `bottomRight()` - 選択の右下取得

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

```
Selection
    |
    +-- init(start_pin, end_pin, rect)
    |      +-- untracked Bounds作成
    |
    +-- track(screen)
    |      +-- screen.pages.trackPin(start)
    |      +-- screen.pages.trackPin(end)
    |      +-- tracked Bounds作成
    |
    +-- order(screen)
    |      +-- pointFromPin比較
    |
    +-- topLeft(screen) / bottomRight(screen)
    |      +-- order()呼び出し
    |      +-- 方向に応じてstart/end返却
    |
    +-- deinit(screen)
           +-- screen.pages.untrackPin(start)
           +-- screen.pages.untrackPin(end)
```

### データフロー図

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

マウスクリック ─────> Selection.init()
                           |
                           v
                    untracked Selection
                           |
マウスドラッグ ─────> endPtr更新
                           |
マウスリリース ─────> Selection.track()
                           |
                           v
                    tracked Selection ───> Screen.selection
                           |
コピー操作 ──────────> テキスト抽出
                           |
                           v
                    クリップボード
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Selection.zig | `src/terminal/Selection.zig` | ソース | 選択範囲管理のメインロジック |
| Screen.zig | `src/terminal/Screen.zig` | ソース | 選択を保持するScreen構造体 |
| PageList.zig | `src/terminal/PageList.zig` | ソース | ピントラッキング機能 |
| point.zig | `src/terminal/point.zig` | ソース | ポイント座標定義 |
