# 機能設計書 113-スニペットペイン

## 概要

保存された sendInput コマンド（スニペット）を一覧表示し、選択して実行するためのペインUIの設計書である。

### 本機能の処理概要

スニペットペインは、settings.json に定義された sendInput アクション（スニペット）をツリービュー形式で一覧表示し、ユーザーがクリックやキーボード操作で選択したスニペットを現在アクティブなターミナルに対して実行する専用ペインである。

**業務上の目的・背景**：開発者が頻繁に使用するコマンドやスクリプトの断片を事前に登録しておき、必要なときに素早く呼び出して実行できる仕組みが必要である。コマンドの再入力や履歴からの検索よりも効率的にコマンドを実行するために、視覚的な一覧表示と検索機能を備えたペインを提供する。

**機能の利用シーン**：頻繁に使用するGitコマンド、ビルドコマンド、デプロイスクリプトなどをスニペットとして登録しておき、開発作業中にスニペットペインを開いて必要なコマンドをクリック1つで実行する場面で使用される。

**主要な処理内容**：
1. ActionMap から sendInput タイプのスニペットを FilterToSnippets で取得する
2. FilteredTask としてラップし、TreeView に表示する
3. テキストフィルタによる検索機能を提供する（fzfマッチャー使用）
4. ユーザーが選択したスニペットを DispatchCommandRequested イベント経由で実行する
5. 最後にアクティブだったターミナルコントロールに対してコマンドを送信する

**関連システム・外部連携**：ActionMap（設定モデル）から sendInput アクションを取得し、TermControl に対してコマンドを送信する。fzf（fuzzy finder）パターンマッチャーをフィルタリングに使用する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 9 | SnippetsPaneContent（スニペット管理） | 主画面 | 保存されたsendInputコマンドの一覧表示 |
| 1 | TerminalPage（メイン画面） | 参照画面 | ペインとしてTerminalPageに配置される |

## 機能種別

UI表示・コマンド実行処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| settings | CascadiaSettings | Yes | スニペット一覧の取得元となる設定オブジェクト | null でないこと |
| filterText | String | No | スニペットを絞り込むフィルタテキスト | 任意の文字列 |

### 入力データソース

- settings.json の ActionMap に登録された sendInput アクション（スニペット）
- ユーザーのフィルタテキスト入力

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| スニペット一覧 | IObservableVector<FilteredTask> | フィルタ済みのスニペットリスト |
| DispatchCommandRequested | イベント | 選択されたコマンドの実行リクエスト |

### 出力先

- SnippetsPaneContent の TreeView（UI表示）
- DispatchCommandRequested イベント経由でアクティブターミナルへコマンド送信

## 処理フロー

### 処理シーケンス

```
1. SnippetsPaneContent が生成される
   └─ InitializeComponent() で XAML を初期化
2. UpdateSettings が呼び出される
   └─ settings.GlobalSettings().ActionMap().FilterToSnippets() でスニペットを取得
3. スニペットを FilteredTask としてラップし _allTasks に追加
   └─ TreeView に ItemsSource として設定
4. ユーザーがフィルタテキストを入力
   └─ _filterTextChanged → _updateFilteredCommands で fzf パターンマッチング
5. ユーザーがスニペットを選択・実行
   └─ _runCommand → DispatchCommandRequested イベント発行
```

### フローチャート

