# 機能設計書 72-URLコピー

## 概要

本ドキュメントは、Ghosttyターミナルエミュレータにおける「カーソル下のURLをクリップボードにコピーする」機能の設計について記載する。この機能により、ユーザーはマウスカーソル位置にあるハイパーリンク（OSC 8または正規表現によるリンク）のURLを直接クリップボードにコピーできる。

### 本機能の処理概要

**業務上の目的・背景**：
ターミナル上に表示されるURL（ログ出力、エラーメッセージ、ドキュメント参照など）を効率的に取得したい場面は多い。通常はURLを選択してコピーする必要があるが、長いURLの場合は選択が面倒である。本機能を使用することで、マウスをURL上に置いた状態でキーバインドを押すだけでURLをクリップボードにコピーでき、作業効率が向上する。

**機能の利用シーン**：
- ログ出力に含まれるURLをブラウザで開くためにコピーしたい場合
- エラーメッセージ内のドキュメントリンクを共有したい場合
- OSC 8でエンコードされたハイパーリンクのURLを取得したい場合
- 正規表現で検出されたURLをコピーしたい場合

**主要な処理内容**：
1. マウスカーソル位置にリンクが存在するかの判定
2. リンク種別（OSC 8またはregex）の識別
3. リンク種別に応じたURL文字列の取得
4. システムクリップボード（標準）へのコピー

**関連システム・外部連携**：
- OSC 8ハイパーリンクプロトコル（端末内のリンク表現）
- 正規表現リンク検出システム（設定ファイルで定義）
- システムクリップボードAPI

**権限による制御**：
- `clipboard-write`設定により書き込み権限を制御可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | メインターミナルウィンドウ | 主画面 | URLコピー操作の実行 |

## 機能種別

クリップボード操作 / データ取得

## 入力仕様

### 入力パラメータ

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

### 入力データソース

- マウスカーソル位置（スクリーン座標）
- ターミナルバッファ内のリンク情報（OSC 8またはregex検出）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| URL文字列 | [:0]u8 | コピーされるURL（NULL終端） |

### 出力先

- システムクリップボード（standard / CLIPBOARD）

## 処理フロー

### 処理シーケンス

```
1. copy_url_to_clipboardアクション受付
   └─ キーバインドからのトリガー
2. リンク存在チェック
   └─ mouse.over_linkフラグを確認
3. カーソル位置取得
   └─ rt_surface.getCursorPos()を呼び出し
4. リンク情報取得
   └─ linkAtPos(pos)でリンク詳細を取得
5. URL文字列抽出
   └─ リンク種別に応じて処理分岐
      ├─ .open (regex): selectionStringでテキスト取得
      └─ ._open_osc8: osc8URIでURI取得
6. クリップボードへコピー
   └─ rt_surface.setClipboard(.standard, ...)
```

### フローチャート

