# 通知設計書 44-エディタ値不正警告

## 概要

本ドキュメントは、Julia の InteractiveUtils モジュールにおけるエディタ値不正警告（`@warn "invalid editor value returned"`）の通知設計について記載する。

### 本通知の処理概要

`define_editor` で登録されたエディタコールバック関数が、`Cmd` でも `nothing` でもない不正な値を返した場合に警告を発行する通知である。

**業務上の目的・背景**：Julia の `edit` 関数はファイルを外部エディタで開くためのユーティリティであり、`define_editor` を通じてカスタムエディタを登録できる。登録されたコールバック関数は `Cmd` オブジェクト（エディタコマンド）または `nothing`（このエディタでは対応不可）を返すことが期待される。しかし、ユーザーが誤ったコールバックを実装して不正な値を返した場合、エディタが起動せず原因特定が困難になる。本警告は、コールバックの返り値が不正であることを明示し、デバッグを容易にする目的で発行される。

**通知の送信タイミング**：`define_editor` 内のコールバックラッパーが実行され、ユーザー定義コールバックの返り値が `Cmd` でも `nothing` でもないと判定された時点で送信される。

**通知の受信者**：`define_editor` でカスタムエディタを登録した Julia 開発者。

**通知内容の概要**：不正なエディタ値が返されたこと、およびマッチしたパターンと実際の返り値を通知する。

**期待されるアクション**：ユーザーは `define_editor` のコールバック関数を修正し、`Cmd` オブジェクトまたは `nothing` を返すようにする。

## 通知種別

ログ出力（`@warn` マクロによる標準エラー出力へのWarnレベルログ）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（`@warn` マクロによる即時ログ出力） |
| 優先度 | 中（Warn レベル） |
| リトライ | なし（ログ出力のため） |

### 送信先決定ロジック

Julia のログシステムに委譲される。デフォルトでは `stderr` に出力される。

## 通知テンプレート

### メール通知の場合

該当なし（ログ出力のみ）

### 本文テンプレート

```
┌ Warning: invalid editor value returned
│   pattern = <パターン>
│   editor = <返り値>
└ @ InteractiveUtils stdlib/InteractiveUtils/src/editless.jl:111
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| `pattern` | `define_editor` に渡されたパターン（文字列、正規表現、または配列） | `define_editor` の引数 | Yes |
| `editor` | コールバック関数が返した不正な値 | コールバック関数の返り値 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| API呼び出し | `edit()` 関数実行時のエディタコールバック評価 | コールバック関数が `Cmd` でも `nothing` でもない値を返した | 不正な返り値のみ対象 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 正常な返り値 | `Cmd` または `nothing` が返された場合は警告なし |
| パターン不一致 | エディタパターンが一致しない場合はコールバック自体が呼ばれない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A["edit(path, line, column) 呼び出し"] --> B["editor() でエディタコマンド取得"]
    B --> C["EDITOR_CALLBACKS をイテレーション"]
    C --> D["各コールバックを実行"]
    D --> E{"editor_matches?"}
    E -->|No| F["return false → 次のコールバックへ"]
    E -->|Yes| G["fn(cmd, path, line, column) 実行"]
    G --> H{"返り値の型チェック"}
    H -->|"Cmd"| I["エディタを起動"]
    H -->|"nothing"| J["return false → 次のコールバックへ"]
    H -->|"その他"| K["@warn 警告出力"]
    K --> L["return false"]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（データベースは使用しない）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 不正なエディタ返り値 | コールバック関数が `Cmd` でも `nothing` でもない値を返した | 警告を出力し `false` を返す（次のエディタコールバックを試行） |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（次のコールバックにフォールバック） |
| リトライ間隔 | なし |
| リトライ対象エラー | なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 上限 | 特に制限なし |

### 配信時間帯

制限なし

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

- ログメッセージにパターン（正規表現等）とエディタの返り値が含まれるが、通常は機密情報を含まない

## 備考

- `define_editor` は Julia 1.4 で導入された
- デフォルトのエディタ定義は `define_default_editors()` で設定されており、vim, emacs, VS Code 等の主要エディタがサポートされている
- `EDITOR_CALLBACKS` はスタック構造（`pushfirst!`）で、後から登録されたエディタが優先される

---

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

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

### 推奨読解順序

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

エディタコールバックシステムの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | editless.jl | `stdlib/InteractiveUtils/src/editless.jl` | `EDITOR_CALLBACKS` 定数（15行目） |

**読解のコツ**: `EDITOR_CALLBACKS` は `Function` の `Vector` であり、各要素は `(cmd, path, line, column) -> Bool` のシグネチャを持つクロージャ。後から追加されたものが先頭に置かれる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | editless.jl | `stdlib/InteractiveUtils/src/editless.jl` | `define_editor` 関数（92-115行目） |
| 2-2 | editless.jl | `stdlib/InteractiveUtils/src/editless.jl` | `edit(path, line, column)` 関数（231-247行目） |

**主要処理フロー**:
1. **92行目**: `define_editor(fn, pattern; wait=false)` が呼び出されると内部コールバックラッパーを生成
2. **93-115行目**: コールバックラッパー内で `editor_matches` → `fn` 呼び出し → 返り値チェック
3. **101-107行目**: `Cmd` の場合はエディタ起動（`wait` フラグで同期/非同期切替）
4. **108-109行目**: `nothing` の場合は `false` を返して次のコールバックへ
5. **111行目**: その他の場合は `@warn` を発行し `false` を返す

#### Step 3: edit 関数からのコールバック呼び出し

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | editless.jl | `stdlib/InteractiveUtils/src/editless.jl` | `edit` 関数内のコールバックループ（238-244行目） |

**主要処理フロー**:
- **237行目**: `cmd = editor()` で `JULIA_EDITOR`/`VISUAL`/`EDITOR` からコマンド取得
- **238-244行目**: `EDITOR_CALLBACKS` を順に試行、`true` が返されたら終了

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

```
edit(path, line, column)           [editless.jl:231]
    │
    ├─ editor()                     [editless.jl:205]
    │      └─ ENV["JULIA_EDITOR"] / "VISUAL" / "EDITOR" 参照
    │
    └─ EDITOR_CALLBACKS loop        [editless.jl:238]
           │
           └─ callback(cmd, path, line, column)  [define_editor内クロージャ]
                  │
                  ├─ editor_matches(pattern, cmd)  [editless.jl:117-119]
                  ├─ fn(cmd, path, line, column)   [ユーザー定義関数]
                  │      └─ 返り値チェック
                  │             ├─ Cmd → run()
                  │             ├─ nothing → false
                  │             └─ その他 → @warn  [editless.jl:111: 本通知]
                  │
                  └─ return Bool
```

### データフロー図

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

ENV変数 ──────────────▶ editor() → Cmd
パターン ─────────────▶ editor_matches() → Bool
path/line/column ─────▶ fn(cmd, ...) → 返り値
                               │
                               ▼
                    型チェック (Cmd/nothing/other)
                               │
                    other → @warn ────────────▶ ログ出力 (stderr)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| editless.jl | `stdlib/InteractiveUtils/src/editless.jl` | ソース | 通知発行元、エディタ連携機能全体のロジック |
| InteractiveUtils.jl | `stdlib/InteractiveUtils/src/InteractiveUtils.jl` | ソース | InteractiveUtils モジュール定義、editless.jl の include |
