# 機能設計書 40-コマンドの選択

## 概要

本ドキュメントは、Windows Terminal における「コマンドの選択」機能（SelectCommand アクション）の設計を記述する。シェル統合機能を使用して、ターミナルバッファ内の前後のコマンドテキストを選択する機能である。

### 本機能の処理概要

**業務上の目的・背景**：シェル統合（Shell Integration）によりターミナルバッファに記録されたコマンドのマーク情報を利用し、個々のコマンドテキストを正確に選択する機能を提供する。従来のテキスト選択では、プロンプト文字列やコマンド出力との境界を正確に判別することが困難であったが、本機能ではシェル統合のマーク情報に基づいて正確にコマンド部分のみを選択できる。

**機能の利用シーン**：ユーザーがキーバインドを押下して、現在位置の前または後ろの最も近いコマンドを選択する。選択したコマンドテキストをコピーして再利用したり、他のツールに貼り付けたりする場合に利用される。コマンド履歴を遡りながら個別のコマンドを選択していくことも可能。

**主要な処理内容**：
1. _HandleSelectCommand で ActionEventArgs を受信し、SelectCommandArgs から方向（Previous/Next）を取得
2. _ApplyToActiveControls で全アクティブコントロールに適用
3. TermControl.SelectCommand → ControlCore.SelectCommand を呼び出し
4. ターミナルバッファからマーク情報（MarkExtents）を取得
5. 現在位置から指定方向で最も近いコマンドマークを検索
6. コマンドの開始（mark.end）から終了（mark.commandEnd）までを選択範囲として設定

**関連システム・外部連携**：シェル統合（Shell Integration）機能が前提。シェル側から OSC エスケープシーケンスでコマンドの境界情報（プロンプト終了、コマンド終了、出力終了）が送信される必要がある。

**権限による制御**：なし。ただし、シェル統合が有効でないシェルではマーク情報が存在しないため、機能が動作しない。

## 関連画面

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

## 機能種別

テキスト操作 / シェル統合連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| Direction | SelectOutputDirection | Yes | 検索方向（Previous: 前のコマンド / Next: 次のコマンド） | Previous または Next（内部では Previous は goUp=true に変換） |

### 入力データソース

- SelectCommandArgs のアクション引数
- ターミナルバッファのマーク情報（GetMarkExtents）
- 現在の選択状態またはカーソル位置

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (なし) | - | コマンドテキストの範囲が選択状態として設定される |

### 出力先

- Terminal の選択範囲

## 処理フロー

### 処理シーケンス

```
1. _HandleSelectCommand が ActionEventArgs を受信
   └─ SelectCommandArgs にキャストして Direction を取得
   └─ Direction == Previous を goUp (bool) に変換
2. _ApplyToActiveControls で全アクティブコントロールに適用
   └─ control.SelectCommand(goUp) を呼び出し
3. TermControl.SelectCommand → ControlCore.SelectCommand
   └─ LockForWriting でロック取得
4. ControlCore.SelectCommand
   └─ 検索開始位置の決定
       ├─ [選択中 + goUp] → GetSelectionAnchor（選択の開始点）
       ├─ [選択中 + !goUp] → GetSelectionEnd（選択の終了点）
       └─ [選択なし] → GetCursor().GetPosition()
   └─ GetMarkExtents() でマーク一覧を取得
   └─ マークが空なら早期リターン
5. 最近傍コマンドマークの検索
   └─ 全マークを走査し、HasCommand() なマークのみ対象
   └─ 距離を計算: goUp ? start - m.end : m.end - start
   └─ 距離が正で最小のマークを nearest として記録
6. nearest が見つかった場合
   └─ _selectSpan で選択範囲を設定
       start = nearest.end, end = nearest.commandEnd
```

### フローチャート

