mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-07-09 17:19:02 +00:00
fix(cli): make alt+t expand thinking on macOS Option-compose terminals (#5872)
On macOS, terminals in the default "Option as compose character" mode (iTerm2 "Normal", VS Code without macOptionIsMeta) turn Option+t into the dagger glyph "†" (U+2020) with no modifier metadata, so the app cannot tell Option was held — the "expand thinking" shortcut silently typed "†" into the prompt instead of toggling. Terminals that speak the Kitty keyboard protocol (e.g. Ghostty) report a real Alt+t event, which is why it already worked there. Rewrite a lone "†" to a synthetic Alt+t in the keypress pipeline. This both fires TOGGLE_THINKING_EXPANDED and, via the meta flag, stops the glyph from being inserted into the input buffer, so it behaves exactly like Alt+t. Scoped to darwin to avoid affecting legitimate "†" input on other platforms. Generated with AI Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
a7b9c5d915
commit
ecdf470bb6
2 changed files with 115 additions and 0 deletions
|
|
@ -122,6 +122,96 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('rewrites macOS composed Option+t glyph "†" to Alt+t', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: 'darwin',
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
try {
|
||||
const keyHandler = vi.fn();
|
||||
|
||||
const { result } = renderHook(() => useKeypressContext(), {
|
||||
wrapper,
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.subscribe(keyHandler);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
stdin.pressKey({
|
||||
name: '',
|
||||
ctrl: false,
|
||||
meta: false,
|
||||
shift: false,
|
||||
paste: false,
|
||||
sequence: '†',
|
||||
});
|
||||
});
|
||||
|
||||
expect(keyHandler).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
name: 't',
|
||||
meta: true,
|
||||
sequence: '†',
|
||||
}),
|
||||
);
|
||||
} finally {
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: originalPlatform,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('leaves "†" untouched on non-macOS platforms', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: 'linux',
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
try {
|
||||
const keyHandler = vi.fn();
|
||||
|
||||
const { result } = renderHook(() => useKeypressContext(), {
|
||||
wrapper,
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.subscribe(keyHandler);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
stdin.pressKey({
|
||||
name: '',
|
||||
ctrl: false,
|
||||
meta: false,
|
||||
shift: false,
|
||||
paste: false,
|
||||
sequence: '†',
|
||||
});
|
||||
});
|
||||
|
||||
expect(keyHandler).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
name: '',
|
||||
meta: false,
|
||||
sequence: '†',
|
||||
}),
|
||||
);
|
||||
} finally {
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: originalPlatform,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('should recognize regular enter key (keycode 13) in kitty protocol', async () => {
|
||||
const keyHandler = vi.fn();
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,15 @@ import { clipboardHasImage } from '../utils/clipboardUtils.js';
|
|||
import { FOCUS_IN, FOCUS_OUT } from '../hooks/useFocus.js';
|
||||
|
||||
const ESC = '\u001B';
|
||||
// On macOS, when the terminal's Option key is in its default "compose
|
||||
// character" mode (iTerm2 "Normal", VS Code without macOptionIsMeta), Option+t
|
||||
// is delivered to the app as the dagger glyph "†" (U+2020) with no modifier
|
||||
// metadata — so there is no way to tell Option was held. Terminals that speak
|
||||
// the Kitty keyboard protocol (e.g. Ghostty) instead report a real Alt+t event,
|
||||
// which is why the shortcut already works there. We treat a lone "†" as Alt+t so
|
||||
// the "expand thinking" shortcut works everywhere without requiring users to
|
||||
// reconfigure their terminal. See handleKeypress for where this is applied.
|
||||
const OPTION_T_COMPOSED_GLYPH = '†';
|
||||
export const PASTE_MODE_PREFIX = `${ESC}[200~`;
|
||||
export const PASTE_MODE_SUFFIX = `${ESC}[201~`;
|
||||
export const DRAG_COMPLETION_TIMEOUT_MS = 100; // Broadcast full path after 100ms if no more input
|
||||
|
|
@ -1048,6 +1057,22 @@ export function KeypressProvider({
|
|||
if (key.name === 'return' && key.sequence === `${ESC}\r`) {
|
||||
key.meta = true;
|
||||
}
|
||||
|
||||
// macOS "Option as compose character" terminals turn Option+t into the
|
||||
// bare glyph "†" (U+2020) with no modifier metadata. Rewrite it to a
|
||||
// synthetic Alt+t so the "expand thinking" shortcut fires; the meta flag
|
||||
// also stops the glyph from being inserted into the input buffer (the
|
||||
// text buffer skips printable input when meta/ctrl is set), so it looks
|
||||
// exactly like Alt was pressed.
|
||||
if (
|
||||
process.platform === 'darwin' &&
|
||||
!isPaste &&
|
||||
key.sequence === OPTION_T_COMPOSED_GLYPH
|
||||
) {
|
||||
key.name = 't';
|
||||
key.meta = true;
|
||||
}
|
||||
|
||||
broadcast({ ...key, paste: isPaste });
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue