# 機能設計書 61-detect-clipboard

## 概要

本ドキュメントは、Oh My Zshのクリップボード機能における`detect-clipboard`関数の設計を記載する。この関数は、実行環境のプラットフォームを自動検出し、適切なクリップボードコマンドを使用する`clipcopy`および`clippaste`関数を動的に定義する。

### 本機能の処理概要

**業務上の目的・背景**：シェル環境でクリップボード操作を行う場合、macOS、Linux（X11/Wayland）、Windows（Cygwin/WSL）、SSH経由のリモート接続など、プラットフォームによって使用するコマンドが異なる。この機能は、ユーザーがプラットフォームの違いを意識することなく、統一されたインターフェース（`clipcopy`/`clippaste`）でクリップボード操作を実現する。これにより、クロスプラットフォーム対応のスクリプトやワークフローの構築が容易になる。

**機能の利用シーン**：
- コマンドの出力結果をクリップボードにコピーしたい場合（例：`cat file.txt | clipcopy`）
- ファイルの内容をクリップボードにコピーしたい場合（例：`clipcopy file.txt`）
- クリップボードの内容をコマンドにパイプしたい場合（例：`clippaste | grep pattern`）
- クリップボードの内容をファイルに保存したい場合（例：`clippaste > output.txt`）

**主要な処理内容**：
1. 環境変数とコマンドの存在を検査し、プラットフォームを判定する
2. プラットフォームに応じた`clipcopy`と`clippaste`関数を定義する
3. 適切なクリップボードツールが見つからない場合、再試行ロジックを設定する

**関連システム・外部連携**：
- macOS: `pbcopy`, `pbpaste`
- Linux/X11: `xsel`, `xclip`
- Linux/Wayland: `wl-copy`, `wl-paste`
- Windows/Cygwin: `/dev/clipboard`
- Windows/WSL: `clip.exe`, `powershell.exe`
- SSH環境: `lemonade`, `doitclient`
- tmux: `tmux load-buffer`, `tmux save-buffer`
- Android/Termux: `termux-clipboard-set`, `termux-clipboard-get`

**権限による制御**：特になし。ただし、一部のクリップボードツール（xclip、xsel等）はDISPLAY環境変数が設定されている必要がある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLIコマンドのため関連画面なし |

## 機能種別

クリップボード操作 / プラットフォーム検出 / 関数定義

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| なし | - | - | detect-clipboard関数自体はパラメータを受け取らない | - |

### 入力データソース

- 環境変数: `$OSTYPE`, `$WAYLAND_DISPLAY`, `$DISPLAY`, `$TMUX`, `$KONSOLE_PROFILE_NAME`
- コマンド存在確認: `$commands` 連想配列（zsh組み込み）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| clipcopy関数 | function | クリップボードへのコピー関数 |
| clippaste関数 | function | クリップボードからのペースト関数 |
| 戻り値 | integer | 成功時0、クリップボードツール未検出時1 |

### 出力先

- シェル関数として定義（グローバルスコープ）

## 処理フロー

### 処理シーケンス

```
1. プラットフォーム判定開始
   └─ emulate -L zshでローカルオプション設定
2. macOS判定
   └─ $OSTYPE == darwin* かつ pbcopy/pbpaste存在確認
3. Cygwin/MSYS判定
   └─ $OSTYPE == cygwin|msys* で/dev/clipboard使用
4. WSL判定
   └─ clip.exe/powershell.exe存在確認
5. Wayland判定
   └─ $WAYLAND_DISPLAY設定かつwl-copy/wl-paste存在確認
6. X11 (xsel)判定
   └─ $DISPLAY設定かつxsel存在確認
7. X11 (xclip)判定
   └─ $DISPLAY設定かつxclip存在確認
8. lemonade (SSH)判定
   └─ lemonade存在確認
9. doitclient (SSH)判定
   └─ doitclient存在確認
10. win32yank判定
    └─ win32yank存在確認
11. Android/Termux判定
    └─ $OSTYPE == linux-android* かつtermux-clipboard-set存在確認
12. tmux判定
    └─ $TMUX設定かつtmux存在確認
13. フォールバック
    └─ 再試行ロジックを持つ関数を定義し、戻り値1を返す
```

### フローチャート

