# 機能設計書 41-出力の選択

## 概要

本ドキュメントは、Windows Terminal における「出力の選択（SelectOutput）」機能の設計を記述する。シェル統合機能と連携し、コマンドの出力テキスト領域をプログラム的に選択する機能である。

### 本機能の処理概要

シェル統合（Shell Integration）により検出されたコマンドマーク情報を活用し、ユーザーが前方または後方のコマンド出力テキスト領域を自動的に選択できるようにする機能である。

**業務上の目的・背景**：ターミナル上でコマンドを実行した後、その出力結果をコピーしたり加工したりするために、出力部分だけを正確に選択する必要がある場面は多い。手動でマウスドラッグやShift+矢印キーで選択する場合、長い出力や複数コマンドが混在する場面では正確な範囲指定が困難になる。本機能はシェル統合のマーク情報を活用して、コマンド出力の開始位置（commandEnd）から終了位置（outputEnd）までを自動的に選択することで、この課題を解決する。

**機能の利用シーン**：
- コマンド実行結果を正確にコピーしたい場合
- 複数コマンドの出力から特定のコマンドの結果だけを取り出したい場合
- 出力結果を別のツールや文書に貼り付けるために選択する場合
- コンテキストメニューから右クリック位置のコマンド出力を選択する場合

**主要な処理内容**：
1. ユーザーのアクション（キーバインドまたはコンテキストメニュー）を受け付ける
2. 現在のカーソル位置または選択位置を基準点として取得する
3. シェル統合マーク（MarkExtents）の一覧から最も近い出力マークを検索する
4. 該当する出力領域（commandEnd〜outputEnd）をテキスト選択状態にする

**関連システム・外部連携**：シェル統合（OSC 133エスケープシーケンス）によりシェル側からコマンド境界情報が送信される必要がある。シェル統合が有効でない場合、マーク情報が存在しないため本機能は動作しない。

**権限による制御**：特になし。シェル統合が有効であれば誰でも利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | TermControl（ターミナル表示） | 主画面 | SelectOutputHandlerによりシェル統合でコマンド出力を選択 |
| 1 | TerminalPage（メイン画面） | 主画面 | _HandleSelectOutputによりアクションを処理 |

## 機能種別

テキスト選択操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| Direction | SelectOutputDirection | No | 選択方向（Previous/Next）。デフォルトはPrevious | 列挙値のみ（Previous=0, Next=1） |

### 入力データソース

- アクション引数（SelectOutputArgs）: キーバインド設定またはコマンドパレットからのDirection指定
- コンテキストメニュー: 右クリック位置（_contextMenuBufferPosition）から出力を選択
- カーソル位置 / 選択範囲: 現在の選択状態（アンカー/エンド）またはカーソル位置が基準点となる

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 選択範囲 | til::point_span | コマンド出力の開始位置（commandEnd）から終了位置（outputEnd）までの範囲 |

### 出力先

ターミナルコントロール上のテキスト選択状態として反映される。選択されたテキストはその後コピー操作等で利用可能になる。

## 処理フロー

### 処理シーケンス

```
1. ユーザーがSelectOutputアクションを実行（キーバインドまたはコンテキストメニュー）
   └─ AppActionHandlers.cppの_HandleSelectOutputが呼ばれる
2. アクション引数からDirectionを取得
   └─ SelectOutputArgs::Direction() でPrevious/Nextを判定
3. _ApplyToActiveControlsを通じてTermControl::SelectOutputを呼び出す
   └─ goUpパラメータに変換（Previous=true, Next=false）
4. ControlCore::SelectOutputが実行される
   └─ ターミナルの書き込みロックを取得
5. 基準点を決定
   └─ 選択がアクティブな場合: goUpならSelectionAnchor、そうでなければSelectionEnd
   └─ 選択が非アクティブな場合: カーソル位置
6. マーク一覧を取得し、最近接の出力マークを検索
   └─ HasOutput()がtrueのマークのみを対象
   └─ 基準点からの距離が最も近いマークを選択
7. 該当マークが見つかった場合、出力領域を選択
   └─ _selectSpanで commandEnd〜outputEnd の範囲を選択
```

