# 画面設計書 19-UltiSnips（スニペット展開）

## 概要

本ドキュメントは、space-vimにおけるUltiSnips（スニペット展開）画面の設計を記述したものである。UltiSnipsプラグインによって提供されるコードスニペットの展開・編集機能について、その構成・機能・操作方法を詳細に解説する。

### 本画面の処理概要

UltiSnips画面（正確には「スニペット展開機能」）は、定型コードパターン（スニペット）を短いトリガー文字列から展開する機能である。関数定義、クラステンプレート、ループ構造など、頻繁に使用するコードパターンを効率的に入力できるようにする。

**業務上の目的・背景**：プログラミングにおいて、同じようなコードパターンを繰り返し入力することは非効率である。UltiSnipsは、スニペット（コードテンプレート）を定義し、短いトリガー文字列で展開することで、タイピング量を削減し、コーディング速度と正確性を向上させる。プレースホルダー機能により、展開後の編集も効率化される。

**画面へのアクセス方法**：
- トリガー文字列入力後、展開キー押下（`C-e`または`C-u`）
- ncm2連携時はEnterキーで展開
- 補完ポップアップからスニペット候補を選択

**主要な操作・処理内容**：
1. **スニペット展開**：トリガー文字列からコードテンプレートを展開
2. **プレースホルダー編集**：展開されたテンプレート内のプレースホルダーを編集
3. **タブストップジャンプ**：`C-j`で次のプレースホルダー、`C-k`で前のプレースホルダーへ移動
4. **スニペット編集**：`:UltiSnipsEdit`でカレントファイルタイプのスニペット定義を編集
5. **補完連携**：ncm2、deoplete等の補完プラグインとの連携

**画面遷移**：
- エディタ画面（挿入モード） → スニペット展開（展開キー押下）
- スニペット展開中 → 次のプレースホルダー（`C-j`）
- スニペット編集画面（`:UltiSnipsEdit`）

**権限による表示制御**：本画面に権限による表示制御は存在しない。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 59 | コードスニペット | 主機能 | UltiSnipsによるスニペット展開・編集 |
| 26 | ncm2連携 | API連携 | ncm2-ultisnipsによる補完との連携 |

## 画面種別

インライン展開機能（エディタ画面内で動作）

## URL/ルーティング

Vimコマンド/キーバインドによるアクセス：
- トリガー + `C-e` - スニペット展開（デフォルト）
- トリガー + `C-u` - スニペット展開（ncm2連携時）
- `C-j` - 次のプレースホルダーへジャンプ
- `C-k` - 前のプレースホルダーへジャンプ
- `:UltiSnipsEdit` - スニペット定義ファイルを編集

## 入出力項目

| 項目名 | 入出力 | データ型 | 説明 |
|--------|--------|----------|------|
| トリガー文字列 | 入力 | 文字列 | スニペット展開のトリガー |
| プレースホルダー値 | 入力 | 文字列 | 展開後のプレースホルダーに入力する値 |
| 展開テンプレート | 出力 | テキスト | 展開されたコードテンプレート |
| ファイルタイプ | 入力（自動） | 文字列 | 現在のバッファのファイルタイプ |

## 表示項目

### スニペット展開時

| 表示項目 | 説明 |
|----------|------|
| 展開されたコード | トリガーから展開されたテンプレート |
| プレースホルダー | 編集対象の位置（ビジュアル選択状態） |
| ミラーリング | 同じ値が複数箇所に反映される |

### 補完ポップアップ内（連携時）

| 表示項目 | 説明 |
|----------|------|
| スニペット候補 | 利用可能なスニペットのリスト |
| スニペットマーク | スニペット候補を示すアイコン/テキスト |

## イベント仕様

### 1-スニペット展開

トリガー文字列を入力後、展開キーを押すとスニペットが展開される。

```
[ユーザー操作] トリガー文字列入力 → C-e/C-u押下
        ↓
[UltiSnips] トリガーに一致するスニペットを検索
        ↓
[UltiSnips] テンプレートをバッファに挿入
        ↓
[UltiSnips] 最初のプレースホルダーを選択状態に
        ↓
[画面更新] 展開されたコードが表示される
```

### 2-プレースホルダー編集

展開後、プレースホルダー位置で値を入力する。

```
[状態] プレースホルダーが選択状態
        ↓
[ユーザー操作] 値を入力
        ↓
[UltiSnips] プレースホルダーの値を更新
        ↓
[UltiSnips] ミラーがある場合は同時に更新
```

### 3-タブストップジャンプ

`C-j`/`C-k`でプレースホルダー間を移動する。

```
[ユーザー操作] C-j押下（次のプレースホルダーへ）
        ↓
[UltiSnips] 次のタブストップを検索
        ↓
[カーソル移動] 該当位置にジャンプ + 選択状態
```

### 4-ncm2との連携

ncm2連携が有効な場合、補完ポップアップからスニペットを選択して展開できる。

```
[ユーザー操作] 補完ポップアップでスニペット候補を選択 → Enter
        ↓
[ncm2-ultisnips] ncm2_ultisnips#expand_or()呼び出し
        ↓
[UltiSnips] スニペット展開
```

