# 機能設計書: 出力パネル

## 1. 機能概要

### 1.1 機能名
出力パネル（Output Panel）

### 1.2 機能ID
No.29

### 1.3 概要説明
出力パネル機能は、VSCodeの各種サービスや拡張機能からのログ出力を表示するパネルである。複数の出力チャンネルを管理し、ログレベルによるフィルタリング、テキスト検索、自動スクロールロックなどの機能を提供する。拡張機能はAPIを通じて独自の出力チャンネルを作成できる。

### 1.4 関連画面
- 出力パネル（下部パネル）
- チャンネル選択ドロップダウン
- フィルタ入力

## 2. 機能要件

### 2.1 ビジネス要件
- 複数の出力チャンネルを管理できること
- ログレベルによるフィルタリングが可能なこと
- テキスト検索でログを絞り込めること
- 自動スクロールを制御できること

### 2.2 機能要件詳細

| 要件ID | 要件名 | 説明 |
|--------|--------|------|
| OUT-001 | チャンネル管理 | 複数出力チャンネルの管理 |
| OUT-002 | ログ表示 | チャンネルのログ内容表示 |
| OUT-003 | レベルフィルタ | Trace/Debug/Info/Warning/Error |
| OUT-004 | テキストフィルタ | テキストによるフィルタリング |
| OUT-005 | 自動スクロール | スクロールロック制御 |
| OUT-006 | クリア | ログのクリア |
| OUT-007 | コピー | ログ内容のコピー |
| OUT-008 | ファイル表示 | ログファイルとして表示 |

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

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

```
┌─────────────────────────────────────────────────────────┐
│                   Output View Pane                      │
│  ┌──────────────────────────────────────────────────┐  │
│  │  Filter Input (FilterWidget)                      │  │
│  ├──────────────────────────────────────────────────┤  │
│  │  Output Editor (CodeEditorWidget)                 │  │
│  │  ┌────────────────────────────────────────────┐  │  │
│  │  │  [INFO] Application started                │  │  │
│  │  │  [DEBUG] Loading configuration...          │  │  │
│  │  │  [WARNING] Config file not found           │  │  │
│  │  │  [ERROR] Failed to connect                 │  │  │
│  │  └────────────────────────────────────────────┘  │  │
│  └──────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│                   IOutputService                        │
│  ┌────────────────────────────────────────────────────┐│
│  │  - channels: IOutputChannel[]                      ││
│  │  - activeChannel: IOutputChannel                   ││
│  │  - filters: IOutputViewFilters                     ││
│  └────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────┘
```

### 3.2 クラス図

```
┌─────────────────────────┐
│    OutputViewPane       │
│   extends FilterViewPane│
├─────────────────────────┤
│ - editor: OutputEditor  │
│ - channelId             │
│ - scrollLock            │
│ - memento               │
├─────────────────────────┤
│ + showChannel()         │
│ + focus()               │
│ + clearFilterText()     │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐      ┌─────────────────────────┐
│     OutputEditor        │      │   IOutputViewFilters    │
│ extends TextResource    │      │    <<interface>>        │
│          Editor         │      ├─────────────────────────┤
├─────────────────────────┤      │ + text                  │
│ + getId()               │      │ + trace                 │
│ + getTitle()            │      │ + debug                 │
│ + getConfigOverrides()  │      │ + info                  │
│ + getAriaLabel()        │      │ + warning               │
└─────────────────────────┘      │ + error                 │
                                 │ + categories            │
                                 └─────────────────────────┘
```

## 4. 詳細設計

### 4.1 データ構造

#### IOutputViewState
```typescript
interface IOutputViewState {
    filter?: string;
    showTrace?: boolean;
    showDebug?: boolean;
    showInfo?: boolean;
    showWarning?: boolean;
    showError?: boolean;
    categories?: string;
}
```

#### IOutputChannel
```typescript
interface IOutputChannel {
    readonly id: string;
    readonly label: string;
    readonly uri: URI;

    // 操作
    append(output: string): void;
    replace(output: string): void;
    clear(): void;
    dispose(): void;
}
```

### 4.2 処理フロー

#### チャンネル切り替えフロー
```
1. チャンネル選択
   │
   ├─2. OutputViewPane.setInput()
   │    │
   │    ├─ channelIdの更新
   │    │
   │    └─ checkMoreFilters()
   │
   └─3. OutputEditor.setInput()
        │
        ├─ TextResourceEditorInput作成
        │
        └─ エディタモデル設定
```

