> [!left-bubble] ![[chappy.webp]]
[[Codex CLI]] x [[GPT-5.3-Codex]] のプランです。
## window_hints のキー衝突解消(prefix-free化)計画
### 概要
appPrefixOverrides で2文字prefixを使ったときに、1文字キー(例: G)が2文字キー(例: GC)の接頭辞になると即確定で選択不能になる問題を解消します。
方針は、最終的に表示される全ヒントキー集合を prefix-free(どのキーも他キーの接頭辞にならない) に自動再割当することです。
これにより、提示期待どおり G は GA に延長され、GC はそのまま使えます。
### 公開仕様の変更点
- 設定スキーマ変更なし(appPrefixOverrides の形式は現状維持)。
- 挙動変更:
1. ヒントキー生成後、prefix衝突がある場合は自動的に短いキーを延長する。
2. 延長文字は hintChars の順で最初に使える文字を採用する。
3. 明示指定prefixでも、他キーの接頭辞になる場合は延長対象になる(prefix-free優先)。
### 実装方針(decision complete)
1. window_hints.lua に prefix衝突解消ヘルパーを追加
- isPrefixOf(a, b):
- a ~= b かつ b が a で始まるか判定。
- hasAnyPrefixConflict(keys):
- キー集合に strict prefix 関係があるか判定。
- findExpandedKey(baseKey, otherKeys, hintChars):
- baseKey + suffix 候補を hintChars 順で探索。
- suffix長は 1 文字で見つからなければ 2 文字、3文字…と段階的に拡張。
- 候補条件:
- 既存キーと完全一致しない
- 既存キーの接頭辞でもない
- 既存キーから接頭辞にされない
- makeKeysPrefixFree(hints, hintChars):
- hints[i].key を入力として反復。
- 「他キーの接頭辞になっているキー」を検出し、findExpandedKey で延長。
- 衝突がなくなるまでループ。
- 結果を hint.key, hint.keyText, hint.displayKeyText に反映。
2. 既存生成フローへの組み込み
- buildHintEntries(entries) の末尾で makeKeysPrefixFree(hints, hintChars) を呼ぶ。
- その後 hints を返す。
- hintByKey 構築や handleChar は既存ロジックを維持(prefix-free化で即確定問題を根本解消)。
3. 並び順の安定化
- prefix-free化でキーが変わるため、必要に応じて hints を最終キー順(既存 comparePrefixes)で再ソートして表示順を安定化。
4. README更新
- appPrefixOverrides の節に「キーは内部でprefix-free化される」旨を追記。
- 例として:
- Ghostty: G, Chrome: GC -> Ghostty: GA, Chrome: GC
- Ghostty: G, Chrome x2: GCA/GCS -> Ghostty: GA, Chrome: GCA/GCS
を追加。
### テスト計画
spec/window_hints_spec.lua を拡張して、内部ヘルパーを対象に以下を追加。
1. G と GC の衝突で G -> GA, GC 維持になる。
2. G と GCA,GCS の衝突で G -> GA になる。
3. G,GA,GC のように GA が既に使われている場合、G が次候補(例: GS)へ進む。
4. 多段衝突(例: A, AB, ABC)でも最終集合がprefix-freeになる。
5. 衝突がない場合はキー不変。
6. 生成されたキーが全て一意であること。
### 受け入れ基準
1. 再現条件(Ghostty G + Chrome GC)で、Chromeを確実に入力選択できる。
2. 既存 busted が全件成功。
3. READMEに新挙動が明記される。
### 前提・採用デフォルト
1. 衝突解消は「表示キーの選択可能性」を優先し、明示prefixも必要なら延長する。
2. 延長候補は hintChars 順を使用する(アルファベット順ではない)。
3. 入力確定ロジック(exact 優先)は変更しない。