# 機能設計書 3-キャッシュ機能

## 概要

本ドキュメントは、space-vimのキャッシュ機能の設計について記述する。キャッシュ機能は、レイヤー情報をキャッシュしてVimの起動時間を最適化する仕組みを提供する。

### 本機能の処理概要

キャッシュ機能は、layers/ディレクトリ以下のレイヤー構造をスキャンし、その結果をinfo.vimファイルにキャッシュとして保存する。Vim起動時にはこのキャッシュを読み込むことで、毎回のディレクトリスキャンを省略し、起動時間を短縮する。

**業務上の目的・背景**：space-vimは多数のレイヤー（カテゴリ別にグループ化されたプラグイン設定）を持ち、起動時にこれらを動的にスキャンしてマニフェストを生成する必要がある。しかし、レイヤー構造は頻繁に変更されるものではないため、スキャン結果をキャッシュすることで、通常の起動時のオーバーヘッドを大幅に削減できる。これにより、Vimの高速な起動というユーザー体験を維持しつつ、柔軟なレイヤーシステムを実現している。

**機能の利用シーン**：
- Vim初回起動時（キャッシュが存在しない場合、自動生成）
- 新しいレイヤーを追加・削除した後に`:LayerCache`コマンドを実行
- キャッシュファイルが破損した場合の自動再生成
- レイヤーのロード時にマニフェストが見つからない場合の自動再生成

**主要な処理内容**：
1. layers/ディレクトリ以下のトピック（+lang, +tools等）をスキャン
2. 各トピック内のレイヤーディレクトリを列挙
3. レイヤー名とディレクトリパスのマッピング（manifest）を作成
4. トピック名とレイヤー名リストのマッピング（topics）を作成
5. private/ディレクトリのプライベートレイヤーも処理
6. 結果をinfo.vimファイルにVimScript形式で出力

**関連システム・外部連携**：
- Python（オプション）: 高速なキャッシュ生成のためにPythonを使用可能
- ファイルシステム: ディレクトリスキャンとキャッシュファイルの読み書き

**権限による制御**：本機能に権限制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面を持たない内部処理機能 |

## 機能種別

データキャッシュ / 初期化処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| - | - | - | spacevim#cache#init()は引数を取らない | - |

### 入力データソース

1. **レイヤーディレクトリ**: `layers/`以下のディレクトリ構造
2. **プライベートレイヤー**: `private/`以下のディレクトリ構造
3. **グローバル変数**: `g:spacevim.base`（space-vimインストールディレクトリ）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| g:spacevim.manifest | Dictionary | レイヤー名をキー、{dir: パス}を値とするマッピング |
| g:spacevim.topics | Dictionary | トピック名をキー、レイヤー名リストを値とするマッピング |
| g:spacevim.private | List | プライベートレイヤー名のリスト（存在する場合） |

### 出力先

- グローバル変数（`g:spacevim`オブジェクト）
- キャッシュファイル（`core/autoload/spacevim/info.vim`）

## 処理フロー

### 処理シーケンス

```
1. spacevim#cache#init()呼び出し
   └─ Python使用可否を判定

2. Python使用可能な場合
   └─ s:py_init()実行（高速処理）

3. Python使用不可の場合
   └─ s:init()実行（VimScript処理）

4. s:init() / s:py_init()内部処理
   └─ layers/ディレクトリのトピック一覧取得
   └─ 各トピック内のレイヤー一覧取得
   └─ g:spacevim.manifestにレイヤー→ディレクトリマッピング格納
   └─ g:spacevim.topicsにトピック→レイヤーリスト格納
   └─ private/ディレクトリのスキャン（存在する場合）
   └─ info.vimファイルに結果を書き込み
```

### フローチャート