```mermaid
flowchart TD
    A[SnippetsPaneContent 生成] --> B[UpdateSettings 呼び出し]
    B --> C[FilterToSnippets でスニペット取得]
    C --> D[FilteredTask でラップ]
    D --> E[TreeView に表示]
    E --> F{ユーザー操作}
    F -->|フィルタ入力| G[fzf パターンマッチで絞り込み]
    G --> E
    F -->|スニペット選択| H[_runCommand 呼び出し]
    H --> I[アクティブコントロールにフォーカス]
    I --> J[DispatchCommandRequested イベント発行]
    F -->|閉じるボタン| K[CloseRequested イベント発行]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-113-01 | スニペット表示対象 | sendInput アクションとして定義されたコマンドのみ表示される | 常時 |
| BR-113-02 | ネスト対応 | ネストされたコマンド（フォルダ構造）をツリービューで展開表示する | ネストコマンド存在時 |
| BR-113-03 | フィルタリング | fzf パターンマッチャーにより名前でファジー検索が可能 | フィルタテキスト入力時 |
| BR-113-04 | 最小サイズ | ペインの最小サイズは 200x200 ピクセル | 常時 |
| BR-113-05 | 実行先 | 最後にアクティブだったターミナルコントロールに対してコマンドが送信される | スニペット実行時 |
| BR-113-06 | 非空制御文字の可視化 | 入力テキストの非空白制御文字は可視化して表示する | 入力テキスト表示時 |

### 計算ロジック

- フィルタリングの可視性判定: `(!pattern || pattern->terms.empty() || weight > 0)` の場合 Visible、子要素の合計 weight が 0 より大きい場合も Visible

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

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | スニペットなし | sendInput アクションが1つも登録されていない場合 | "SnippetsPaneNoneFoundHeader" メッセージを表示 |
| - | コントロール参照切れ | 最後にアクティブだったコントロールが破棄されている場合 | weak_ref の get() が nullptr を返し、コマンドは実行されない |

### リトライ仕様

リトライは行わない。

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

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

## パフォーマンス要件

- FilterToSnippets はバックグラウンドスレッドで実行される（co_await で非同期化）
- フィルタリングはUI スレッドで同期的に実行されるため、大量のスニペットがある場合は応答性に注意

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

- スニペットの内容はユーザーが settings.json で定義するため、信頼された入力である
- sendInput によるコマンド実行はターミナルプロセスのコンテキストで行われる

## 備考

- SnippetsPaneContent は UserControl として実装され、ペインとしてタブ内に配置される
- アイコンには QuickNote グリフ（\xe70b）が使用される
- 背景色は SettingsUiTabBrush テーマリソースから取得される

---

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

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

### 推奨読解順序

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

FilteredTask がスニペットのビューモデルとなる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SnippetsPaneContent.h | `src/cascadia/TerminalApp/SnippetsPaneContent.h` | **58-141行目**: FilteredTask 構造体。Command を FilteredCommand でラップし、子要素のツリー構造、fzf パターンによるフィルタリング、可視性判定を実装 |
| 1-2 | SnippetsPaneContent.h | `src/cascadia/TerminalApp/SnippetsPaneContent.h` | **13-56行目**: SnippetsPaneContent クラス定義。IPaneContent インターフェースを実装し、_allTasks（IObservableVector<FilteredTask>）を管理 |

**読解のコツ**: FilteredTask は FilteredCommand をラップし、さらに子要素（Children）を持つツリー構造を形成する。Visibility プロパティは fzf のマッチスコア（Weight）に基づいて動的に計算される。`Row()` メソッドの返値は XAML の Grid.Row にバインドされ、ネストコマンドかどうかで入力テキストの表示位置を制御する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SnippetsPaneContent.cpp | `src/cascadia/TerminalApp/SnippetsPaneContent.cpp` | **24-30行目**: コンストラクタ。XAML の InitializeComponent と AutomationProperties の設定 |
| 2-2 | SnippetsPaneContent.cpp | `src/cascadia/TerminalApp/SnippetsPaneContent.cpp` | **47-79行目**: UpdateSettings メソッド。FilterToSnippets で非同期にスニペットを取得し、FilteredTask でラップして _allTasks に追加する |

**主要処理フロー**:
1. **59行目**: FilterToSnippets を co_await で非同期呼び出し
2. **68-73行目**: 取得した各コマンドを FilteredTask でラップし _allTasks に追加
3. **74行目**: TreeView の ItemsSource に _allTasks を設定
4. **76行目**: _updateFilteredCommands でフィルタを適用

#### Step 3: フィルタリング処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SnippetsPaneContent.cpp | `src/cascadia/TerminalApp/SnippetsPaneContent.cpp` | **32-45行目**: _updateFilteredCommands メソッド。fzf::matcher::ParsePattern でパターンを生成し、各 FilteredTask の UpdateFilter を呼び出す |

#### Step 4: コマンド実行処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SnippetsPaneContent.cpp | `src/cascadia/TerminalApp/SnippetsPaneContent.cpp` | **134-144行目**: _runCommand メソッド。最後にアクティブだったコントロールにフォーカスを移し、DispatchCommandRequested イベントを発行 |
| 4-2 | SnippetsPaneContent.cpp | `src/cascadia/TerminalApp/SnippetsPaneContent.cpp` | **146-153行目**: _runCommandButtonClicked メソッド。ボタンクリック時のハンドラ |
| 4-3 | SnippetsPaneContent.cpp | `src/cascadia/TerminalApp/SnippetsPaneContent.cpp` | **188-215行目**: _treeItemKeyUpHandler メソッド。Enter/Space キーでのスニペット実行 |

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

```
SnippetsPaneContent
    |
    +-- UpdateSettings (設定変更時)
    |       |
    |       +-- ActionMap::FilterToSnippets (スニペット取得)
    |       |
    |       +-- FilteredTask (ビューモデル生成)
    |
    +-- _filterTextChanged (テキスト入力時)
    |       |
    |       +-- _updateFilteredCommands
    |               |
    |               +-- fzf::matcher::ParsePattern
    |               |
    |               +-- FilteredTask::UpdateFilter (各タスクに適用)
    |
    +-- _runCommandButtonClicked / _treeItemKeyUpHandler (実行時)
            |
            +-- _runCommand
                    |
                    +-- TermControl::Focus
                    |
                    +-- DispatchCommandRequested イベント
```

### データフロー図

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

settings.json の     FilterToSnippets で     FilteredTask リスト
sendInput アクション ──> スニペット取得 ──> TreeView に表示

ユーザーの           fzf パターンマッチ       フィルタ済みリスト
フィルタ入力 ──────> で絞り込み ──────────> Visibility 更新

ユーザーの           _runCommand で          DispatchCommandRequested
スニペット選択 ───> コマンド実行 ──────────> イベント発行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SnippetsPaneContent.h | `src/cascadia/TerminalApp/SnippetsPaneContent.h` | ソース | SnippetsPaneContent と FilteredTask の定義 |
| SnippetsPaneContent.cpp | `src/cascadia/TerminalApp/SnippetsPaneContent.cpp` | ソース | スニペットペインの処理実装 |
| SnippetsPaneContent.xaml | `src/cascadia/TerminalApp/SnippetsPaneContent.xaml` | XAML | スニペットペインのUI定義 |
| FilteredCommand.h | `src/cascadia/TerminalApp/FilteredCommand.h` | ソース | フィルタ済みコマンドのビューモデル |
| CommandPaletteItems.h | `src/cascadia/TerminalApp/CommandPaletteItems.h` | ソース | ActionPaletteItem の定義 |
| BasicPaneEvents.h | `src/cascadia/TerminalApp/BasicPaneEvents.h` | ソース | ペインイベントの基底クラス |