```mermaid
flowchart TD
    A[copy_url_to_clipboard アクション] --> B{mouse.over_link?}
    B -->|No| C[return false - 何もしない]
    B -->|Yes| D[getCursorPos で位置取得]
    D --> E[renderer_state.mutex.lock]
    E --> F[linkAtPos で リンク情報取得]
    F --> G{リンク取得成功?}
    G -->|No| H[return false]
    G -->|Yes| I{リンク種別?}
    I -->|.open regex| J[selectionString でURL取得]
    I -->|._open_osc8| K[osc8URI でURI取得]
    J --> L{取得成功?}
    K --> L
    L -->|No| M[エラーログ出力]
    L -->|Yes| N[setClipboard でコピー]
    N --> O{コピー成功?}
    O -->|No| P[エラーログ出力]
    O -->|Yes| Q[return true]
    M --> H
    P --> H
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-72-1 | リンク必須 | マウスがリンク上にない場合は何もしない | mouse.over_link == false |
| BR-72-2 | OSC8優先 | OSC 8リンクはURIを直接取得 | link_info.action == ._open_osc8 |
| BR-72-3 | Regex選択 | 正規表現リンクは選択範囲からテキスト取得 | link_info.action == .open |
| BR-72-4 | 末尾空白除去 | clipboard_trim_trailing_spaces設定に従う | 設定有効時 |

### 計算ロジック

該当なし

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | リンクなし | カーソル位置にリンクがない | falseを返して終了 |
| - | URL取得失敗 | selectionStringまたはosc8URIの失敗 | エラーログ出力、falseを返す |
| - | クリップボード書込失敗 | setClipboardの失敗 | エラーログ出力、falseを返す |

### リトライ仕様

リトライは行わない。

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

該当なし

## パフォーマンス要件

- renderer_state.mutexを取得するため、描画との競合に注意
- URL取得は同期処理だが、通常は瞬時に完了

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

- クリップボードへの書き込みは`clipboard-write`設定で制御可能
- コピーされるURLは画面に表示されているものに限定

## 備考

- OSC 8形式: `\033]8;;URL\033\\TEXT\033]8;;\033\\`
- regex形式: 設定ファイルで定義されたパターンにマッチしたテキスト

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Binding.zig | `src/input/Binding.zig` | `copy_url_to_clipboard`アクションの定義 |
| 1-2 | link.zig | `src/renderer/link.zig` | リンク情報の構造体定義 |

**読解のコツ**: リンクには2種類（OSC 8とregex）があり、それぞれ処理が異なる。`action`フィールドで識別する。

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

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

**主要処理フロー**:
1. **5351-5393行目**: `copy_url_to_clipboard`アクションの全処理
2. **5352-5353行目**: `mouse.over_link`チェックでリンク存在確認
3. **5358行目**: `linkAtPos(pos)`でリンク情報取得
4. **5359-5378行目**: リンク種別に応じたURL取得処理
5. **5382-5388行目**: クリップボードへのコピー実行

#### Step 3: リンク検出処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Surface.zig | `src/Surface.zig` | `linkAtPos`関数 |
| 3-2 | hyperlink.zig | `src/terminal/hyperlink.zig` | OSC 8ハイパーリンクの管理 |

**主要処理フロー**:
- リンク位置からリンク情報（種別、選択範囲、アクション）を取得

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

```
performBindingAction (Surface.zig)
    │
    └─ copy_url_to_clipboard
           │
           ├─ getCursorPos() - マウス位置取得
           │
           ├─ linkAtPos(pos) - リンク情報取得
           │      │
           │      ├─ OSC8リンク検索
           │      └─ Regexリンク検索
           │
           ├─ [.open] selectionString() - テキスト取得
           │
           ├─ [._open_osc8] osc8URI() - URI取得
           │
           └─ setClipboard(.standard, ...) - コピー実行
```

### データフロー図

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

キーバインド ───▶ copy_url_to_clipboard
                        │
マウス位置 ─────────────▶ getCursorPos
                        │
                        ▼
                   linkAtPos ──▶ リンク情報
                        │
                        ▼
          ┌─────────────┴─────────────┐
          │                           │
     [regex]                    [OSC 8]
          │                           │
  selectionString              osc8URI
          │                           │
          └──────────┬────────────────┘
                     ▼
               setClipboard ───▶ システムクリップボード
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Surface.zig | `src/Surface.zig` | ソース | メイン処理、copy_url_to_clipboardの実装 |
| Binding.zig | `src/input/Binding.zig` | ソース | アクション定義 |
| command.zig | `src/input/command.zig` | ソース | コマンドパレット定義（162-166行目） |
| hyperlink.zig | `src/terminal/hyperlink.zig` | ソース | OSC 8ハイパーリンク管理 |
| link.zig | `src/renderer/link.zig` | ソース | リンク検出・描画 |
| Config.zig | `src/config/Config.zig` | ソース | link設定（正規表現リンク定義） |
