# 機能設計書: エクスプローラー

## 1. 機能概要

### 1.1 機能名
エクスプローラー（Explorer）

### 1.2 機能ID
No.21

### 1.3 概要説明
エクスプローラー機能は、VSCodeのサイドバーに表示されるファイルシステムナビゲーション機能である。ワークスペース内のファイルとフォルダをツリー構造で表示し、ファイルの作成、削除、名前変更、移動などの基本的なファイル操作を提供する。また、ファイルの検索、フィルタリング、ドラッグ&ドロップによるファイル移動などの高度な機能も備える。

### 1.4 関連画面
- エクスプローラービュー（サイドバー）
- ファイルツリー
- オープンエディターセクション

## 2. 機能要件

### 2.1 ビジネス要件
- ユーザーがワークスペース内のファイル構造を視覚的に把握できること
- ファイルやフォルダの基本操作（CRUD）が直感的に行えること
- 複数のルートフォルダ（マルチルートワークスペース）をサポートすること
- ファイル変更の自動検出と表示の更新が行われること

### 2.2 機能要件詳細

| 要件ID | 要件名 | 説明 |
|--------|--------|------|
| EXP-001 | ファイルツリー表示 | ワークスペース内のファイルとフォルダを階層構造で表示 |
| EXP-002 | ファイル作成 | 新規ファイル/フォルダの作成機能 |
| EXP-003 | ファイル削除 | ファイル/フォルダの削除機能（ゴミ箱への移動） |
| EXP-004 | 名前変更 | ファイル/フォルダの名前変更機能 |
| EXP-005 | ドラッグ&ドロップ | ファイルの移動・コピー機能 |
| EXP-006 | ファイル監視 | ファイルシステムの変更を自動検出 |
| EXP-007 | フィルタリング | ファイル名による絞り込み表示 |
| EXP-008 | コンテキストメニュー | 右クリックによる操作メニュー表示 |

## 3. アーキテクチャ設計

### 3.1 コンポーネント構成

```
┌─────────────────────────────────────────────────────────┐
│                    Explorer View                        │
│  ┌──────────────────────────────────────────────────┐  │
│  │              ExplorerViewlet                      │  │
│  │  ┌────────────────┐  ┌─────────────────────────┐ │  │
│  │  │ OpenEditors    │  │  ExplorerView           │ │  │
│  │  │ View           │  │  ┌───────────────────┐  │ │  │
│  │  └────────────────┘  │  │   ExplorerTree    │  │ │  │
│  │                      │  │   (AsyncDataTree) │  │ │  │
│  │                      │  └───────────────────┘  │ │  │
│  │                      └─────────────────────────┘ │  │
│  └──────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│                  ExplorerService                        │
│  ┌────────────────────────────────────────────────────┐│
│  │  - roots: ExplorerItem[]                           ││
│  │  - onDidChangeItem: Event                          ││
│  │  - refresh(): Promise<void>                        ││
│  │  - findClosest(): ExplorerItem                     ││
│  └────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│                   ExplorerModel                         │
│  ┌────────────────────────────────────────────────────┐│
│  │  ExplorerItem                                      ││
│  │  - resource: URI                                   ││
│  │  - name: string                                    ││
│  │  - isDirectory: boolean                            ││
│  │  - children: Map<string, ExplorerItem>             ││
│  │  - parent: ExplorerItem                            ││
│  └────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────┘
```

### 3.2 クラス図

```
┌─────────────────────────┐
│    IExplorerService     │
│     <<interface>>       │
├─────────────────────────┤
│ + roots: ExplorerItem[] │
│ + getContext(): URI     │
│ + setToCopy()          │
│ + setEditable()        │
│ + findClosest()        │
│ + refresh()            │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐
│    ExplorerService      │
├─────────────────────────┤
│ - _roots: ExplorerItem[]│
│ - _sortOrder: string    │
│ - _onDidChange: Emitter │
├─────────────────────────┤
│ + constructor()         │
│ + getContext()          │
│ + refresh()             │
│ - handleFileOperation() │
└─────────────────────────┘

┌─────────────────────────┐
│     ExplorerItem        │
├─────────────────────────┤
│ - _resource: URI        │
│ - _name: string         │
│ - _isDirectory: boolean │
│ - _children: Map        │
│ - _parent: ExplorerItem │
├─────────────────────────┤
│ + get resource()        │
│ + get name()            │
│ + get children()        │
│ + addChild()            │
│ + removeChild()         │
│ + forgetChildren()      │
└─────────────────────────┘
```

## 4. 詳細設計

### 4.1 データ構造

