# 機能設計書 101-コマンド履歴

## 概要

本ドキュメントは、Windows Console Host (conhost.exe) におけるコマンド入力履歴の管理機能について記述する。CommandHistoryクラスを中心に、コマンドの追加・取得・検索・削除・リサイズ等の操作と、Win32 Console API経由での外部公開インターフェースを設計レベルで詳述する。

### 本機能の処理概要

**業務上の目的・背景**：コンソールアプリケーションにおいて、ユーザーが過去に入力したコマンドを再利用できるようにすることは、操作効率を大幅に向上させる基本機能である。Windowsコンソールでは、上下矢印キーで履歴をナビゲートしたり、F7キーで履歴一覧を表示したりする機能が古くから提供されている。本機能はそれらを支える内部データ管理を担う。

**機能の利用シーン**：コマンドプロンプト(cmd.exe)やPowerShellなどのCUIアプリケーションがConsole Hostで動作する際に利用される。ユーザーが上矢印キーで前のコマンドを呼び出したり、doskey /historyで履歴一覧を表示したりするシーンで使用される。また、Win32 Console API (GetConsoleCommandHistory等) を通じてプログラムからも履歴にアクセスできる。

**主要な処理内容**：
1. アプリケーション名(EXE名)ごとにコマンド履歴バッファを管理する
2. コマンドの追加時に重複抑制オプションを提供する
3. 上下方向のナビゲーション(前のコマンド/次のコマンド)をサポートする
4. プレフィックスマッチおよび完全一致でのコマンド検索を行う
5. LRU(Least Recently Used)方式で履歴バッファを管理し、最大数を超えた場合は古いものから削除する
6. Win32 Console API (ExpungeConsoleCommandHistory, GetConsoleCommandHistory, SetConsoleNumberOfCommands等) を通じて外部公開する

**関連システム・外部連携**：Win32 Console API (kernel32.dll) を通じてクライアントプロセスと連携する。A版(ANSI)とW版(Unicode)の両方のAPIを提供し、コードページ変換を行う。

**権限による制御**：特段のロール制御はないが、コンソールのロック機構(LockConsole/UnlockConsole)によるスレッドセーフティが確保されている。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | コンソールウィンドウ | 主画面 | 上下矢印キーによるコマンド履歴のナビゲーション |
| - | F7履歴ポップアップ | 補助画面 | 履歴一覧の表示と選択 |

## 機能種別

データ管理（CRUD操作）/ メモリ内データ操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| appName | wstring_view | Yes | アプリケーション名(EXE名) | 空でないこと |
| processHandle | HANDLE | Yes | クライアントプロセスのハンドル | 有効なハンドル |
| command | wstring_view | Yes | 追加するコマンド文字列 | 空文字の場合はスキップ |
| suppressDuplicates | bool | No | 重複コマンドを抑制するか | - |
| searchDirection | SearchDirection | No | 検索方向(Previous/Next) | - |
| matchOptions | MatchOptions | No | マッチオプション(ExactMatch/JustLooking) | - |

### 入力データソース

- コンソール入力バッファからの確定済みコマンドライン
- Win32 Console API経由のプログラムからのリクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| command | wstring_view | 取得されたコマンド文字列 |
| indexFound | Index(int32_t) | 検索で見つかったコマンドのインデックス |
| commandCount | Index | 格納されているコマンド数 |
| historyLength | size_t | 全履歴を格納するのに必要なバッファサイズ |

### 出力先

- コマンドライン編集バッファへの復元
- Win32 Console API経由でのクライアントプロセスへの返却

## 処理フロー

### 処理シーケンス

```
1. コマンド追加 (Add)
   └─ 空コマンドは無視、重複抑制時は既存を削除して末尾に移動
      └─ 最大数到達時は先頭(最古)を削除
         └─ LastDisplayedを更新しリセットフラグを設定

2. コマンド取得 (Retrieve)
   └─ Previous方向: リセット状態なら現在位置、そうでなければデクリメント
   └─ Next方向: インクリメント
      └─ RetrieveNthで範囲クランプして返却

3. コマンド検索 (FindMatchingCommand)
   └─ 開始インデックスから逆方向に全履歴を走査
      └─ プレフィックスマッチまたは完全一致で判定
         └─ 見つかればtrueとインデックスを返却

4. バッファ割り当て (s_Allocate)
   └─ 同名EXEの未割り当てバッファを再利用
      └─ なければ新規作成(上限チェック)
         └─ それもなければLRUバッファを再利用
            └─ リストの先頭に移動(MRU管理)
```

