fix(coding-agent): respected effective follow-up bindings
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { getKeybindings, matchesKey } from "@oh-my-pi/pi-tui";
|
||||
import { getKeybindings, type KeyId, matchesKey } from "@oh-my-pi/pi-tui";
|
||||
|
||||
/**
|
||||
* Match the coding-agent interrupt key.
|
||||
@@ -50,6 +50,20 @@ export function matchesAppExternalEditor(data: string): boolean {
|
||||
return matchesKey(data, "ctrl+g");
|
||||
}
|
||||
|
||||
function matchesEffectiveKey(data: string, key: KeyId): boolean {
|
||||
if ((key === "ctrl+enter" || key === "ctrl+return") && data.charCodeAt(0) === 10 && data.length > 1) {
|
||||
return true;
|
||||
}
|
||||
return matchesKey(data, key);
|
||||
}
|
||||
|
||||
function matchesEffectiveKeys(data: string, keys: readonly KeyId[]): boolean {
|
||||
for (const key of keys) {
|
||||
if (matchesEffectiveKey(data, key)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the "submit multi-line text input" keybinding (`app.message.followUp`).
|
||||
*
|
||||
@@ -59,16 +73,14 @@ export function matchesAppExternalEditor(data: string): boolean {
|
||||
* `["ctrl+q", "ctrl+enter"]` so Windows Terminal (which can't deliver a distinct
|
||||
* Ctrl+Enter event; #1903) still has a working chord without user remapping.
|
||||
*
|
||||
* Also recognizes a modifier-tagged LF (e.g. modifyOtherKeys legacy encoding for
|
||||
* Ctrl+Enter), which the keybinding matcher itself does not cover.
|
||||
* Also recognizes modifier-tagged LF as Ctrl+Enter only when Ctrl+Enter is an
|
||||
* effective follow-up binding.
|
||||
*/
|
||||
export function matchesAppFollowUp(data: string): boolean {
|
||||
// Modifier-tagged LF: terminals that send `\n` followed by the CSI modifier
|
||||
// payload (legacy modifyOtherKeys) report Ctrl+Enter this way.
|
||||
if (data.charCodeAt(0) === 10 && data.length > 1) return true;
|
||||
const keybindings = getKeybindings();
|
||||
if (keybindings.getKeys("app.message.followUp").length > 0) {
|
||||
return keybindings.matches(data, "app.message.followUp");
|
||||
const keys = keybindings.getKeys("app.message.followUp");
|
||||
if (keys.length > 0) {
|
||||
return matchesEffectiveKeys(data, keys);
|
||||
}
|
||||
return matchesKey(data, "ctrl+enter") || matchesKey(data, "ctrl+q");
|
||||
return matchesEffectiveKeys(data, ["ctrl+enter", "ctrl+q"]);
|
||||
}
|
||||
|
||||
@@ -3,9 +3,13 @@ import * as fs from "node:fs/promises";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { KeybindingsManager } from "@oh-my-pi/pi-coding-agent/config/keybindings";
|
||||
import { matchesAppFollowUp } from "@oh-my-pi/pi-coding-agent/modes/utils/keybinding-matchers";
|
||||
import { setKeybindings } from "@oh-my-pi/pi-tui";
|
||||
import { YAML } from "bun";
|
||||
|
||||
function ctrl(key: string): string {
|
||||
return String.fromCharCode(key.toLowerCase().charCodeAt(0) & 31);
|
||||
}
|
||||
describe("KeybindingsManager.create", () => {
|
||||
beforeEach(() => {
|
||||
setKeybindings(KeybindingsManager.inMemory());
|
||||
@@ -151,11 +155,14 @@ describe("KeybindingsManager.create", () => {
|
||||
const manager = KeybindingsManager.inMemory({
|
||||
"app.plan.toggle": "ctrl+q",
|
||||
});
|
||||
setKeybindings(manager);
|
||||
|
||||
expect(manager.getKeys("app.plan.toggle")).toEqual(["ctrl+q"]);
|
||||
expect(manager.getKeys("app.message.followUp")).toEqual(["ctrl+enter"]);
|
||||
expect(manager.getDisplayString("app.message.followUp")).toBe("Ctrl+Enter");
|
||||
expect(manager.getEffectiveConfig()["app.message.followUp"]).toBe("ctrl+enter");
|
||||
expect(matchesAppFollowUp(ctrl("q"))).toBe(false);
|
||||
expect(matchesAppFollowUp("\x1b[13;5u")).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps the Ctrl+Q follow-up default when only an unknown config key claims it (#1903)", () => {
|
||||
|
||||
Reference in New Issue
Block a user