# 機能設計書 65-Windowspty

## 概要

本ドキュメントは、GhosttyターミナルエミュレータにおけるWindows擬似コンソール（ConPTY）管理機能の設計を記述する。

### 本機能の処理概要

Windows pty機能は、Windows上でシェルやコマンドを実行するためのConPTY（Console Pseudo Terminal）を作成・管理する機能である。ConPTYはWindows 10以降で導入された機能で、POSIX PTYに相当する機能をWindowsで提供する。名前付きパイプを使用してターミナルエミュレータとコンソールアプリケーション間の通信を実現する。

**業務上の目的・背景**：従来のWindowsではターミナルエミュレーションは複雑で、各アプリケーションが独自の実装を必要としていた。ConPTYの導入により、POSIXライクなPTYインターフェースがWindowsでも利用可能になり、クロスプラットフォームなターミナルエミュレータの実装が容易になった。GhosttyはConPTYを活用することで、Windows上でも高品質なターミナル体験を提供する。

**機能の利用シーン**：
- Windows上でGhosttyウィンドウ/タブ/スプリット作成時のシェル起動
- cmd.exe、PowerShell、WSLなどのコンソールアプリケーション実行
- Windowsネイティブコマンドの実行

**主要な処理内容**：
1. 名前付きパイプの作成（入力用・出力用）
2. CreatePseudoConsole()によるConPTYの作成
3. ウィンドウサイズの設定と変更
4. パイプを介した入出力処理
5. ConPTYのリサイズ処理

**関連システム・外部連携**：
- Windows API: CreateNamedPipeW, CreatePipe, CreatePseudoConsole, ResizePseudoConsole
- libxev: 非同期I/O処理（IOCPバックエンド）

**権限による制御**：特になし（通常のユーザー権限で動作）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はバックグラウンドで動作し、特定の画面UIは持たない |

## 機能種別

システムリソース管理 / プロセス間通信

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ws_row | u16 | No | 端末の行数（デフォルト100） | 正の整数 |
| ws_col | u16 | No | 端末の列数（デフォルト80） | 正の整数 |
| ws_xpixel | u16 | No | 端末のピクセル幅（デフォルト800） | 正の整数 |
| ws_ypixel | u16 | No | 端末のピクセル高さ（デフォルト600） | 正の整数 |

### 入力データソース

- レンダラー: ウィンドウサイズ変更時のサイズ情報
- 設定ファイル: 初期ウィンドウサイズ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| in_pipe | HANDLE | 入力パイプ（ターミナル→PTY） |
| out_pipe | HANDLE | 出力パイプ（PTY→ターミナル） |
| in_pipe_pty | HANDLE | PTY側入力ハンドル |
| out_pipe_pty | HANDLE | PTY側出力ハンドル |
| pseudo_console | HPCON | 擬似コンソールハンドル |
| size | winsize | 現在のウィンドウサイズ |

### 出力先

- in_pipe/out_pipe: ターミナルエミュレータ側で使用
- in_pipe_pty/out_pipe_pty: 子プロセス（シェル）側で使用
- pseudo_console: ConPTY制御用

## 処理フロー

### 処理シーケンス

```
1. パイプ名生成
   └─ プロセスIDとカウンターから一意なパイプ名を生成
   └─ 形式: "\\.\pipe\LOCAL\ghostty-pty-{pid}-{counter}"

2. 入力パイプ作成
   └─ CreateNamedPipeW()で名前付きパイプ作成
   └─ FILE_FLAG_OVERLAPPEDで非同期対応
   └─ CreateFileW()でPTY側ハンドル作成

3. 出力パイプ作成
   └─ CreatePipe()で匿名パイプ作成

4. ハンドル継承設定
   └─ SetHandleInformation()で全ハンドルの継承を無効化

5. ConPTY作成
   └─ CreatePseudoConsole()でPTY作成
   └─ サイズとパイプハンドルを指定

6. サイズ変更
   └─ ResizePseudoConsole()でリサイズ

7. クリーンアップ
   └─ 全ハンドルをCloseHandle()
   └─ ClosePseudoConsole()でPTY破棄
```

### フローチャート