### フローチャート

```mermaid
flowchart TD
    A[コマンド入力確定] --> B{コマンドが空?}
    B -->|Yes| Z[何もしない]
    B -->|No| C{前回と同一?}
    C -->|Yes| Z
    C -->|No| D{重複抑制ON?}
    D -->|Yes| E[既存の同一コマンドを検索]
    E --> F{見つかった?}
    F -->|Yes| G[既存を削除し文字列を再利用]
    F -->|No| H[新規追加]
    D -->|No| H
    G --> I{最大数到達?}
    H --> I
    I -->|Yes| J[先頭の最古コマンドを削除]
    I -->|No| K[末尾に追加]
    J --> K
    K --> L[LastDisplayedをリセット]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-101-1 | 重複抑制 | suppressDuplicatesがtrueの場合、同一コマンドが既に存在すれば既存を削除して末尾に移動 | Add呼び出し時 |
| BR-101-2 | LRU管理 | 最大コマンド数に到達した場合、最も古いコマンド(先頭)を削除して新しいコマンドを追加 | 最大数到達時 |
| BR-101-3 | EXE別管理 | コマンド履歴はアプリケーション名(EXE名)ごとに独立して管理される | 常時 |
| BR-101-4 | 大文字小文字無視 | EXE名の比較はCompareStringOrdinalのIgnoreCase=TRUEで行う | EXE名比較時 |
| BR-101-5 | リセット状態 | 履歴追加やEscapeキー押下時にCLE_RESETフラグがセットされ、次の取得操作で現在位置から返却する | Retrieve時 |

### 計算ロジック

- LastDisplayedインデックスは0からGetNumberOfCommands()-1の範囲にクランプされる
- _Prev/_Nextはコマンド数に基づいてラップアラウンドする
- _Inc/_Decは_maxCommandsに基づいてラップアラウンドする

## データベース操作仕様

### 操作別データベース影響一覧

本機能はデータベースを使用しない。メモリ内のstd::vector<std::wstring>とstd::list<CommandHistory>で管理される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| E_OUTOFMEMORY | メモリ不足 | _maxCommandsが0の場合 | HRESULTを返却 |
| FAIL_FAST | 致命的エラー | 未割り当てバッファへのAdd | プロセスクラッシュ |
| E_INVALIDARG | 引数不正 | 不正なインデックス指定 | HRESULTを返却 |

### リトライ仕様

リトライは不要。メモリ操作のため失敗時は即座にエラーを返却する。

## トランザクション仕様

トランザクション管理は不要。LockConsole/UnlockConsoleによるスレッド排他制御で一貫性を保証する。

## パフォーマンス要件

- コマンドの追加・取得はO(1)（末尾への追加、インデックスアクセス）
- 検索はO(n)（全履歴を走査）
- 重複抑制時のRemoveはO(n)（要素の削除とシフト）
- デフォルトの最大コマンド数は設定依存（ConsoleInformation::GetHistoryBufferSize()）

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

- コマンド履歴にはパスワード等の機密情報が含まれる可能性がある
- 履歴はプロセスごとに分離されており、他プロセスからは直接アクセスできない
- Win32 Console APIを通じたアクセスはコンソールセッション内に限定される

## 備考

- 元のconhost v1ではCircular Bufferを使用していたが、C++リファクタリング時にstd::vectorに変更された（コード内コメントで言及）
- s_historyListsはstd::listを使用しており、これはLRU管理のための要素のsplice操作でイテレータを無効化しないためである

---

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

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

### 推奨読解順序

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

まず、CommandHistoryクラスの構造と公開インターフェースを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | history.h | `src/host/history.h` | CommandHistoryクラスの定義、メンバ変数、公開メソッド |

**読解のコツ**:
- **6-9行目**: CommandHistoryクラスの基本型定義。IndexはInt32_tのエイリアス
- **12-14行目**: CLE_ALLOCATED/CLE_RESETフラグの定義。ビットフラグで状態管理
- **24-35行目**: MatchOptionsとSearchDirectionの列挙型。検索動作を制御
- **78行目**: _commandsはstd::vector<std::wstring>で、実際のコマンド文字列を格納
- **84行目**: s_historyListsは静的メンバで、全アプリケーションの履歴をstd::listで管理

#### Step 2: コア実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | history.cpp | `src/host/history.cpp` | CommandHistoryクラスの実装全体 |

**主要処理フロー**:
1. **35-47行目**: s_Find - プロセスハンドルによる履歴バッファ検索
2. **89-154行目**: Add - コマンド追加のメインロジック。重複抑制、LRU削除、リセット処理を含む
3. **170-204行目**: Retrieve/RetrieveNth - 方向指定での履歴取得とインデックスクランプ
4. **291-365行目**: s_Allocate - 履歴バッファのLRU方式での割り当て。同名EXE再利用、新規作成、LRU再利用の3段階
5. **432-477行目**: FindMatchingCommand - プレフィックスマッチによるコマンド検索

#### Step 3: Win32 Console APIインターフェース

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | history.cpp | `src/host/history.cpp` | ファイル後半のApiRoutines群 |

**主要処理フロー**:
- **509-520行目**: ExpungeConsoleCommandHistoryAImpl - A版(ANSI)からW版への変換
- **528-544行目**: ExpungeConsoleCommandHistoryWImpl - 指定EXEの全履歴をクリア
- **602-643行目**: GetConsoleCommandHistoryLengthImplHelper - 履歴全体のバッファサイズ計算
- **706-764行目**: GetConsoleCommandHistoryWImplHelper - 全履歴をNull区切りで出力バッファに書き込み

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

```
CommandHistory (静的メンバ s_historyLists)
    |
    +-- s_Allocate(appName, processHandle)   ... 新規プロセス接続時
    |       +-- s_Find / IsAppNameMatch       ... 既存バッファ検索
    |       +-- Realloc                       ... バッファサイズ変更
    |
    +-- Add(command, suppressDuplicates)      ... コマンド確定時
    |       +-- FindMatchingCommand           ... 重複チェック
    |       +-- Remove                        ... 重複削除
    |       +-- _Reset                        ... 状態リセット
    |
    +-- Retrieve(searchDirection)             ... 上下矢印キー
    |       +-- RetrieveNth                   ... インデックスクランプ
    |
    +-- FindMatchingCommand                   ... F8キー等
    |       +-- _Prev                         ... インデックス移動
    |
    +-- ApiRoutines::*                        ... Win32 API経由
            +-- ExpungeConsoleCommandHistory   ... 履歴クリア
            +-- GetConsoleCommandHistory       ... 履歴取得
            +-- SetConsoleNumberOfCommands     ... バッファサイズ変更
            +-- GetConsoleCommandHistoryLength ... バッファサイズ照会
```

### データフロー図

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

コマンドライン入力 -------> CommandHistory::Add ---------> _commands (vector)
                               |
上下矢印キー ------------> CommandHistory::Retrieve -----> コマンドライン編集バッファ
                               |
F8キー(プレフィックス) ---> FindMatchingCommand ---------> マッチしたコマンド
                               |
Win32 API呼び出し --------> ApiRoutines::* --------------> クライアントバッファ
                               |                            (A/W変換含む)
コンソール設定 -----------> s_ResizeAll -----------------> 全バッファのサイズ変更
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| history.h | `src/host/history.h` | ソース(ヘッダ) | CommandHistoryクラスの宣言 |
| history.cpp | `src/host/history.cpp` | ソース(実装) | CommandHistoryクラスの実装およびWin32 API実装 |
| ApiRoutines.h | `src/host/ApiRoutines.h` | ソース(ヘッダ) | Win32 Console APIルーティンの宣言 |
| srvinit.h | `src/host/srvinit.h` | ソース(ヘッダ) | コンソール初期化関連 |
| convert.hpp | `src/types/inc/convert.hpp` | ソース(ヘッダ) | A/W文字列変換ユーティリティ |