```mermaid
flowchart TD
    A[detect-clipboard開始] --> B{macOS?}
    B -->|Yes| C[pbcopy/pbpaste定義]
    B -->|No| D{Cygwin/MSYS?}
    D -->|Yes| E[/dev/clipboard定義]
    D -->|No| F{WSL?}
    F -->|Yes| G[clip.exe/powershell定義]
    F -->|No| H{Wayland?}
    H -->|Yes| I[wl-copy/wl-paste定義]
    H -->|No| J{X11+xsel?}
    J -->|Yes| K[xsel定義]
    J -->|No| L{X11+xclip?}
    L -->|Yes| M[xclip定義]
    L -->|No| N{lemonade?}
    N -->|Yes| O[lemonade定義]
    N -->|No| P{doitclient?}
    P -->|Yes| Q[doitclient定義]
    P -->|No| R{win32yank?}
    R -->|Yes| S[win32yank定義]
    R -->|No| T{Android/Termux?}
    T -->|Yes| U[termux-clipboard定義]
    T -->|No| V{tmux?}
    V -->|Yes| W[tmux buffer定義]
    V -->|No| X[再試行ロジック定義]
    C --> Y[return 0]
    E --> Y
    G --> Y
    I --> Y
    K --> Y
    M --> Y
    O --> Y
    Q --> Y
    S --> Y
    U --> Y
    W --> Y
    X --> Z[return 1]
    Y --> AA[終了]
    Z --> AA
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | プラットフォーム優先順位 | macOS > Cygwin > WSL > Wayland > X11(xsel) > X11(xclip) > lemonade > doitclient > win32yank > Termux > tmuxの順で判定 | 常時 |
| BR-02 | 遅延検出 | clipcopy/clippasteの初回呼び出し時にdetect-clipboardを実行 | 初回呼び出し時 |
| BR-03 | 再試行許可 | クリップボードツール未検出時、次回呼び出しで再検出を試行 | 初回検出失敗時 |

### 計算ロジック

該当なし

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

### 操作別データベース影響一覧

該当なし（データベースを使用しない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | プラットフォーム未対応 | 対応するクリップボードツールが見つからない | エラーメッセージを標準エラー出力に表示し、戻り値1を返す |

### リトライ仕様

- 初回検出失敗時、`clipcopy`/`clippaste`呼び出し時に自動的に再検出を試行
- `_retry_clipboard_detection_or_fail`関数により実装

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

該当なし

## パフォーマンス要件

- 関数定義は瞬時（ミリ秒単位）で完了すること
- 遅延評価により、クリップボード機能未使用時のオーバーヘッドを最小化

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

- クリップボードの内容は他のアプリケーションからアクセス可能なため、機密情報の取り扱いに注意
- SSH経由のクリップボード（lemonade/doitclient）使用時はネットワーク経由でデータが転送される

## 備考

- この機能はneovimのクリップボード検出ロジックを参考にしている
- Konsoleではホスト名を含めるとエラーになるため、特別処理がある（omz_termsupport_cwdで使用）

---

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

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

### 推奨読解順序

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

クリップボード機能では複雑なデータ構造は使用しないが、zshの特殊変数と環境変数の理解が重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | clipboard.zsh | `lib/clipboard.zsh` | ファイル冒頭のコメント（1-50行目）で使用可能なプラットフォームとコマンドを確認 |

**読解のコツ**: zshの`$OSTYPE`変数はOSの種類を示す（darwin*, linux*, cygwin*等）。`${+commands[cmd]}`はコマンドの存在確認を行い、存在すれば1、なければ0を返す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | clipboard.zsh | `lib/clipboard.zsh` | 103-107行目の遅延初期化パターンを理解する |

**主要処理フロー**:
1. **103-107行目**: `clipcopy`と`clippaste`のスタブ関数を定義。初回呼び出し時に自身をunfunctionで削除し、detect-clipboardを実行後、本来の関数を呼び出す

```zsh
function clipcopy clippaste {
  unfunction clipcopy clippaste
  detect-clipboard || true
  "$0" "$@"
}
```

#### Step 3: detect-clipboard関数の実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | clipboard.zsh | `lib/clipboard.zsh` | 51-101行目のdetect-clipboard関数本体 |

**主要処理フロー**:
- **51-52行目**: 関数定義とローカルオプション設定
- **54-56行目**: macOS判定とpbcopy/pbpaste関数定義
- **57-59行目**: Cygwin/MSYS判定と/dev/clipboard使用
- **60-62行目**: WSL判定とclip.exe/powershell使用
- **63-65行目**: Wayland判定とwl-copy/wl-paste使用
- **66-68行目**: X11+xsel判定
- **69-71行目**: X11+xclip判定
- **72-74行目**: lemonade（SSH用）判定
- **75-77行目**: doitclient（SSH用）判定
- **78-80行目**: win32yank判定
- **81-83行目**: Android/Termux判定
- **84-86行目**: tmux判定
- **87-99行目**: フォールバック処理（再試行ロジック）

**読解のコツ**:
- 条件分岐は`if-elif-else`ではなく、マッチした時点でreturnせずに関数を定義して終了する
- 各プラットフォーム判定は独立しており、最初にマッチしたものが使用される
- `&>/dev/null &|`はバックグラウンド実行でディスオウン

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

```
clipcopy / clippaste (スタブ関数)
    │
    ├─ unfunction clipcopy clippaste
    │
    ├─ detect-clipboard()
    │      │
    │      ├─ プラットフォーム判定
    │      │      └─ clipcopy / clippaste 関数を再定義
    │      │
    │      └─ 検出失敗時: _retry_clipboard_detection_or_fail 定義
    │
    └─ clipcopy / clippaste (本来の関数) 実行
```

### データフロー図

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

環境変数                    detect-clipboard()
  $OSTYPE ─────────────────▶                                ┌─ clipcopy関数定義
  $WAYLAND_DISPLAY ────────▶  プラットフォーム判定 ─────────▶│
  $DISPLAY ────────────────▶                                └─ clippaste関数定義
  $TMUX ───────────────────▶

$commands配列
  pbcopy, xsel等 ──────────▶  コマンド存在確認

[clipcopy使用時]
stdin / file ──────────────▶ clipcopy() ─────────────────▶ システムクリップボード

[clippaste使用時]
システムクリップボード ────▶ clippaste() ─────────────────▶ stdout
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| clipboard.zsh | `lib/clipboard.zsh` | ソース | クリップボード機能のメイン実装 |
| functions.zsh | `lib/functions.zsh` | ソース | omz_urlencode関数（omz_termsupport_cwdで使用） |