```mermaid
flowchart TD
    A[WindowsPty.open] --> B[パイプ名生成]
    B --> C[CreateNamedPipeW - 入力パイプ]
    C --> D{成功?}
    D -->|No| E[Unexpected error]
    D -->|Yes| F[CreateFileW - PTY側入力]
    F --> G{成功?}
    G -->|No| E
    G -->|Yes| H[CreatePipe - 出力パイプ]
    H --> I{成功?}
    I -->|No| E
    I -->|Yes| J[SetHandleInformation x4]
    J --> K[CreatePseudoConsole]
    K --> L{成功?}
    L -->|No| E
    L -->|Yes| M[PTY準備完了]

    N[setSize] --> O[ResizePseudoConsole]
    O --> P{成功?}
    P -->|No| Q[ResizeFailed]
    P -->|Yes| R[サイズ更新完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-65-01 | 名前付きパイプ使用 | 入力には名前付きパイプを使用（非同期I/O対応のため） | 常時 |
| BR-65-02 | 匿名パイプ使用 | 出力にはCreatePipe匿名パイプを使用 | 常時 |
| BR-65-03 | 継承無効化 | 全パイプハンドルの継承を無効化 | 常時 |
| BR-65-04 | サイズキャッシュ | 最後に設定したサイズを内部で保持 | getSize対応 |

### 計算ロジック

パイプ名のカウンターはプロセス全体でアトミックにインクリメントされる（`pipe_name_counter.fetchAdd(1, .monotonic)`）。

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

該当なし（本機能はデータベースを使用しない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| Unexpected | システムエラー | パイプ作成失敗、ConPTY作成失敗 | GetLastError()の情報を含めてエラー返却 |
| ResizeFailed | システムエラー | ResizePseudoConsole失敗 | エラーを呼び出し元に返す |

### リトライ仕様

該当なし（システムコールの失敗は即座にエラー返却）

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

該当なし

## パフォーマンス要件

- PTY作成は高速に完了すること（通常はミリ秒以下）
- サイズ変更は即座に反映されること
- 名前付きパイプはFILE_FLAG_OVERLAPPEDで非同期I/Oに対応

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

- 名前付きパイプは`LOCAL\`プレフィックスでローカルアクセスに限定
- SECURITY_ATTRIBUTESでbInheritHandle=FALSEを設定
- SetHandleInformationで明示的に継承を無効化

## 備考

- 名前付きパイプを使用する理由: CreatePipeで作成された匿名パイプは非同期操作をサポートしないため、libxevのIOCPバックエンドが動作しない
- Windows 10 1809以降でConPTYが利用可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | pty.zig | `src/pty.zig` | winsize構造体（11-16行目） |
| 1-2 | pty.zig | `src/pty.zig` | WindowsPty構造体フィールド（255-268行目） |

**読解のコツ**: WindowsPtyはPosixPtyと異なり、サイズ情報をキャッシュとして保持している。これはWindowsのConPTYがサイズ取得APIを提供しないためである。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | pty.zig | `src/pty.zig` | WindowsPty構造体定義（255-401行目） |
| 2-2 | pty.zig | `src/pty.zig` | open関数（273-371行目） |

**主要処理フロー**:
1. **261行目**: pipe_name_counterのアトミックカウンター
2. **278-292行目**: パイプ名の生成（UTF-8→UTF-16変換含む）
3. **300-311行目**: CreateNamedPipeWで入力パイプ作成
4. **318-326行目**: CreateFileWでPTY側入力ハンドル取得
5. **347-349行目**: CreatePipeで出力パイプ作成
6. **355-358行目**: SetHandleInformationで継承無効化
7. **360-367行目**: CreatePseudoConsole呼び出し

#### Step 3: サイズ変更処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pty.zig | `src/pty.zig` | setSize関数（392-400行目） |
| 3-2 | pty.zig | `src/pty.zig` | getSize関数（385-387行目） |

**主要処理フロー**:
- **393-396行目**: ResizePseudoConsole呼び出し（COORD構造体使用）
- **399行目**: 内部サイズキャッシュ更新

#### Step 4: クリーンアップを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | pty.zig | `src/pty.zig` | deinit関数（373-380行目） |

**主要処理フロー**:
- **374-377行目**: 全パイプハンドルのCloseHandle
- **378行目**: ClosePseudoConsole

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

```
Ghosttyプロセス
    │
    └─ WindowsPty.open(winsize)
           │
           ├─ pipe_name_counter.fetchAdd (アトミックインクリメント)
           │
           ├─ CreateNamedPipeW() [名前付きパイプ作成]
           │      └─ in_pipe取得
           │
           ├─ CreateFileW() [パイプオープン]
           │      └─ in_pipe_pty取得
           │
           ├─ CreatePipe() [匿名パイプ作成]
           │      └─ out_pipe, out_pipe_pty取得
           │
           ├─ SetHandleInformation() x4 [継承無効化]
           │
           └─ CreatePseudoConsole()
                  └─ pseudo_console取得

WindowsPty.setSize(winsize)
    │
    └─ ResizePseudoConsole()
           └─ ConPTYサイズ変更

WindowsPty.deinit()
    │
    ├─ CloseHandle() x4
    │
    └─ ClosePseudoConsole()
```

### データフロー図

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

winsize構造体 ────────▶ パイプ名生成 ───▶ "\\.\pipe\LOCAL\ghostty-pty-..."
(rows, cols)                │
                            ▼
                   CreateNamedPipeW ───▶ in_pipe (HANDLE)
                            │
                            ▼
                   CreateFileW ────────▶ in_pipe_pty (HANDLE)
                            │
                            ▼
                   CreatePipe ─────────▶ out_pipe, out_pipe_pty
                            │
                            ▼
                   CreatePseudoConsole ───▶ pseudo_console (HPCON)

キー入力 ────────▶ in_pipe ───▶ ConPTY ───▶ 子プロセス

子プロセス出力 ──▶ out_pipe_pty ───▶ ConPTY ───▶ out_pipe ───▶ ターミナル表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| pty.zig | `src/pty.zig` | ソース | Windows PTY実装（255-401行目） |
| windows.zig | `src/os/windows.zig` | ソース | Windows API定義・ラッパー |
| Termio.zig | `src/termio/Termio.zig` | ソース | PTYを使用するターミナルIO |