```mermaid
flowchart TD
    A[spacevim#cache#init] --> B{Python使用可能?}
    B -->|Yes| C[s:py_init]
    B -->|No| D[s:init]
    C --> E[layers/スキャン]
    D --> E
    E --> F[トピック抽出]
    F --> G[各トピックのレイヤー抽出]
    G --> H[manifest生成]
    H --> I[topics生成]
    I --> J{private/存在?}
    J -->|Yes| K[private/スキャン]
    J -->|No| L[info.vim出力]
    K --> L
    L --> M[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | Python優先 | Python（python/python3）が使用可能な場合は高速処理を使用 | has('python') または has('python3') |
| BR-02 | ディレクトリのみ | layers/内のディレクトリのみをレイヤーとして認識 | ファイルは無視 |
| BR-03 | キャッシュ形式 | キャッシュはVimScript形式（let文）で出力 | 常時 |
| BR-04 | プライベート処理 | private/以下のディレクトリもレイヤーとして処理 | private/が存在する場合 |

### 計算ロジック

該当なし

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Pythonエラー | Pythonでの処理中にエラー発生 | VimScriptによるs:init()にフォールバック |
| - | ファイル書き込みエラー | info.vimへの書き込み失敗 | エラーメッセージ表示 |

### リトライ仕様

Python処理失敗時はVimScript処理にフォールバック。

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

該当なし

## パフォーマンス要件

- キャッシュ使用時: ファイル読み込みのみ（高速）
- キャッシュ生成時: Python使用で高速化、VimScriptでも許容範囲内

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

- キャッシュファイルはVimScriptとして実行されるため、改ざんに注意
- 信頼できるディレクトリからのみキャッシュを読み込む

## 備考

- LayerCacheコマンドで手動キャッシュ更新可能
- レイヤー追加・削除後はLayerCache実行を推奨

---

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

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

### 推奨読解順序

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

キャッシュ機能で生成・使用されるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | spacevim.vim | `core/autoload/spacevim.vim` | g:spacevim.infoの定義（3行目）、g:spacevim.layers_baseの定義（4行目） |

**読解のコツ**: キャッシュで管理されるデータは以下の3つ:
- `g:spacevim.manifest`: `{'レイヤー名': {'dir': 'パス'}, ...}`
- `g:spacevim.topics`: `{'+トピック名': ['レイヤー1', 'レイヤー2'], ...}`
- `g:spacevim.private`: `['プライベートレイヤー1', ...]`（オプション）

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | cache.vim | `core/autoload/spacevim/cache.vim` | spacevim#cache#init()の処理分岐 |

**主要処理フロー**:
1. **1-12行目**: spacevim#cache#init()
   - **2行目**: Python（python/python3）の使用可否を判定
   - **3行目**: 使用可能な方のPythonコマンドを選択
   - **4-6行目**: Pythonが使用可能な場合はs:py_init()を試行
   - **7行目**: Pythonエラー時はs:init()にフォールバック
   - **9-10行目**: Python不可の場合は直接s:init()を実行

#### Step 3: VimScriptによるキャッシュ生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | cache.vim | `core/autoload/spacevim/cache.vim` | s:init()関数 |

**主要処理フロー**:
- **14行目**: topic_baseをlayers/ディレクトリに設定
- **15-17行目**: globpath()でトピックディレクトリを取得し、ディレクトリのみをフィルタ
- **20-33行目**: 各トピックを処理
  - **23行目**: トピック名を抽出（fnamemodify :t）
  - **24行目**: トピック内のレイヤーをglob
  - **26-27行目**: レイヤー名リストをtopicsに格納
  - **29-32行目**: 各レイヤーをmanifestに格納
- **35行目**: topicsをg:spacevimに格納
- **37-47行目**: private/ディレクトリの処理
- **41-47行目**: info.vimファイルへの書き込み
  - **42行目**: g:spacevim.topicsを書き込み
  - **43行目**: g:spacevim.manifestを書き込み
  - **44-46行目**: プライベートレイヤーがあれば追記

#### Step 4: Pythonによる高速キャッシュ生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | cache.vim | `core/autoload/spacevim/cache.vim` | s:py_init()関数 |

**主要処理フロー**:
- **50行目**: execute s:py_exe でPythonコードを実行
- **52-54行目**: Pythonモジュールのインポート
- **56-57行目**: glob_basename()ヘルパー関数定義
- **59-61行目**: Vim変数からbase, topic_base, private_baseを取得
- **63-70行目**: トピックディレクトリとプライベートディレクトリをスキャン
- **72-81行目**: manifest（spacevim_manifest）とtopics（spacevim_topics）を生成
- **83-86行目**: vim.command()でVim変数に値を設定
- **88-93行目**: info.vimファイルに結果を書き込み

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

```
:LayerCache または s:cache()
    │
    └─ spacevim#cache#init()  [core/autoload/spacevim/cache.vim:1]
           │
           ├─ [Python使用可能時]
           │      └─ s:py_init()  [core/autoload/spacevim/cache.vim:50]
           │             └─ Pythonによるディレクトリスキャン
           │             └─ vim.command()でg:spacevimに設定
           │             └─ info.vimファイル書き込み
           │
           └─ [Python使用不可 または エラー時]
                  └─ s:init()  [core/autoload/spacevim/cache.vim:14]
                         └─ globpath()によるディレクトリスキャン
                         └─ g:spacevimに設定
                         └─ writefile()でinfo.vim書き込み
```

### データフロー図

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

layers/
  +lang/
    python/            ─────▶ ディレクトリスキャン ─────────▶ g:spacevim.manifest
    javascript/               │                                {'python': {'dir': '...'}}
  +tools/                     │
    fzf/                      │
    ctags/                    │
                              ▼
                        トピック分類 ─────────────────────────▶ g:spacevim.topics
                              │                                {'+lang': ['python', 'javascript']}
                              │
private/                      │
  my-layer/           ─────▶ プライベートレイヤー処理 ────────▶ g:spacevim.private
                              │                                ['my-layer']
                              ▼
                        info.vim書き込み ─────────────────────▶ core/autoload/spacevim/info.vim
                                                               (VimScript形式)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| cache.vim | `core/autoload/spacevim/cache.vim` | ソース | キャッシュ生成処理 |
| spacevim.vim | `core/autoload/spacevim.vim` | ソース | キャッシュ読み込み・利用 |
| info.vim | `core/autoload/spacevim/info.vim` | キャッシュ | 生成されたキャッシュファイル |
| layers/ | `layers/` | ディレクトリ | レイヤー格納ディレクトリ |
| private/ | `private/` | ディレクトリ | プライベートレイヤー格納ディレクトリ |
