# 機能設計書 51-マークにスクロール

## 概要

本ドキュメントは、Windows Terminal における「マークにスクロール」機能の設計を記述する。ScrollToMark アクションにより、ターミナルバッファ内のスクロールバーマーク位置へスクロールする機能である。

### 本機能の処理概要

**業務上の目的・背景**：ターミナルバッファが長くなると、過去のコマンド実行位置やユーザーが手動で付けたマークの位置に戻ることが困難になる。本機能は、マーク位置への素早いナビゲーションを提供し、作業効率を向上させる。シェル統合によって自動的にマークが付与されるコマンドプロンプト位置への移動にも活用される。

**機能の利用シーン**：ユーザーがターミナルで長い出力を確認した後、以前のコマンド実行位置に戻りたい場合に利用する。キーバインドまたはコマンドパレットから ScrollToMark アクションを実行し、Previous/Next/First/Last の方向指定で目的のマーク位置にスクロールする。

**主要な処理内容**：
1. ユーザーが ScrollToMark アクションを実行（キーバインドまたはコマンドパレット経由）
2. ActionArgs から方向（ScrollToMarkDirection）を取得
3. ControlCore が現在のスクロール位置とバッファ内の全マーク位置を取得
4. 指定方向に基づいて最も近いマーク位置を検索
5. 対象マーク位置にビューポートをスクロールし、スクロールバーを更新

**関連システム・外部連携**：シェル統合機能（OSC シーケンス経由）で自動付与されるマークと連携する。TerminalCore のテキストバッファが保持するマーク情報を参照する。

**権限による制御**：特になし。すべてのユーザーが利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | TerminalPage（メイン画面） | 主画面 | _HandleScrollToMarkによりマーク位置へスクロール |

## 機能種別

スクロール操作 / ナビゲーション機能

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| Direction | ScrollToMarkDirection (enum) | No | スクロール方向。Previous（前のマーク）、Next（次のマーク）、First（最初のマーク）、Last（最後のマーク） | デフォルト値: Previous |

### 入力データソース

キーバインド設定またはコマンドパレットからの ScrollToMark アクション。ActionArgs 経由で ScrollToMarkArgs として方向パラメータを受け取る。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| スクロール位置 | int | マーク位置の行番号（バッファ内座標） |
| Handled | bool | アクションが処理されたかどうか（常に true） |

### 出力先

ターミナルコントロールのビューポートスクロール位置が更新され、スクロールバーの表示位置も同期される。

## 処理フロー

### 処理シーケンス

```
1. TerminalPage::_HandleScrollToMark がアクションイベントを受信
   └─ ActionArgs から ScrollToMarkArgs を取得
2. _ApplyToActiveControls でアクティブなコントロールに処理を適用
   └─ control.ScrollToMark(direction) を呼び出し
3. ControlCore::ScrollToMark が実行される
   └─ ターミナルのロックを取得（LockForWriting）
4. 現在のスクロールオフセットを取得
   └─ ScrollOffset() で現在のビューポート位置を取得
5. Terminal::GetMarkExtents() で全マーク情報を取得
6. 方向に応じたマーク検索
   ├─ Previous: 現在位置より前で最も近いマーク
   ├─ Next: 現在位置より後で最も近いマーク
   ├─ First: 現在位置より前で最も遠いマーク
   └─ Last: 現在位置より後で最も遠いマーク
7. 対象マークが見つかった場合
   └─ UserScrollViewport で指定行にスクロール
8. 対象マークが見つからない場合
   ├─ Last/Next: バッファ末尾にスクロール
   └─ First/Previous: バッファ先頭にスクロール
9. _terminalScrollPositionChanged でスクロールバーを更新
```

### フローチャート

