refactor(ui): unify keybinding infrastructure and support string initialization (#21776)

This commit is contained in:
Tommaso Sciortino
2026-03-09 23:26:33 +00:00
committed by GitHub
parent b89944c3a3
commit 215f8f3f15
53 changed files with 523 additions and 410 deletions

View File

@@ -1,143 +0,0 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect } from 'vitest';
import { formatKeyBinding, formatCommand } from './keybindingUtils.js';
import { Command } from '../../config/keyBindings.js';
import type { KeyBinding } from '../../config/keyBindings.js';
describe('keybindingUtils', () => {
describe('formatKeyBinding', () => {
const testCases: Array<{
name: string;
binding: KeyBinding;
expected: {
darwin: string;
win32: string;
linux: string;
default: string;
};
}> = [
{
name: 'simple key',
binding: { key: 'a' },
expected: { darwin: 'A', win32: 'A', linux: 'A', default: 'A' },
},
{
name: 'named key (return)',
binding: { key: 'return' },
expected: {
darwin: 'Enter',
win32: 'Enter',
linux: 'Enter',
default: 'Enter',
},
},
{
name: 'named key (escape)',
binding: { key: 'escape' },
expected: { darwin: 'Esc', win32: 'Esc', linux: 'Esc', default: 'Esc' },
},
{
name: 'ctrl modifier',
binding: { key: 'c', ctrl: true },
expected: {
darwin: 'Ctrl+C',
win32: 'Ctrl+C',
linux: 'Ctrl+C',
default: 'Ctrl+C',
},
},
{
name: 'cmd modifier',
binding: { key: 'z', cmd: true },
expected: {
darwin: 'Cmd+Z',
win32: 'Win+Z',
linux: 'Super+Z',
default: 'Cmd/Win+Z',
},
},
{
name: 'alt/option modifier',
binding: { key: 'left', alt: true },
expected: {
darwin: 'Option+Left',
win32: 'Alt+Left',
linux: 'Alt+Left',
default: 'Alt+Left',
},
},
{
name: 'shift modifier',
binding: { key: 'up', shift: true },
expected: {
darwin: 'Shift+Up',
win32: 'Shift+Up',
linux: 'Shift+Up',
default: 'Shift+Up',
},
},
{
name: 'multiple modifiers (ctrl+shift)',
binding: { key: 'z', ctrl: true, shift: true },
expected: {
darwin: 'Ctrl+Shift+Z',
win32: 'Ctrl+Shift+Z',
linux: 'Ctrl+Shift+Z',
default: 'Ctrl+Shift+Z',
},
},
{
name: 'all modifiers',
binding: { key: 'a', ctrl: true, alt: true, shift: true, cmd: true },
expected: {
darwin: 'Ctrl+Option+Shift+Cmd+A',
win32: 'Ctrl+Alt+Shift+Win+A',
linux: 'Ctrl+Alt+Shift+Super+A',
default: 'Ctrl+Alt+Shift+Cmd/Win+A',
},
},
];
testCases.forEach(({ name, binding, expected }) => {
describe(`${name}`, () => {
it('formats correctly for darwin', () => {
expect(formatKeyBinding(binding, 'darwin')).toBe(expected.darwin);
});
it('formats correctly for win32', () => {
expect(formatKeyBinding(binding, 'win32')).toBe(expected.win32);
});
it('formats correctly for linux', () => {
expect(formatKeyBinding(binding, 'linux')).toBe(expected.linux);
});
it('formats correctly for default', () => {
expect(formatKeyBinding(binding, 'default')).toBe(expected.default);
});
});
});
});
describe('formatCommand', () => {
it('formats default commands (using default platform behavior)', () => {
expect(formatCommand(Command.QUIT, undefined, 'default')).toBe('Ctrl+C');
expect(formatCommand(Command.SUBMIT, undefined, 'default')).toBe('Enter');
expect(
formatCommand(Command.TOGGLE_BACKGROUND_SHELL, undefined, 'default'),
).toBe('Ctrl+B');
});
it('returns empty string for unknown commands', () => {
expect(
formatCommand(
'unknown.command' as unknown as Command,
undefined,
'default',
),
).toBe('');
});
});
});

View File

@@ -1,111 +0,0 @@
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import process from 'node:process';
import {
type Command,
type KeyBinding,
type KeyBindingConfig,
defaultKeyBindings,
} from '../../config/keyBindings.js';
/**
* Maps internal key names to user-friendly display names.
*/
const KEY_NAME_MAP: Record<string, string> = {
return: 'Enter',
escape: 'Esc',
backspace: 'Backspace',
delete: 'Delete',
up: 'Up',
down: 'Down',
left: 'Left',
right: 'Right',
pageup: 'Page Up',
pagedown: 'Page Down',
home: 'Home',
end: 'End',
tab: 'Tab',
space: 'Space',
'double escape': 'Double Esc',
};
interface ModifierMap {
ctrl: string;
alt: string;
shift: string;
cmd: string;
}
const MODIFIER_MAPS: Record<string, ModifierMap> = {
darwin: {
ctrl: 'Ctrl',
alt: 'Option',
shift: 'Shift',
cmd: 'Cmd',
},
win32: {
ctrl: 'Ctrl',
alt: 'Alt',
shift: 'Shift',
cmd: 'Win',
},
linux: {
ctrl: 'Ctrl',
alt: 'Alt',
shift: 'Shift',
cmd: 'Super',
},
default: {
ctrl: 'Ctrl',
alt: 'Alt',
shift: 'Shift',
cmd: 'Cmd/Win',
},
};
/**
* Formats a single KeyBinding into a human-readable string (e.g., "Ctrl+C").
*/
export function formatKeyBinding(
binding: KeyBinding,
platform?: string,
): string {
const activePlatform =
platform ??
(process.env['FORCE_GENERIC_KEYBINDING_HINTS']
? 'default'
: process.platform);
const modMap = MODIFIER_MAPS[activePlatform] || MODIFIER_MAPS['default'];
const parts: string[] = [];
if (binding.ctrl) parts.push(modMap.ctrl);
if (binding.alt) parts.push(modMap.alt);
if (binding.shift) parts.push(modMap.shift);
if (binding.cmd) parts.push(modMap.cmd);
const keyName = KEY_NAME_MAP[binding.key] || binding.key.toUpperCase();
parts.push(keyName);
return parts.join('+');
}
/**
* Formats the primary keybinding for a command.
*/
export function formatCommand(
command: Command,
config: KeyBindingConfig = defaultKeyBindings,
platform?: string,
): string {
const bindings = config[command];
if (!bindings || bindings.length === 0) {
return '';
}
// Use the first binding as the primary one for display
return formatKeyBinding(bindings[0], platform);
}

View File

@@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { Command } from '../keyMatchers.js';
import { Command } from '../key/keyMatchers.js';
import type { Key } from '../hooks/useKeypress.js';
import { useKeyMatchers } from '../hooks/useKeyMatchers.js';