#### ExplorerItem
```typescript
interface ExplorerItem {
    resource: URI;           // ファイル/フォルダのURI
    name: string;            // 表示名
    isDirectory: boolean;    // ディレクトリフラグ
    isSymbolicLink: boolean; // シンボリックリンクフラグ
    readonly: boolean;       // 読み取り専用フラグ
    mtime: number;           // 更新日時
    etag?: string;           // エンティティタグ
    children?: Map<string, ExplorerItem>; // 子要素
    parent?: ExplorerItem;   // 親要素
    isError: boolean;        // エラー状態フラグ
    isExcluded: boolean;     // 除外フラグ
    nestedParent?: ExplorerItem; // ネスト親要素
}
```

### 4.2 処理フロー

#### ファイルツリー初期化フロー
```
1. ExplorerViewlet.create()
   │
   ├─2. ExplorerService.constructor()
   │    │
   │    └─ ワークスペースルートの初期化
   │
   ├─3. ExplorerView.renderBody()
   │    │
   │    └─ AsyncDataTreeの作成
   │
   └─4. ExplorerService.refresh()
        │
        ├─ ファイルサービスからルートの読み込み
        │
        └─ ツリーのレンダリング
```

#### ファイル操作フロー
```
1. ユーザー操作（コンテキストメニュー/キーボード）
   │
   ├─2. FileAction.run()
   │    │
   │    ├─ BulkFileOperations経由でファイル操作
   │    │
   │    └─ ExplorerService.handleFileOperation()
   │
   └─3. FileService.onDidFilesChange
        │
        └─ ExplorerService._onDidChangeItem.fire()
             │
             └─ ExplorerView.refresh()
```

### 4.3 主要メソッド

#### ExplorerService.refresh()
```typescript
async refresh(resource?: URI): Promise<void> {
    // 1. リソース指定がある場合はそのアイテムのみ更新
    if (resource) {
        const item = this.findClosest(resource);
        if (item) {
            await this._onDidChangeItem.fire({ item, recursive: true });
        }
        return;
    }

    // 2. 全ルートの再読み込み
    const roots = await Promise.all(
        this.contextService.getWorkspace().folders.map(folder =>
            this._resolveRoot(folder)
        )
    );

    // 3. ルートの設定と通知
    this._roots = roots;
    this._onDidChangeItem.fire(undefined);
}
```

#### ExplorerItem.addChild()
```typescript
addChild(child: ExplorerItem): void {
    // 1. 子マップの初期化
    if (!this._children) {
        this._children = new Map();
    }

    // 2. 子の追加
    this._children.set(child.name, child);
    child._parent = this;
}
```

## 5. インターフェース設計

### 5.1 サービスインターフェース

```typescript
interface IExplorerService {
    readonly _serviceBrand: undefined;

    // プロパティ
    readonly roots: ExplorerItem[];
    readonly sortOrderConfiguration: ExplorerSortOrderConfiguration;

    // イベント
    readonly onDidChangeItem: Event<ExplorerItem | undefined>;
    readonly onDidChangeEditable: Event<ExplorerItem>;
    readonly onDidSelectResource: Event<{ resource?: URI; reveal?: boolean | string }>;

    // メソッド
    getContext(respectMultiSelection: boolean, ignoreNestedChildren?: boolean): URI[];
    hasViewFocus(): boolean;
    setEditable(stat: ExplorerItem, data: IEditableData | null): Promise<void>;
    setToCopy(stats: ExplorerItem[], cut: boolean): Promise<void>;
    isCut(stat: ExplorerItem): boolean;
    getEditable(): { stat: ExplorerItem; data: IEditableData } | undefined;
    getEditableData(stat: ExplorerItem): IEditableData | undefined;
    findClosest(resource: URI): ExplorerItem | null;
    findClosestRoot(resource: URI): ExplorerItem | null;
    refresh(): Promise<void>;
    select(resource: URI, reveal?: boolean | string): Promise<void>;
    registerView(contextAndRefreshProvider: IExplorerView): void;
}
```

### 5.2 ビューインターフェース

```typescript
interface IExplorerView {
    getContext(respectMultiSelection: boolean): ExplorerItem[];
    refresh(recursive: boolean, item?: ExplorerItem, cancelEditing?: boolean): Promise<void>;
    selectResource(resource: URI | undefined, reveal?: boolean | string, retry?: number): Promise<void>;
    setTreeInput(): Promise<void>;
    setEditable(stat: ExplorerItem, isEditing: boolean): Promise<void>;
    isItemVisible(item: ExplorerItem): boolean;
    hasFocus(): boolean;
}
```

## 6. エラーハンドリング

### 6.1 エラー種別

