# 通知設計書 10-genericSaveError

## 概要

本ドキュメントは、VS Codeでファイルの保存に失敗した場合に表示される一般的なエラー通知の設計について記述する。

### 本通知の処理概要

この通知は、ユーザーがファイルを保存しようとした際に、特定のエラー（書き込みロック、権限エラー、ファイル変更競合など）に該当しない一般的な保存エラーが発生した場合にエラーメッセージを表示する機能である。

**業務上の目的・背景**：ファイル保存は開発作業において最も基本的かつ重要な操作の一つである。保存に失敗した場合、ユーザーは作業内容を失う可能性があるため、明確なエラーメッセージを表示し、問題の特定と解決を支援することが重要である。この通知は、特定カテゴリに分類されないエラーに対応するフォールバックとして機能する。

**通知の送信タイミング**：ファイル保存処理（TextFileEditorModel.save()）が失敗し、そのエラーがFILE_MODIFIED_SINCE（競合）、FILE_WRITE_LOCKED（書き込みロック）、FILE_PERMISSION_DENIED（権限エラー）のいずれにも該当しない場合に通知が送信される。

**通知の受信者**：ファイル保存を試みたVS Codeユーザーが対象となる。

**通知内容の概要**：「Failed to save '{ファイル名}': {エラーメッセージ}」という形式でメッセージが表示される。

**期待されるアクション**：ユーザーは以下のいずれかの対応を取ることが期待される：
- 「リトライ」ボタンで再保存を試みる
- 「名前を付けて保存」で別の場所に保存する
- 「元に戻す」でファイルを元の状態に戻す
- エラーメッセージを確認して問題を特定する

## 通知種別

アプリ内通知（VS Code内部のNotificationService経由、エラーレベル）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（onSaveErrorコールバック） |
| 優先度 | 高（エラー通知） |
| リトライ | ユーザー操作による（リトライボタン提供） |

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

ファイル保存を試みたユーザーに対して表示される。

## 通知テンプレート

### アプリ内通知の場合

| 項目 | 内容 |
|-----|------|
| 深刻度 | Error（エラー） |
| 形式 | テキスト + アクションボタン |

### 本文テンプレート

```
Failed to save '{0}': {1}
```

- `{0}`: 保存に失敗したファイル名（basename）
- `{1}`: エラーメッセージ（toErrorMessage関数で整形）

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| {0} | ファイル名 | basename(resource) | Yes |
| {1} | エラーメッセージ | toErrorMessage(error, false) | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ファイル操作 | Ctrl+S / 自動保存 / メニューから保存 | 保存失敗かつ特定エラー以外 | 一般的な保存エラー |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 保存成功 | ファイルが正常に保存された場合は通知せず |
| FILE_MODIFIED_SINCE | ファイル競合の場合は専用の通知が表示される |
| FILE_WRITE_LOCKED | 書き込みロックの場合は専用の通知が表示される |
| FILE_PERMISSION_DENIED | 権限エラーの場合は専用の通知が表示される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ファイル保存要求] --> B[TextFileEditorModel.save]
    B --> C{保存結果}
    C -->|成功| D[保存完了]
    C -->|失敗| E{エラー種別}
    E -->|FILE_MODIFIED_SINCE| F[競合解決通知]
    E -->|FILE_WRITE_LOCKED| G[書き込みロック通知]
    E -->|FILE_PERMISSION_DENIED| H[権限エラー通知]
    E -->|その他| I[一般エラー通知 genericSaveError]
    I --> J[アクションボタン提供]
    J --> K[Retry / SaveAs / Revert]
    D --> L[処理終了]
    F --> L
    G --> L
    H --> L
    K --> L
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| なし | - | データベースアクセスなし |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | データベースアクセスなし（ファイルシステム経由） |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 一般保存エラー | 特定カテゴリ以外の保存失敗 | エラーメッセージを表示、リトライ/名前を付けて保存/元に戻すオプションを提供 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | ユーザー操作による（無制限） |
| リトライ間隔 | ユーザー操作に依存 |
| リトライ対象エラー | 全ての一般保存エラー |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし（ユーザー操作に応じて発生） |
| 1日あたり上限 | なし |