### フローチャート

```mermaid
flowchart TD
    A[SelectOutputアクション発火] --> B[Direction取得]
    B --> C[TermControl::SelectOutput呼び出し]
    C --> D[ControlCore::SelectOutput実行]
    D --> E{選択がアクティブ?}
    E -->|Yes| F{goUp?}
    E -->|No| G[カーソル位置を基準点に]
    F -->|Yes| H[SelectionAnchorを基準点に]
    F -->|No| I[SelectionEndを基準点に]
    H --> J[マーク一覧取得]
    I --> J
    G --> J
    J --> K[HasOutputのマークをフィルタ]
    K --> L[基準点から最近接マークを検索]
    L --> M{マークが見つかった?}
    M -->|Yes| N[commandEnd〜outputEnd を選択]
    M -->|No| O[何もしない]
    N --> P[終了]
    O --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-41-01 | シェル統合必須 | シェル統合が有効でマーク情報が存在する場合のみ動作する | 常時 |
| BR-41-02 | 出力マーク必須 | HasOutput()がtrueのマーク（outputEndがcommandEndと異なる）のみ対象 | マーク検索時 |
| BR-41-03 | 最近接選択 | 基準点から最も距離が近いマークが選択される | 複数マーク存在時 |
| BR-41-04 | 方向指定 | Previous（上方向）は基準点より前のマーク、Next（下方向）は基準点より後のマークを対象とする | Direction指定時 |
| BR-41-05 | デフォルト方向 | Direction未指定時はPrevious（上方向）がデフォルト | Direction省略時 |

### 計算ロジック

距離計算: `goUp ? start - *m.commandEnd : *m.commandEnd - start`
- goUp=true の場合、基準点から上方向へ commandEnd までの距離を計算
- goUp=false の場合、commandEnd から基準点までの距離を計算
- 距離が (0,0) より大きく、かつ最小の距離を持つマークを「最近接」と判定

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

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

本機能ではデータベース操作は行わない。すべてインメモリのバッファ操作である。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 無操作 | シェル統合が無効（マークが存在しない） | 何も起こらずに終了 |
| - | 無操作 | 基準点付近に出力を持つマークが存在しない | 何も起こらずに終了 |
| - | 無操作 | アクション引数がSelectOutputArgsにキャストできない | 何も起こらずに終了 |

### リトライ仕様

リトライは不要。ユーザーが再度アクションを実行することで再試行される。

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

ターミナルの書き込みロック（LockForWriting）を取得して処理を行う。選択操作はアトミックに実行され、ロールバックは不要。

## パフォーマンス要件

マーク一覧の線形探索であるため、マーク数が極端に多くない限り応答は即時（数ミリ秒以内）。

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

特になし。ローカルのバッファ内テキストの選択操作のみであり、外部通信やファイルアクセスは行わない。

## 備考

- コンテキストメニューからの選択（ContextMenuSelectOutput）は、右クリック位置に基づいて直接マークを特定するため、キーバインドによるSelectOutputとは異なるロジックを使用する。
- ShouldShowSelectOutput() により、コンテキストメニューの「出力を選択」ボタンの表示/非表示が制御される。

---

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

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

### 推奨読解順序

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

まず、シェル統合マークのデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Marks.hpp | `src/buffer/out/Marks.hpp` | MarkExtents構造体の定義。start/end/commandEnd/outputEndフィールドとHasOutput()メソッド |
| 1-2 | ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | SelectOutputDirection列挙型（Previous=0, Next=1）とSelectOutputArgsの定義 |
| 1-3 | ActionArgs.h | `src/cascadia/TerminalSettingsModel/ActionArgs.h` | SELECT_OUTPUT_ARGSマクロによるSelectOutputArgsの実装。デフォルトDirection=Previous |

**読解のコツ**: MarkExtents構造体では、Promptはstart〜end、Commandはend〜commandEnd、Outputはcommand〜outputEndという領域区分になっている。HasOutput()はoutputEndが存在し且つcommandEndと異なる場合にtrueを返す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | _HandleSelectOutput関数がアクションのエントリーポイント |

**主要処理フロー**:
1. **1402-1415行目**: _HandleSelectOutput - アクション引数をSelectOutputArgsにキャストし、Directionに応じてgoUpフラグを算出、_ApplyToActiveControlsでcontrol.SelectOutputを呼び出す

#### Step 3: TermControl層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | SelectOutput関数が_core.SelectOutputに委譲する薄いラッパー（3870-3873行目） |
| 3-2 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | _SelectOutputHandler - コンテキストメニュー経由の出力選択（4108-4114行目） |

#### Step 4: ControlCore層（コアロジック）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | SelectOutput関数 - マーク検索と出力領域選択のコアロジック（2742-2776行目） |
| 4-2 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | _selectSpan - 選択範囲をターミナルに反映するヘルパー（2690-2698行目） |
| 4-3 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ContextMenuSelectOutput - コンテキストメニュー用の出力選択（2867-2873行目） |
| 4-4 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ShouldShowSelectOutput - コンテキストメニュー表示判定（2923-2928行目） |

**主要処理フロー**:
- **2742-2747行目**: 書き込みロック取得、基準点決定（選択アクティブならanchor/end、非アクティブならカーソル位置）
- **2749-2767行目**: マーク一覧を走査し、HasOutput()がtrueで距離が最小のマークを特定
- **2770-2775行目**: 見つかったマークのcommandEnd〜outputEndを_selectSpanで選択

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

```
TerminalPage::_HandleSelectOutput (AppActionHandlers.cpp:1402)
    │
    ├─ SelectOutputArgs::Direction() → goUpフラグ算出
    │
    └─ _ApplyToActiveControls
           └─ TermControl::SelectOutput (TermControl.cpp:3870)
                  └─ ControlCore::SelectOutput (ControlCore.cpp:2742)
                         ├─ _terminal->LockForWriting()
                         ├─ _terminal->GetMarkExtents()
                         ├─ MarkExtents::HasOutput() でフィルタ
                         └─ _selectSpan (ControlCore.cpp:2690)
                                └─ _terminal->SelectNewRegion()