### 4.3 主要メソッド

#### OutputViewPane.showChannel()
```typescript
showChannel(channel: IOutputChannel, preserveFocus: boolean): void {
    if (this.channelId !== channel.id) {
        this.setInput(channel);
    }
    if (!preserveFocus) {
        this.focus();
    }
}
```

#### OutputViewPane.renderBody()
```typescript
protected override renderBody(container: HTMLElement): void {
    super.renderBody(container);
    this.editor.create(container);
    container.classList.add('output-view');

    const codeEditor = <ICodeEditor>this.editor.getControl();
    codeEditor.setAriaOptions({ role: 'document', activeDescendant: undefined });

    // モデル変更時の自動スクロール
    this._register(codeEditor.onDidChangeModelContent(() => {
        if (!this.scrollLock) {
            this.editor.revealLastLine();
        }
    }));

    // スマートスクロール
    this._register(codeEditor.onDidChangeCursorPosition((e) => {
        if (e.reason !== CursorChangeReason.Explicit) {
            return;
        }
        // 最終行でない場合はスクロールロック
        const model = codeEditor.getModel();
        if (model) {
            const lastLine = model.getLineCount();
            this.scrollLock = lastLine !== e.position.lineNumber;
        }
    }));
}
```

#### OutputEditor.getConfigurationOverrides()
```typescript
protected override getConfigurationOverrides(configuration: IEditorConfiguration): ICodeEditorOptions {
    const options = super.getConfigurationOverrides(configuration);
    options.wordWrap = 'on';
    options.lineNumbers = 'off';
    options.glyphMargin = false;
    options.folding = false;
    options.scrollBeyondLastLine = false;
    options.renderLineHighlight = 'none';
    options.minimap = { enabled: false };
    options.readOnly = true;
    options.domReadOnly = true;
    return options;
}
```

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

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

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

    // チャンネル管理
    readonly channels: readonly IOutputChannel[];
    readonly activeChannel: IOutputChannel | undefined;
    getChannel(id: string): IOutputChannel | undefined;
    showChannel(id: string, preserveFocus?: boolean): void;

    // フィルタ
    readonly filters: IOutputViewFilters;

    // イベント
    readonly onActiveOutputChannel: Event<string>;
}
```

### 5.2 フィルタインターフェース

```typescript
interface IOutputViewFilters {
    text: string;
    trace: boolean;
    debug: boolean;
    info: boolean;
    warning: boolean;
    error: boolean;
    categories: string;

    readonly onDidChange: Event<void>;
}
```

## 6. コンテキストキー

```typescript
// 出力関連コンテキストキー
const CONTEXT_IN_OUTPUT: RawContextKey<boolean>;
const CONTEXT_OUTPUT_SCROLL_LOCK: RawContextKey<boolean>;
const OUTPUT_FILTER_FOCUS_CONTEXT: RawContextKey<boolean>;
const HIDE_CATEGORY_FILTER_CONTEXT: RawContextKey<boolean>;
```

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

### 7.1 推奨読解順序

1. **ビュー層**: `src/vs/workbench/contrib/output/browser/outputView.ts`
   - **53-61行目**: IOutputViewStateインターフェース
   - **63-126行目**: OutputViewPaneクラス
   - **128-135行目**: showChannel()メソッド
   - **146-173行目**: renderBody()メソッド

2. **エディタ層**: 同ファイル
   - **229-300行目**: OutputEditorクラス

3. **出力サービス**: `src/vs/workbench/services/output/common/output.ts`
   - IOutputService、IOutputChannelインターフェース

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

```
OutputViewPane
├── FilterWidget
│   └── IOutputViewFilters
├── OutputEditor
│   └── CodeEditorWidget
│       └── TextModel (Output content)
└── IOutputService
    ├── IOutputChannel[]
    └── Filters
```

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

| パス | 種別 | 役割 |
|------|------|------|
| `src/vs/workbench/contrib/output/browser/outputView.ts` | ビュー | 出力ビュー実装 |
| `src/vs/workbench/services/output/common/output.ts` | サービス | 出力サービス定義 |
| `src/vs/workbench/services/output/common/outputChannelModel.ts` | モデル | チャンネルモデル |

## 8. 変更履歴

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