## データベース更新仕様

本画面はコード編集補助機能であり、データベースへの更新は行わない。

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------|
| ULT001 | 警告 | No matching snippets | 一致するスニペットがない場合 |
| ULT002 | 情報 | Editing snippets for filetype | :UltiSnipsEdit実行時 |

## 例外処理

| 例外状態 | 対処 | ユーザーへの通知 |
|---------|------|-----------------|
| 一致するスニペットがない | 展開をスキップ | 特になし（通常の入力として扱う） |
| スニペットファイルが存在しない | 新規作成 | 新規ファイルを開く |

## 備考

- UltiSnipsはSirVer氏によって開発されたスニペットエンジンである
- space-vimではInsertEnterイベントで遅延読み込みが設定されている
- vim-snippetsプラグインにより、多数の言語向けスニペット定義が提供される
- スニペットディレクトリは`~/.vim/UltiSnips`と`private/UltiSnips`に設定
- ncm2連携時は展開トリガーが異なる（`<Plug>(ultisnips_expand)`）

---

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

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

### 推奨読解順序

#### Step 1: プラグイン登録と遅延読み込みを理解する

まず、UltiSnipsがどのように登録され、いつ読み込まれるかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | packages.vim | `layers/+programming/code-snippets/packages.vim` | UltiSnipsの登録と遅延読み込み設定 |

**読解のコツ**: `{ 'on': [], 'on_event': 'InsertEnter' }`は、InsertEnterイベント発生時に初めて読み込まれることを示す。

**主要処理フロー**:
1. **3行目**: `MP 'SirVer/ultisnips', { 'on': [], 'on_event': 'InsertEnter' }` - 遅延読み込み
2. **4行目**: `MP 'honza/vim-snippets', { 'on': [], 'on_event': 'InsertEnter' }` - スニペット定義集

#### Step 2: UltiSnips設定を理解する

スニペットディレクトリ、トリガーキー、ジャンプキーの設定を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | config.vim | `layers/+programming/code-snippets/config.vim` | UltiSnips詳細設定 |

**主要処理フロー**:
1. **5行目**: `let g:UltiSnipsSnippetDirectories=['UltiSnips']` - スニペットディレクトリ
2. **6行目**: `exe 'set rtp+=' ...` - privateスニペットディレクトリをruntimepathに追加
3. **7行目**: `let g:UltiSnipsSnippetsDir = '~/.vim/UltiSnips'` - ユーザースニペット保存先
4. **10行目**: `let g:UltiSnipsJumpForwardTrigger = "<c-j>"` - 次のプレースホルダーへ
5. **11行目**: `let g:UltiSnipsJumpBackwardTrigger = "<c-k>"` - 前のプレースホルダーへ

#### Step 3: ncm2との連携を理解する

ncm2補完エンジンとの連携設定を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | config.vim | `layers/+programming/code-snippets/config.vim` | ncm2連携設定（13-22行目） |

**主要処理フロー**:
1. **13行目**: `if has_key(g:plugs, 'ncm2-ultisnips')` - ncm2連携プラグインの存在チェック
2. **15行目**: CRキーでのスニペット展開マッピング
3. **16-17行目**: C-uキーでのスニペット展開マッピング
4. **18行目**: 展開トリガーを`<Plug>(ultisnips_expand)`に設定
5. **21行目**: ncm2連携がない場合は`<C-e>`をトリガーに設定

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

```
挿入モード開始（InsertEnter）
    │
    └─ UltiSnips / vim-snippets 遅延読み込み

トリガー入力 → 展開キー押下
    │
    ├─ ncm2連携なし
    │      └─ <C-e> → UltiSnipsExpandTrigger
    │             └─ UltiSnips展開処理
    │
    └─ ncm2連携あり
           └─ <CR> / <C-u> → ncm2_ultisnips#expand_or()
                  └─ UltiSnips展開処理

プレースホルダー編集中
    │
    ├─ <C-j> → UltiSnipsJumpForwardTrigger
    │      └─ 次のタブストップへ
    │
    └─ <C-k> → UltiSnipsJumpBackwardTrigger
           └─ 前のタブストップへ
```

### データフロー図

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

トリガー + C-e ──▶ UltiSnips ──────────▶ 展開テンプレート
                          │
                          ├─▶ スニペット検索
                          │
                          └─▶ バッファに挿入

プレースホルダー編集 ▶ UltiSnips ──────────▶ 値の更新
                          │
                          └─▶ ミラーリング処理

C-j ─────────────▶ UltiSnips ──────────▶ 次のプレースホルダー
                          │
                          └─▶ タブストップジャンプ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| packages.vim | `layers/+programming/code-snippets/packages.vim` | ソース | UltiSnips, vim-snippetsプラグイン登録 |
| config.vim | `layers/+programming/code-snippets/config.vim` | ソース | トリガー設定、ncm2連携設定 |
| 画面一覧.csv | `docs/code-to-docs/画面一覧/画面一覧.csv` | データ | 画面No.19の定義 |
| UltiSnips/ | `private/UltiSnips/` | データ | ユーザー定義スニペットディレクトリ |