```mermaid
flowchart TD
    A[SelectCommand アクション受信] --> B{SelectCommandArgs 取得成功?}
    B -->|No| Z[何もしない]
    B -->|Yes| C[Direction を goUp に変換]
    C --> D[_ApplyToActiveControls]
    D --> E[ControlCore.SelectCommand]
    E --> F[LockForWriting でロック取得]
    F --> G[検索開始位置の決定]
    G --> H[GetMarkExtents でマーク取得]
    H --> I{マーク一覧が空?}
    I -->|Yes| Z
    I -->|No| J[全マークを走査]
    J --> K{HasCommand?}
    K -->|No| L[次のマークへ]
    K -->|Yes| M[距離を計算]
    M --> N{距離が正かつ最小?}
    N -->|Yes| O[nearest を更新]
    N -->|No| L
    O --> L
    L --> P{全マーク走査完了?}
    P -->|No| J
    P -->|Yes| Q{nearest が見つかった?}
    Q -->|No| Z
    Q -->|Yes| R["_selectSpan(nearest.end, nearest.commandEnd)"]
    R --> S[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-40-01 | シェル統合必須 | マーク情報がない場合（シェル統合未対応のシェル）はコマンド選択ができない | マーク一覧が空 |
| BR-40-02 | コマンドマークのみ | HasCommand() が true のマークのみが検索対象となる | 常に適用 |
| BR-40-03 | 方向指定 | Previous（goUp=true）は現在位置より前方のコマンド、Next は後方のコマンドを検索する | 常に適用 |
| BR-40-04 | 距離計算 | 距離は goUp の場合 start - m.end、そうでない場合 m.end - start で計算される | 常に適用 |
| BR-40-05 | 連続選択 | 選択中の場合は選択のアンカーまたは終了点を起点として次のコマンドを検索する | 選択がアクティブ |
| BR-40-06 | コマンド範囲 | マークの end（プロンプト終了位置）から commandEnd（コマンド入力終了位置）までが選択される | 常に適用 |

### 計算ロジック

- 距離計算: `goUp ? start - m.end : m.end - start`
- 距離比較: `(distance > til::point{0, 0}) && distance < bestDistance`

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | マークなし | シェル統合が無効でマーク情報がない | 何もしない（早期リターン） |
| - | コマンドマークなし | マークは存在するがコマンドを含むマークがない | 何もしない（nearest が見つからない） |
| - | 方向に該当なし | 指定方向に該当するコマンドがない | 何もしない（nearest が見つからない） |

### リトライ仕様

リトライは行わない。

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

ControlCore.SelectCommand の実行中は LockForWriting でロックを保持する。

## パフォーマンス要件

マーク一覧の走査は O(n) であり、マーク数が多い場合の影響は小さい。

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

特になし。

## 備考

- MarkExtents はシェル統合の OSC シーケンスで設定される。各マークは以下の情報を持つ:
  - start: プロンプトの開始位置
  - end: プロンプトの終了位置（= コマンドの開始位置）
  - commandEnd: コマンド入力の終了位置
  - outputEnd: コマンド出力の終了位置
- HasCommand() は commandEnd が有効な値を持つかどうかを確認する
- 類似機能として SelectOutput（No.41）があり、コマンドの出力部分を選択する
- 連続して SelectCommand を実行することで、コマンド履歴を1つずつ遡っていくことが可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | SelectCommandArgs の定義。Direction プロパティ（SelectOutputDirection 列挙） |

**読解のコツ**: SelectOutputDirection は Previous と Next（旧名称 Next）の2値。SelectCommand と SelectOutput で同じ方向列挙型を共有している。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | _HandleSelectCommand がエントリーポイント |

**主要処理フロー**:
1. **1388-1401行目**: SelectCommandArgs へのキャスト、Direction == Previous を bool に変換、_ApplyToActiveControls で全コントロールに control.SelectCommand(goUp) を適用

#### Step 3: TermControl 層

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | SelectCommand で ControlCore に委譲 |

**主要処理フロー**:
- **3865-3868行目**: _core.SelectCommand(goUp) を呼び出す

#### Step 4: ControlCore 層

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | SelectCommand のコアロジック |

**主要処理フロー**:
- **2700-2740行目**: LockForWriting、検索開始位置の決定（選択中はアンカー/終了点、なければカーソル位置）、GetMarkExtents でマーク取得、全マーク走査で距離計算、最近傍コマンドマークの検索、_selectSpan で選択範囲設定

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

```
TerminalPage::_HandleSelectCommand (AppActionHandlers.cpp:1388)
    |
    +-- _ApplyToActiveControls
           |
           +-- TermControl::SelectCommand (TermControl.cpp:3865)
                  |
                  +-- ControlCore::SelectCommand (ControlCore.cpp:2700)
                         |
                         +-- Terminal::IsSelectionActive
                         +-- Terminal::GetSelectionAnchor / GetSelectionEnd
                         +-- Terminal::GetTextBuffer().GetCursor().GetPosition()
                         +-- Terminal::GetMarkExtents
                         +-- MarkExtents::HasCommand
                         +-- _selectSpan
                                |
                                +-- Terminal::SelectNewRegion
```

### データフロー図

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

SelectCommandArgs    --> _HandleSelectCommand              --> goUp (bool) 変換
  (Direction)            |
                         v
カーソル位置/          ControlCore::SelectCommand          --> 検索開始位置
選択状態                 |
                         v
マーク一覧            全マーク走査                         --> 最近傍コマンドマーク
  (MarkExtents)          |
                         v
                     _selectSpan                           --> 選択範囲設定
                      (mark.end → mark.commandEnd)            (コマンドテキスト選択)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | ソース | _HandleSelectCommand アクションハンドラ |
| TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | ソース | SelectCommand の委譲 |
| TermControl.h | `src/cascadia/TerminalControl/TermControl.h` | ヘッダ | SelectCommand 宣言 |
| ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ソース | SelectCommand のコアロジック |
| Terminal.hpp | `src/cascadia/TerminalCore/Terminal.hpp` | ヘッダ | GetMarkExtents / SelectNewRegion 宣言 |
| ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | IDL | SelectCommandArgs / SelectOutputDirection の型定義 |