```mermaid
flowchart TD
    A[ScrollToMark アクション受信] --> B[ScrollToMarkArgs から方向取得]
    B --> C[_ApplyToActiveControls]
    C --> D[ControlCore::ScrollToMark]
    D --> E[現在のスクロール位置取得]
    E --> F[全マーク位置取得 GetMarkExtents]
    F --> G{方向は?}
    G -->|Previous| H[現在位置より前で最も近いマーク検索]
    G -->|Next| I[現在位置より後で最も近いマーク検索]
    G -->|First| J[現在位置より前で最も遠いマーク検索]
    G -->|Last| K[現在位置より後で最も遠いマーク検索]
    H --> L{マーク見つかった?}
    I --> L
    J --> L
    K --> L
    L -->|Yes| M[UserScrollViewport でマーク位置にスクロール]
    L -->|No| N{方向は Last/Next?}
    N -->|Yes| O[バッファ末尾にスクロール]
    N -->|No| P[バッファ先頭にスクロール]
    M --> Q[_terminalScrollPositionChanged でスクロールバー更新]
    O --> Q
    P --> Q
    Q --> R[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-51-1 | 方向デフォルト | 方向が未指定の場合、Previous（前のマーク）がデフォルト | Direction が未指定の場合 |
| BR-51-2 | マーク不在時のフォールバック | 指定方向にマークが見つからない場合、バッファの端にスクロール | マーク検索結果が空の場合 |
| BR-51-3 | 距離最小マーク選択 | Previous/Next では現在位置から最も距離が小さいマークを選択 | Previous または Next 方向の場合 |
| BR-51-4 | 距離最大マーク選択 | First/Last では現在位置から最も距離が大きいマークを選択 | First または Last 方向の場合 |

### 計算ロジック

- Previous: `delta = currentOffset - mark.start.y`（delta > 0 で最小の delta を選択）
- Next: `delta = mark.start.y - currentOffset`（delta > 0 で最小の delta を選択）
- First: `mark.start.y < lowest` を満たす中で最小の y を選択
- Last: `mark.start.y > highest` を満たす中で最大の y を選択

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

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

本機能はデータベース操作を行わない。ターミナルバッファのインメモリマークデータを参照するのみ。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| なし | マーク不在 | バッファにマークが存在しない場合 | バッファの端（先頭または末尾）にスクロール |
| なし | ActionArgs 取得失敗 | ScrollToMarkArgs へのキャストが失敗 | 処理をスキップし、Handled=true を返す |

### リトライ仕様

リトライ処理は不要。

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

本機能にトランザクション制御はない。ターミナルの書き込みロック（LockForWriting）を取得して排他制御を行う。

## パフォーマンス要件

全マークを線形探索するため、マーク数に比例した処理時間（O(n)）がかかるが、通常のマーク数では問題にならない。

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

特になし。ユーザーのローカルターミナルバッファ内の操作のみ。

## 備考

- ScrollToMark アクションは AllShortcutActions.h で定義されている
- シェル統合機能で自動的に付与されるコマンドプロンプトマークへのナビゲーションにも利用可能

---

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

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

### 推奨読解順序

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

まず、スクロールマークとその方向を定義するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ICoreState.idl | `src/cascadia/TerminalControl/ICoreState.idl` | ScrollToMarkDirection 列挙型（Previous, Next, First, Last）と ScrollMark 構造体の定義 |
| 1-2 | ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | ScrollToMarkArgs の定義（Direction プロパティ） |
| 1-3 | Terminal.hpp | `src/cascadia/TerminalCore/Terminal.hpp` | GetMarkExtents, AddMarkFromUI, ClearMark, ClearAllMarks の宣言 |

**読解のコツ**: IDL ファイルは WinRT のインターフェース定義であり、C++ コードでの `winrt::` 名前空間に対応する。`ScrollToMarkDirection` 列挙型は `Microsoft.Terminal.Control` 名前空間に所属する。

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

アクションハンドラーが処理の起点となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | _HandleScrollToMark メソッドの実装 |

**主要処理フロー**:
1. **381-391行目**: _HandleScrollToMark が ActionArgs から ScrollToMarkArgs を取得し、_ApplyToActiveControls で control.ScrollToMark(direction) を呼び出す

#### Step 3: ControlCore のスクロール処理を理解する

実際のマーク検索とスクロール制御を行うレイヤー。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ScrollToMark メソッドの実装（方向別マーク検索ロジック） |

**主要処理フロー**:
- **2590-2682行目**: ScrollToMark の全体実装。方向別の switch 文でマーク検索し、UserScrollViewport でスクロール実行
- **2600-2612行目**: Last 方向 - 現在位置より後の最も遠いマーク
- **2614-2626行目**: First 方向 - 現在位置より前の最も遠いマーク
- **2628-2640行目**: Next 方向 - 現在位置より後の最も近いマーク
- **2642-2656行目**: Previous 方向 - 現在位置より前の最も近いマーク
- **2664-2680行目**: マーク不在時のフォールバック処理

#### Step 4: Terminal コアのマーク管理を理解する

マークデータの保持と取得を行う最下層。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Terminal.cpp | `src/cascadia/TerminalCore/Terminal.cpp` | GetMarkExtents メソッドでバッファからマーク情報を取得 |

**主要処理フロー**:
- **1488行目付近**: GetMarkExtents が MarkExtents のベクターを返す

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

```
TerminalPage::_HandleScrollToMark (AppActionHandlers.cpp:381)
    │
    ├─ ActionArgs.try_as<ScrollToMarkArgs>() → 方向パラメータ取得
    │
    └─ _ApplyToActiveControls
           │
           └─ TermControl::ScrollToMark (TermControl.cpp)
                  │
                  └─ ControlCore::ScrollToMark (ControlCore.cpp:2590)
                         │
                         ├─ Terminal::GetMarkExtents() → マーク一覧取得
                         │
                         ├─ 方向別検索ロジック (switch文)
                         │
                         ├─ UserScrollViewport(targetY) → ビューポート移動
                         │
                         └─ _terminalScrollPositionChanged() → スクロールバー更新