| エラーコード | エラー名 | 説明 | 対処方法 |
|-------------|---------|------|---------|
| EXP-E001 | FileNotFound | ファイルが見つからない | ツリーから該当アイテムを削除 |
| EXP-E002 | PermissionDenied | 権限不足 | エラーメッセージを表示 |
| EXP-E003 | FileExists | 同名ファイルが存在 | 上書き確認ダイアログを表示 |
| EXP-E004 | DiskFull | ディスク容量不足 | エラーメッセージを表示 |
| EXP-E005 | InvalidPath | 無効なパス | 入力値の検証エラーを表示 |

### 6.2 エラーハンドリングフロー

```
1. ファイル操作実行
   │
   ├─ 成功 → ツリー更新
   │
   └─ 失敗
        │
        ├─ FileNotFound → アイテム削除 + 警告表示
        │
        ├─ PermissionDenied → エラーダイアログ表示
        │
        └─ その他 → 一般エラーダイアログ表示
```

## 7. パフォーマンス考慮事項

### 7.1 最適化戦略

- **遅延読み込み**: ディレクトリ展開時に子要素を読み込み
- **仮想スクロール**: 大量のファイルでも高速表示
- **デバウンス**: ファイル変更イベントの集約
- **キャッシュ**: ファイル統計情報のキャッシュ

### 7.2 パフォーマンス目標

| 指標 | 目標値 |
|------|--------|
| 初期表示時間 | < 200ms |
| ディレクトリ展開時間 | < 100ms |
| ファイル操作レスポンス | < 50ms |
| メモリ使用量（10万ファイル） | < 100MB |

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

### 8.1 セキュリティ対策

- ファイルパスのサニタイズ（パストラバーサル防止）
- 信頼されていないワークスペースでの制限モード
- シンボリックリンクの安全な処理
- 除外パターンによる機密ファイルの非表示

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

### 9.1 推奨読解順序

1. **データモデル**: `src/vs/workbench/contrib/files/common/explorerModel.ts`
   - **1-50行目**: ExplorerItemクラスの基本構造
   - **51-150行目**: プロパティ定義（resource, name, children等）
   - **151-300行目**: ファイル/フォルダ操作メソッド

2. **サービス層**: `src/vs/workbench/contrib/files/browser/explorerService.ts`
   - **1-70行目**: IExplorerServiceインターフェース定義
   - **71-150行目**: ExplorerServiceクラスのプロパティとコンストラクタ
   - **151-250行目**: refresh()メソッドの実装
   - **251-350行目**: findClosest()、select()メソッド

3. **ビュー層**: `src/vs/workbench/contrib/files/browser/views/explorerView.ts`
   - **1-100行目**: インポートとコンテキストキー定義
   - **101-300行目**: ExplorerViewクラスの初期化
   - **301-500行目**: ツリーレンダリングとイベントハンドリング

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

```
ExplorerViewlet
├── OpenEditorsView
│   └── OpenEditorsDelegate
└── ExplorerView
    ├── ExplorerService
    │   ├── FileService (IFileService)
    │   ├── WorkspaceContextService
    │   └── ConfigurationService
    ├── AsyncDataTree
    │   ├── ExplorerDataSource
    │   ├── ExplorerRenderer
    │   ├── ExplorerAccessibilityProvider
    │   └── ExplorerDragAndDrop
    └── ExplorerDecorationsProvider
```

### 9.3 データフロー図

```
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   FileSystem    │────▶│   FileService   │────▶│ ExplorerService │
│    (Native)     │     │                 │     │                 │
└─────────────────┘     └─────────────────┘     └────────┬────────┘
                                                         │
                                                         ▼
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   User Input    │────▶│  ExplorerView   │◀────│  ExplorerModel  │
│  (Click/Key)    │     │   (AsyncTree)   │     │  (ExplorerItem) │
└─────────────────┘     └─────────────────┘     └─────────────────┘
```

### 9.4 関連ファイル一覧

| パス | 種別 | 役割 |
|------|------|------|
| `src/vs/workbench/contrib/files/common/explorerModel.ts` | モデル | ExplorerItemクラス定義 |
| `src/vs/workbench/contrib/files/browser/explorerService.ts` | サービス | エクスプローラーサービス実装 |
| `src/vs/workbench/contrib/files/browser/views/explorerView.ts` | ビュー | エクスプローラービュー実装 |
| `src/vs/workbench/contrib/files/browser/views/openEditorsView.ts` | ビュー | オープンエディタービュー |
| `src/vs/workbench/contrib/files/browser/fileActions.ts` | アクション | ファイル操作アクション |
| `src/vs/workbench/contrib/files/common/files.ts` | 共通 | 定数・インターフェース定義 |
| `src/vs/workbench/contrib/files/browser/fileImportExport.ts` | ユーティリティ | インポート/エクスポート機能 |

## 10. 変更履歴

| 日付 | バージョン | 変更内容 | 作成者 |
|------|-----------|---------|--------|
| 2026-01-27 | 1.0 | 初版作成 | Claude |