TermControl::_SelectOutputHandler (TermControl.cpp:4108)  [コンテキストメニュー経由]
    └─ ControlCore::ContextMenuSelectOutput (ControlCore.cpp:2867)
           └─ _contextMenuSelectMark
                  └─ _selectSpan
```

### データフロー図

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

SelectOutputArgs      →  _HandleSelectOutput          →  テキスト選択状態
  (Direction)              ├─ goUpフラグ変換               (バッファ上の
                           └─ TermControl::SelectOutput     commandEnd〜outputEnd
                                └─ ControlCore::SelectOutput  領域が選択される)
                                     ├─ 基準点決定
                                     ├─ マーク検索
                                     └─ _selectSpan

コンテキストメニュー  →  _SelectOutputHandler         →  テキスト選択状態
  (右クリック位置)         └─ ContextMenuSelectOutput     (クリック位置の
                                └─ _contextMenuSelectMark   出力領域が選択される)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | ソース | アクションハンドラーのエントリーポイント |
| TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | ソース | TermControlレベルのSelectOutput実装とコンテキストメニューハンドラー |
| TermControl.h | `src/cascadia/TerminalControl/TermControl.h` | ヘッダー | TermControl::SelectOutputの宣言 |
| ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ソース | SelectOutputのコアロジック |
| ControlCore.h | `src/cascadia/TerminalControl/ControlCore.h` | ヘッダー | ControlCore::SelectOutputの宣言 |
| Marks.hpp | `src/buffer/out/Marks.hpp` | ヘッダー | MarkExtents構造体の定義 |
| ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | IDL | SelectOutputArgs/SelectOutputDirectionの定義 |
| ActionArgs.h | `src/cascadia/TerminalSettingsModel/ActionArgs.h` | ヘッダー | SelectOutputArgsの実装 |
| AllShortcutActions.h | `src/cascadia/TerminalSettingsModel/AllShortcutActions.h` | ヘッダー | SelectOutputアクションの登録 |
| TermControl.xaml | `src/cascadia/TerminalControl/TermControl.xaml` | XAML | コンテキストメニューのSelectOutputButtonの定義 |
