Remove sequence binding (#16664)

This commit is contained in:
Tommaso Sciortino
2026-01-14 15:09:09 -08:00
committed by GitHub
parent 5ed275ce39
commit fb7640886b
5 changed files with 9 additions and 58 deletions
+3 -6
View File
@@ -28,12 +28,9 @@ describe('keyBindings config', () => {
it('should have valid key binding structures', () => { it('should have valid key binding structures', () => {
for (const [_, bindings] of Object.entries(defaultKeyBindings)) { for (const [_, bindings] of Object.entries(defaultKeyBindings)) {
for (const binding of bindings) { for (const binding of bindings) {
// Each binding should have either key or sequence, but not both // Each binding must have a key name
const hasKey = binding.key !== undefined; expect(typeof binding.key).toBe('string');
const hasSequence = binding.sequence !== undefined; expect(binding.key.length).toBeGreaterThan(0);
expect(hasKey || hasSequence).toBe(true);
expect(hasKey && hasSequence).toBe(false);
// Modifier properties should be boolean or undefined // Modifier properties should be boolean or undefined
if (binding.ctrl !== undefined) { if (binding.ctrl !== undefined) {
+2 -7
View File
@@ -94,9 +94,7 @@ export enum Command {
*/ */
export interface KeyBinding { export interface KeyBinding {
/** The key name (e.g., 'a', 'return', 'tab', 'escape') */ /** The key name (e.g., 'a', 'return', 'tab', 'escape') */
key?: string; key: string;
/** The key sequence (e.g., '\x18' for Ctrl+X) - alternative to key name */
sequence?: string;
/** Control key requirement: true=must be pressed, false=must not be pressed, undefined=ignore */ /** Control key requirement: true=must be pressed, false=must not be pressed, undefined=ignore */
ctrl?: boolean; ctrl?: boolean;
/** Shift key requirement: true=must be pressed, false=must not be pressed, undefined=ignore */ /** Shift key requirement: true=must be pressed, false=must not be pressed, undefined=ignore */
@@ -221,10 +219,7 @@ export const defaultKeyBindings: KeyBindingConfig = {
], ],
// External tools // External tools
[Command.OPEN_EXTERNAL_EDITOR]: [ [Command.OPEN_EXTERNAL_EDITOR]: [{ key: 'x', ctrl: true }],
{ key: 'x', ctrl: true },
{ sequence: '\x18', ctrl: true },
],
[Command.PASTE_CLIPBOARD]: [ [Command.PASTE_CLIPBOARD]: [
{ key: 'v', ctrl: true }, { key: 'v', ctrl: true },
{ key: 'v', command: true }, { key: 'v', command: true },
+1 -4
View File
@@ -256,10 +256,7 @@ describe('keyMatchers', () => {
// External tools // External tools
{ {
command: Command.OPEN_EXTERNAL_EDITOR, command: Command.OPEN_EXTERNAL_EDITOR,
positive: [ positive: [createKey('x', { ctrl: true })],
createKey('x', { ctrl: true }),
{ ...createKey('\x18'), sequence: '\x18', ctrl: true },
],
negative: [createKey('x'), createKey('c', { ctrl: true })], negative: [createKey('x'), createKey('c', { ctrl: true })],
}, },
{ {
+1 -13
View File
@@ -13,19 +13,7 @@ import { Command, defaultKeyBindings } from '../config/keyBindings.js';
* Pure data-driven matching logic * Pure data-driven matching logic
*/ */
function matchKeyBinding(keyBinding: KeyBinding, key: Key): boolean { function matchKeyBinding(keyBinding: KeyBinding, key: Key): boolean {
// Either key name or sequence must match (but not both should be defined) if (keyBinding.key !== key.name) {
let keyMatches = false;
if (keyBinding.key !== undefined) {
keyMatches = keyBinding.key === key.name;
} else if (keyBinding.sequence !== undefined) {
keyMatches = keyBinding.sequence === key.sequence;
} else {
// Neither key nor sequence defined - invalid binding
return false;
}
if (!keyMatches) {
return false; return false;
} }
+2 -28
View File
@@ -157,14 +157,8 @@ function formatBinding(binding: KeyBinding): string {
if (binding.ctrl) modifiers.push('Ctrl'); if (binding.ctrl) modifiers.push('Ctrl');
if (binding.command) modifiers.push('Cmd'); if (binding.command) modifiers.push('Cmd');
if (binding.shift) modifiers.push('Shift'); if (binding.shift) modifiers.push('Shift');
if (binding.paste) modifiers.push('Paste');
const keyName = binding.key
? formatKeyName(binding.key)
: binding.sequence
? formatSequence(binding.sequence)
: '';
const keyName = formatKeyName(binding.key);
if (!keyName) { if (!keyName) {
return ''; return '';
} }
@@ -176,7 +170,6 @@ function formatBinding(binding: KeyBinding): string {
if (binding.ctrl === false) restrictions.push('no Ctrl'); if (binding.ctrl === false) restrictions.push('no Ctrl');
if (binding.shift === false) restrictions.push('no Shift'); if (binding.shift === false) restrictions.push('no Shift');
if (binding.command === false) restrictions.push('no Cmd'); if (binding.command === false) restrictions.push('no Cmd');
if (binding.paste === false) restrictions.push('not Paste');
if (restrictions.length > 0) { if (restrictions.length > 0) {
combo = `${combo} (${restrictions.join(', ')})`; combo = `${combo} (${restrictions.join(', ')})`;
@@ -190,26 +183,7 @@ function formatKeyName(key: string): string {
if (KEY_NAME_OVERRIDES[normalized]) { if (KEY_NAME_OVERRIDES[normalized]) {
return KEY_NAME_OVERRIDES[normalized]; return KEY_NAME_OVERRIDES[normalized];
} }
if (key.length === 1) { return key.length === 1 ? key.toUpperCase() : key;
return key.toUpperCase();
}
return key;
}
function formatSequence(sequence: string): string {
if (sequence.length === 1) {
const code = sequence.charCodeAt(0);
if (code >= 1 && code <= 26) {
return String.fromCharCode(code + 64);
}
if (code === 10 || code === 13) {
return 'Enter';
}
if (code === 9) {
return 'Tab';
}
}
return JSON.stringify(sequence);
} }
if (process.argv[1]) { if (process.argv[1]) {