fix(cli-ui): revert backspace handling to fix Windows regression (#25941)

This commit is contained in:
Tommaso Sciortino
2026-04-24 13:30:00 -07:00
committed by GitHub
parent ed469e492b
commit 048bf6e514
4 changed files with 5 additions and 101 deletions
@@ -44,7 +44,7 @@ enum TerminalKeys {
LEFT_ARROW = '\u001B[D', LEFT_ARROW = '\u001B[D',
RIGHT_ARROW = '\u001B[C', RIGHT_ARROW = '\u001B[C',
ESCAPE = '\u001B', ESCAPE = '\u001B',
BACKSPACE = '\x7f', BACKSPACE = '\u0008',
CTRL_P = '\u0010', CTRL_P = '\u0010',
CTRL_N = '\u000E', CTRL_N = '\u000E',
} }
@@ -24,7 +24,7 @@ enum TerminalKeys {
LEFT_ARROW = '\u001B[D', LEFT_ARROW = '\u001B[D',
RIGHT_ARROW = '\u001B[C', RIGHT_ARROW = '\u001B[C',
ESCAPE = '\u001B', ESCAPE = '\u001B',
BACKSPACE = '\x7f', BACKSPACE = '\u0008',
CTRL_L = '\u000C', CTRL_L = '\u000C',
} }
@@ -9,17 +9,7 @@ import { act } from 'react';
import { renderHookWithProviders } from '../../test-utils/render.js'; import { renderHookWithProviders } from '../../test-utils/render.js';
import { createMockSettings } from '../../test-utils/settings.js'; import { createMockSettings } from '../../test-utils/settings.js';
import { waitFor } from '../../test-utils/async.js'; import { waitFor } from '../../test-utils/async.js';
import type { Mock } from 'vitest'; import { vi, afterAll, beforeAll, type Mock } from 'vitest';
import {
vi,
afterAll,
beforeAll,
describe,
it,
expect,
beforeEach,
afterEach,
} from 'vitest';
import { import {
useKeypressContext, useKeypressContext,
ESC_TIMEOUT, ESC_TIMEOUT,
@@ -441,80 +431,6 @@ describe('KeypressContext', () => {
); );
}); });
describe('Windows Terminal Backspace handling', () => {
afterEach(() => {
vi.unstubAllEnvs();
});
it('should NOT treat \\b as ctrl when WT_SESSION is NOT present and OS is not Windows_NT', async () => {
vi.stubEnv('WT_SESSION', '');
vi.stubEnv('OS', 'Linux');
const { keyHandler } = await setupKeypressTest();
act(() => {
stdin.write('\b');
});
expect(keyHandler).toHaveBeenCalledWith(
expect.objectContaining({
name: 'backspace',
ctrl: false,
}),
);
});
it('should treat \\b as ctrl when WT_SESSION IS present (even if not Windows_NT)', async () => {
vi.stubEnv('WT_SESSION', 'some-id');
vi.stubEnv('OS', 'Linux');
const { keyHandler } = await setupKeypressTest();
act(() => {
stdin.write('\b');
});
expect(keyHandler).toHaveBeenCalledWith(
expect.objectContaining({
name: 'backspace',
ctrl: true,
}),
);
});
it('should treat \\b as ctrl when OS is Windows_NT', async () => {
vi.stubEnv('WT_SESSION', '');
vi.stubEnv('OS', 'Windows_NT');
const { keyHandler } = await setupKeypressTest();
act(() => {
stdin.write('\b');
});
expect(keyHandler).toHaveBeenCalledWith(
expect.objectContaining({
name: 'backspace',
ctrl: true,
}),
);
});
it('should treat \\x7f as regular backspace regardless of WT_SESSION or OS', async () => {
vi.stubEnv('WT_SESSION', 'some-id');
vi.stubEnv('OS', 'Windows_NT');
const { keyHandler } = await setupKeypressTest();
act(() => {
stdin.write('\x7f');
});
expect(keyHandler).toHaveBeenCalledWith(
expect.objectContaining({
name: 'backspace',
ctrl: false,
}),
);
});
});
describe('paste mode', () => { describe('paste mode', () => {
it.each([ it.each([
{ {
@@ -651,20 +651,8 @@ function* emitKeys(
// tab // tab
name = 'tab'; name = 'tab';
alt = escaped; alt = escaped;
} else if (ch === '\b') { } else if (ch === '\b' || ch === '\x7f') {
// ctrl+h / ctrl+backspace (windows terminals send \x08 for ctrl+backspace) // backspace or ctrl+h
name = 'backspace';
// In Windows environments, \b is sent for Ctrl+Backspace (standard backspace is translated to \x7f).
// We scope this to Windows/WT_SESSION to avoid breaking other unixes where \b is a plain backspace.
if (
typeof process !== 'undefined' &&
(process.env?.['OS'] === 'Windows_NT' || !!process.env?.['WT_SESSION'])
) {
ctrl = true;
}
alt = escaped;
} else if (ch === '\x7f') {
// backspace
name = 'backspace'; name = 'backspace';
alt = escaped; alt = escaped;
} else if (ch === ESC) { } else if (ch === ESC) {