# 機能設計書 8-指定タブに切り替え

## 概要

本ドキュメントは、Windows Terminal における「指定タブに切り替え」機能の設計を記述する。インデックスを指定して特定のタブにフォーカスを移動する機能の詳細を定義する。

### 本機能の処理概要

**業務上の目的・背景**：多数のタブを開いて作業する際、特定のタブに素早くジャンプする手段が必要である。この機能は、タブのインデックス番号を指定して直接切り替えることで、順序通りにたどる必要なく目的のタブに到達できるようにする。キーボードショートカット（Alt+1〜Alt+9等）と組み合わせて使用されることが多い。

**機能の利用シーン**：キーボードショートカットで特定番号のタブに直接切り替える場合に使用される。一般的には Alt+1 で1番目のタブ、Alt+2 で2番目のタブ、といったキーバインドが設定される。また、コマンドパレットのタブスイッチャーで選択されたタブへの切り替えでも使用される。

**主要な処理内容**：
1. SwitchToTab アクションの受信と引数（SwitchToTabArgs）の解析
2. 指定されたタブインデックスの取得
3. _SelectTab によるフォーカスの移動（インデックスのクランプ付き）

**関連システム・外部連携**：特になし。

**権限による制御**：特別な権限制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | TerminalPage（メイン画面） | 主画面 | _HandleSwitchToTab によりインデックス指定でタブ切り替え |

## 機能種別

ナビゲーション操作（タブフォーカスの移動）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| TabIndex | UInt32 | Yes | 切り替え先のタブインデックス（0始まり） | _SelectTab 内で 0 以上 _tabs.Size()-1 以下にクランプされる |

### 入力データソース

- アクション引数: SwitchToTabArgs 経由の TabIndex
- UIイベント: コマンドパレットのタブスイッチャーでの選択

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (なし) | - | 指定されたインデックスのタブにフォーカスが移動する |

### 出力先

- TabView のフォーカスが指定タブに移動

## 処理フロー

### 処理シーケンス

```
1. _HandleSwitchToTab がアクションイベントを受信
   └─ SwitchToTabArgs から TabIndex を取得
2. _SelectTab(TabIndex) の呼び出し
   └─ インデックスのクランプ: std::clamp(tabIndex, 0u, _tabs.Size() - 1)
   └─ 指定インデックスのタブオブジェクトを取得
   └─ TabView の SelectedItem を設定
3. フォーカスの設定
   └─ 起動中の場合: _UpdatedSelectedTab で即座に設定
   └─ 起動後の場合: _SetFocusedTab で非同期的に設定
```

### フローチャート

```mermaid
flowchart TD
    A[_HandleSwitchToTab 受信] --> B[SwitchToTabArgs から TabIndex 取得]
    B --> C[_SelectTab TabIndex]
    C --> D[インデックスをクランプ]
    D --> E[タブオブジェクトを取得]
    E --> F[TabView.SelectedItem を設定]
    F --> G{起動中?}
    G -->|Yes| H[_UpdatedSelectedTab]
    G -->|No| I[_SetFocusedTab]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | インデックスクランプ | 指定されたインデックスが範囲外の場合、有効範囲 [0, _tabs.Size()-1] にクランプされる | 常時 |
| BR-02 | 起動時の即時設定 | 起動中（InStartup）の場合、_UpdatedSelectedTab で即座にタブを設定する | _startupState == StartupState::InStartup |
| BR-03 | 起動後の非同期設定 | 起動完了後は _SetFocusedTab でフォーカスを設定する | 起動完了後 |
| BR-04 | TabView 先行設定 | GH#11107 対応として、まず TabView.SelectedItem を直接設定し、後続の _GetFocusedTab 呼び出しで正しいタブが返されるようにする | 常時 |

### 計算ロジック

インデックスのクランプ：
- `tabIndex = std::clamp(tabIndex, 0u, _tabs.Size() - 1)`

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

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし |

### テーブル別操作詳細

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| (なし) | 範囲外インデックス | TabIndex が _tabs.Size() 以上 | 自動的に _tabs.Size()-1 にクランプされる |

### リトライ仕様

リトライは行わない。

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

トランザクション管理は不要。

## パフォーマンス要件

タブ切り替えはキーボードショートカットに応じて即座に実行される必要がある。

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

特別なセキュリティ考慮事項はない。

## 備考

- GH#9369: 以前は範囲外のインデックスを黙って無視していたが、現在はクランプして最も近い有効なタブに切り替える
- GH#11107: TabView.SelectedItem を先に設定することで、複数アクションの連続実行時に _GetFocusedTab が正しい値を返すようにしている

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | SwitchToTabArgs の定義（227-231行目）。UInt32 型の TabIndex プロパティ |

**読解のコツ**: SwitchToTabArgs は必須のインデックスパラメータを持つシンプルな構造。他のタブ操作（CloseTabArgs等）が Optional<UInt32> を使うのに対し、こちらは必須である。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | _HandleSwitchToTab（480-488行目）がエントリーポイント |

**主要処理フロー**:
1. **480-481行目**: _HandleSwitchToTab の定義
2. **483行目**: SwitchToTabArgs へのキャスト
3. **485行目**: `_SelectTab({ realArgs.TabIndex() })` 呼び出し

#### Step 3: タブ選択ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TabManagement.cpp | `src/cascadia/TerminalApp/TabManagement.cpp` | _SelectTab（565-588行目） |

**主要処理フロー**:
- **570行目**: `std::clamp(tabIndex, 0u, _tabs.Size() - 1)` でインデックスをクランプ
- **572行目**: `_tabs.GetAt(tabIndex)` でタブを取得
- **576行目**: `_tabView.SelectedItem(tab.TabViewItem())` で TabView の選択を設定
- **578-581行目**: 起動中は _UpdatedSelectedTab を呼び出し
- **582-585行目**: 起動後は _SetFocusedTab を呼び出し

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

```
_HandleSwitchToTab (AppActionHandlers.cpp:480)
    |
    +-- _SelectTab(tabIndex) (TabManagement.cpp:565)
            |
            +-- std::clamp() -- インデックスクランプ
            |
            +-- _tabs.GetAt(tabIndex) -- タブ取得
            |
            +-- _tabView.SelectedItem() -- TabView 選択設定
            |
            +-- [起動中] _UpdatedSelectedTab()
            |
            +-- [起動後] _SetFocusedTab()
```

### データフロー図

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

SwitchToTabArgs --------> _HandleSwitchToTab
  TabIndex                  |
                          _SelectTab
                            |
                          クランプ -> タブ取得 -> TabView.SelectedItem -> フォーカス移動
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | ソース | _HandleSwitchToTab エントリーポイント |
| TabManagement.cpp | `src/cascadia/TerminalApp/TabManagement.cpp` | ソース | _SelectTab の実装 |
| TerminalPage.h | `src/cascadia/TerminalApp/TerminalPage.h` | ヘッダー | TerminalPage クラスのメソッド宣言 |
| ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | IDL | SwitchToTabArgs の WinRT インターフェース定義 |