### 配信時間帯

制限なし（ユーザー操作に応じて随時発生）

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

- ファイル名（basename）のみが表示され、フルパスは表示されない
- エラーメッセージはtoErrorMessage関数で整形され、スタックトレース等は除外される
- ローカライズ機能（nls.localize）を使用して多言語対応している

## 備考

- 通知はmodel.resourceごとに一意のID（hash）が付与され、重複表示を防止
- ファイルが保存または元に戻された場合、対応する通知は自動的に閉じられる
- アクションボタン（Retry, Save As, Revert）はprimaryActionsとして提供

---

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

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

### 推奨読解順序

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

テキストファイルモデルと保存エラーハンドラーの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | textfiles.ts | `src/vs/workbench/services/textfile/common/textfiles.ts` | ITextFileEditorModel、ISaveErrorHandlerインターフェース |
| 1-2 | files.ts | `src/vs/platform/files/common/files.ts` | FileOperationError、FileOperationResult列挙型 |

**読解のコツ**: FileOperationResultには様々なエラー種別が定義されている。

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

`TextFileSaveErrorHandler.onSaveError`メソッドの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | textFileSaveErrorHandler.ts | `src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts` | TextFileSaveErrorHandler.onSaveError()メソッド（104-191行目） |

**主要処理フロー**:
1. **104行目**: `onSaveError()`メソッドの定義開始
2. **113-135行目**: FILE_MODIFIED_SINCEの処理（競合解決）
3. **139-177行目**: その他のエラー処理
4. **140-143行目**: FILE_WRITE_LOCKEDとFILE_PERMISSION_DENIEDのチェック
5. **176行目**: 一般エラーの場合、`localize('genericSaveError', ...)`でメッセージ生成
6. **181-189行目**: 通知の表示とイベントハンドリング

#### Step 3: アクションボタンの実装を理解する

保存エラー時のアクションボタンを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | textFileSaveErrorHandler.ts | `src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts` | RetrySaveModelAction、SaveModelAsAction、RevertModelActionクラス |

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

```
TextFileEditorModel.save()
    │
    └─ 保存失敗
           │
           └─ TextFileSaveErrorHandler.onSaveError()
                  │
                  ├─ FILE_MODIFIED_SINCE ?
                  │      └─ 競合解決通知
                  │
                  ├─ FILE_WRITE_LOCKED ?
                  │      └─ ロック解除/上書きオプション
                  │
                  ├─ FILE_PERMISSION_DENIED ?
                  │      └─ 管理者権限で保存オプション
                  │
                  └─ その他のエラー
                         │
                         ├─ メッセージ生成
                         │   └─ localize('genericSaveError', ...)
                         │
                         ├─ アクション生成
                         │   ├─ RetrySaveModelAction
                         │   ├─ SaveModelAsAction
                         │   └─ RevertModelAction
                         │
                         └─ notificationService.notify()
```

### データフロー図

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

保存失敗イベント    ───▶ TextFileSaveErrorHandler      ───▶ エラー通知
(error, model)            │                                  + アクションボタン
                          ├─ エラー種別判定
                          │
                          ├─ メッセージ生成
                          │   ├─ basename(resource)
                          │   └─ toErrorMessage(error)
                          │
                          └─ NotificationService
                              └─ notify({severity: Error})
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| textFileSaveErrorHandler.ts | `src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts` | ソース | 保存エラーハンドラー、onSaveError()の実装 |
| textfiles.ts | `src/vs/workbench/services/textfile/common/textfiles.ts` | ソース | ITextFileEditorModel、ISaveErrorHandlerインターフェース |
| files.ts | `src/vs/platform/files/common/files.ts` | ソース | FileOperationError、FileOperationResult |
| notification.ts | `src/vs/platform/notification/common/notification.ts` | ソース | 通知サービスのインターフェース定義 |
| errorMessage.ts | `src/vs/base/common/errorMessage.ts` | ソース | toErrorMessage関数 |
| resources.ts | `src/vs/base/common/resources.ts` | ソース | basename関数 |