```

### データフロー図

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

ScrollToMarkArgs    ───▶ TerminalPage                ───▶ ビューポート位置更新
(Direction:enum)         ::_HandleScrollToMark
                              │
                              ▼
                         ControlCore
                         ::ScrollToMark
                              │
                              ├─ GetMarkExtents() ◀── TextBuffer (マーク情報)
                              │
                              ▼
                         方向別マーク検索
                              │
                              ▼
                         UserScrollViewport ──────────▶ スクロールバー同期
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AppActionHandlers.cpp | `src/cascadia/TerminalApp/AppActionHandlers.cpp` | ソース | アクションハンドラー（エントリーポイント） |
| TerminalPage.h | `src/cascadia/TerminalApp/TerminalPage.h` | ヘッダー | _ApplyToActiveControls テンプレートメソッド定義 |
| ControlCore.cpp | `src/cascadia/TerminalControl/ControlCore.cpp` | ソース | ScrollToMark の実装（方向別マーク検索・スクロール） |
| ControlCore.h | `src/cascadia/TerminalControl/ControlCore.h` | ヘッダー | ScrollToMark メソッド宣言 |
| ICoreState.idl | `src/cascadia/TerminalControl/ICoreState.idl` | IDL | ScrollToMarkDirection 列挙型、ScrollMark 構造体定義 |
| ActionArgs.idl | `src/cascadia/TerminalSettingsModel/ActionArgs.idl` | IDL | ScrollToMarkArgs 定義 |
| AllShortcutActions.h | `src/cascadia/TerminalSettingsModel/AllShortcutActions.h` | ヘッダー | ScrollToMark アクションの登録 |
| Terminal.cpp | `src/cascadia/TerminalCore/Terminal.cpp` | ソース | GetMarkExtents の実装 |
| Terminal.hpp | `src/cascadia/TerminalCore/Terminal.hpp` | ヘッダー | マーク関連メソッドの宣言 |
| TermControl.cpp | `src/cascadia/TerminalControl/TermControl.cpp` | ソース | TermControl の ScrollToMark ラッパー |
| TermControl.h | `src/cascadia/TerminalControl/TermControl.h` | ヘッダー | TermControl の ScrollToMark 宣言 |
