# 通知設計書 54-キーマップエラー

## 概要

本ドキュメントは、Julia REPLのキーマップ処理中にエラーが発生した場合に発行されるエラー通知の設計を記述する。

### 本通知の処理概要

REPLの行入力ループにおいて、キー入力に対応するキーマップハンドラ関数の実行中に例外が発生した場合に、エラー情報をログに出力し、REPLの状態をリセットして操作を継続可能にする処理である。

**業務上の目的・背景**：Julia REPLのキーマップシステムは、各キー入力に対応する関数（補完、履歴検索、編集操作など）を実行する。これらの関数は複雑な処理を含むため、予期しないエラーが発生する可能性がある。キーマップエラーがREPL全体のクラッシュにつながることを防ぎ、エラーの詳細をユーザーに通知してデバッグを支援するために本通知が存在する。

**通知の送信タイミング**：`run_interface` 関数内のキー入力処理ループで、`match_input(kmap, s)` で取得したキーマップ関数 `fcn(s, kdata)` の実行が例外をスローした場合にトリガーされる。

**通知の受信者**：REPLを使用している開発者本人。ターミナルの標準エラー出力を通じて表示される。

**通知内容の概要**：「Error in the keymap」というメッセージと、発生した例外およびスタックトレース情報（`exception=e,catch_backtrace()`）が含まれる。

**期待されるアクション**：開発者は、エラーの原因を特定し、カスタムキーマップを使用している場合はその修正を行う。REPLは自動的に元の状態にリセットされるため、操作の継続は可能である。

## 通知種別

ログ（Error） - Julia標準ロギングフレームワーク `@error` マクロによるコンソール出力

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（キー入力処理ループ内で即座に出力） |
| 優先度 | 高（Errorレベル） |
| リトライ | 無し |

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

REPLセッション中のコード入力者本人が受信者。`@error` マクロによりグローバルロガーの設定に従いstderrへ出力される。

## 通知テンプレート

### メール通知の場合

該当なし（コンソールログ出力のみ）

### 本文テンプレート

```
Error: Error in the keymap
  exception = {例外オブジェクトとスタックトレース}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| exception | 発生した例外とスタックトレース | `e,catch_backtrace()` タプル | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| キー入力 | キーマップ関数実行時の例外 | `fcn(s, kdata)` が例外をスロー | `run_interface` 内の try-catch ブロックで捕捉 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 正常なキーマップ実行 | キーマップ関数が正常に完了した場合は通知されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[キー入力検出] --> B[match_input でキーマップ関数取得]
    B --> C[fcn実行]
    C --> D{例外発生?}
    D -->|No| E[status に基づく処理継続]
    D -->|Yes| F[@error Error in the keymap]
    F --> G[transition s :reset]
    G --> H[transition s old_state]
    H --> I[status = :done で処理終了]
```

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

### 参照テーブル一覧

該当なし

### テーブル別参照項目詳細

該当なし

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| キーマップ関数エラー | 任意の例外がキーマップハンドラ内で発生 | `@error` で通知し、状態をリセットして `status = :done` で入力ループを終了 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし。状態リセット後にREPLは新しいプロンプトを表示） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（REPLセッション中いつでも発生し得る）

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

例外情報にスタックトレースが含まれるため、内部のコードパスが表示される可能性があるが、ユーザーのローカル環境で表示されるのみであり、セキュリティ上の問題はない。

## 備考

- キーマップ処理は `Threads.@spawn :interactive` で対話型スレッドで実行される（LineEdit.jl 2990行目）
- `@lock s.line_modify_lock` でロックを取得した状態で処理が行われる（2992行目）
- エラー発生後、`transition(s, :reset)` でREPL状態をリセットし、`transition(s, old_state)` で元のモードに復帰する
- `status = :done` が設定され、入力ループは正常終了として扱われる

---

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

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

### 推奨読解順序

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

REPLの状態管理とキーマップの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | LineEdit.jl | `stdlib/REPL/src/LineEdit.jl` | 1-25行目: `TextInterface`, `ModeState`, `HistoryProvider`, `CompletionProvider` の抽象型定義 |
| 1-2 | LineEdit.jl | `stdlib/REPL/src/LineEdit.jl` | 43-45行目: `ModalInterface` と `Prompt` の定義 |

**読解のコツ**: REPLの状態は `MIState`（Modal Interface State）で管理され、複数のモード（julia, shell, help, pkg）を切り替え可能な設計である。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | LineEdit.jl | `stdlib/REPL/src/LineEdit.jl` | 2980-3029行目: `run_interface` 関数のキー入力処理ループ |

**主要処理フロー**:
1. **2990行目**: `Threads.@spawn :interactive` で対話型スレッドを起動
2. **2992行目**: `@lock s.line_modify_lock` でロック取得
3. **2994行目**: `keymap(s, prompt)` でキーマップ辞書を取得
4. **2995行目**: `match_input(kmap, s)` でキー入力に対応する関数を取得
5. **3003行目**: `fcn(s, kdata)` でキーマップ関数を実行
6. **3004-3010行目**: 例外発生時のcatchブロック
7. **3005行目**: `@error "Error in the keymap"` で通知
8. **3007行目**: `transition(s, :reset)` で状態リセット
9. **3008行目**: `transition(s, old_state)` で元の状態に復帰

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

```
run_interface  [LineEdit.jl:2980]
    |
    +-- activate(prompt, s, term, term)
    +-- Threads.@spawn :interactive  [LineEdit.jl:2990]
           |
           +-- [入力ループ]
                  |
                  +-- @lock s.line_modify_lock  [LineEdit.jl:2992]
                         |
                         +-- keymap(s, prompt) -> kmap
                         +-- match_input(kmap, s) -> fcn
                         +-- fcn(s, kdata)
                         |       |
                         |       +-- [例外発生時]
                         |              +-- @error "Error in the keymap"  [LineEdit.jl:3005]
                         |              +-- transition(s, :reset)  [LineEdit.jl:3007]
                         |              +-- transition(s, old_state)  [LineEdit.jl:3008]
                         |              +-- status = :done  [LineEdit.jl:3009]
                         |
                         +-- [status処理]
```

### データフロー図

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

キー入力 -----------------> match_input(kmap, s) -> fcn
                                    |
                                    +-> fcn(s, kdata)
                                    |       |
                                    |       +-> 正常: status (:ok/:done/:abort)
                                    |       +-> 例外: @error ------------> stderr
                                    |                  |
                                    |                  +-> transition(:reset)
                                    |                  +-> transition(old_state)
                                    |
                                    +-> status処理 --> バッファ/制御フロー
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| LineEdit.jl | `stdlib/REPL/src/LineEdit.jl` | ソース | キー入力処理ループとエラーハンドリング（2980-3029行目） |
| REPL.jl | `stdlib/REPL/src/REPL.jl` | ソース | カスタムキーマップの定義（`repl_keymap`） |
