From 0dea7233b65b480466e4da62db9127205b57a6d0 Mon Sep 17 00:00:00 2001 From: fuyou Date: Sun, 10 Aug 2025 06:26:43 +0800 Subject: feat(cli) - enhance input UX with double ESC clear (#4453) Co-authored-by: Jacob Richman --- .../cli/src/ui/components/InputPrompt.test.tsx | 100 +++++++++++++++++++++ 1 file changed, 100 insertions(+) (limited to 'packages/cli/src/ui/components/InputPrompt.test.tsx') diff --git a/packages/cli/src/ui/components/InputPrompt.test.tsx b/packages/cli/src/ui/components/InputPrompt.test.tsx index f050ba07..a29a095a 100644 --- a/packages/cli/src/ui/components/InputPrompt.test.tsx +++ b/packages/cli/src/ui/components/InputPrompt.test.tsx @@ -1191,6 +1191,106 @@ describe('InputPrompt', () => { }); }); + describe('enhanced input UX - double ESC clear functionality', () => { + it('should clear buffer on second ESC press', async () => { + const onEscapePromptChange = vi.fn(); + props.onEscapePromptChange = onEscapePromptChange; + props.buffer.setText('text to clear'); + + const { stdin, unmount } = render(); + await wait(); + + stdin.write('\x1B'); + await wait(); + + stdin.write('\x1B'); + await wait(); + + expect(props.buffer.setText).toHaveBeenCalledWith(''); + expect(mockCommandCompletion.resetCompletionState).toHaveBeenCalled(); + unmount(); + }); + + it('should reset escape state on any non-ESC key', async () => { + const onEscapePromptChange = vi.fn(); + props.onEscapePromptChange = onEscapePromptChange; + props.buffer.setText('some text'); + + const { stdin, unmount } = render(); + await wait(); + + stdin.write('\x1B'); + await wait(); + + expect(onEscapePromptChange).toHaveBeenCalledWith(true); + + stdin.write('a'); + await wait(); + + expect(onEscapePromptChange).toHaveBeenCalledWith(false); + unmount(); + }); + + it('should handle ESC in shell mode by disabling shell mode', async () => { + props.shellModeActive = true; + + const { stdin, unmount } = render(); + await wait(); + + stdin.write('\x1B'); + await wait(); + + expect(props.setShellModeActive).toHaveBeenCalledWith(false); + unmount(); + }); + + it('should handle ESC when completion suggestions are showing', async () => { + mockedUseCommandCompletion.mockReturnValue({ + ...mockCommandCompletion, + showSuggestions: true, + suggestions: [{ label: 'suggestion', value: 'suggestion' }], + }); + + const { stdin, unmount } = render(); + await wait(); + + stdin.write('\x1B'); + await wait(); + + expect(mockCommandCompletion.resetCompletionState).toHaveBeenCalled(); + unmount(); + }); + + it('should not call onEscapePromptChange when not provided', async () => { + props.onEscapePromptChange = undefined; + props.buffer.setText('some text'); + + const { stdin, unmount } = render(); + await wait(); + + stdin.write('\x1B'); + await wait(); + + unmount(); + }); + + it('should not interfere with existing keyboard shortcuts', async () => { + const { stdin, unmount } = render(); + await wait(); + + stdin.write('\x0C'); + await wait(); + + expect(props.onClearScreen).toHaveBeenCalled(); + + stdin.write('\x01'); + await wait(); + + expect(props.buffer.move).toHaveBeenCalledWith('home'); + unmount(); + }); + }); + describe('reverse search', () => { beforeEach(async () => { props.shellModeActive = true; -- cgit v1.2.3