diff --git a/packages/cli/src/ui/components/InputPrompt.test.tsx b/packages/cli/src/ui/components/InputPrompt.test.tsx
index 886a6235..3f646cc6 100644
--- a/packages/cli/src/ui/components/InputPrompt.test.tsx
+++ b/packages/cli/src/ui/components/InputPrompt.test.tsx
@@ -221,6 +221,83 @@ describe('InputPrompt', () => {
unmount();
});
+ it('should call completion.navigateUp for both up arrow and Ctrl+P when suggestions are showing', async () => {
+ mockedUseCompletion.mockReturnValue({
+ ...mockCompletion,
+ showSuggestions: true,
+ suggestions: [
+ { label: 'memory', value: 'memory' },
+ { label: 'memcache', value: 'memcache' },
+ ],
+ });
+
+ props.buffer.setText('/mem');
+
+ const { stdin, unmount } = render();
+ await wait();
+
+ // Test up arrow
+ stdin.write('\u001B[A'); // Up arrow
+ await wait();
+
+ stdin.write('\u0010'); // Ctrl+P
+ await wait();
+ expect(mockCompletion.navigateUp).toHaveBeenCalledTimes(2);
+ expect(mockCompletion.navigateDown).not.toHaveBeenCalled();
+
+ unmount();
+ });
+
+ it('should call completion.navigateDown for both down arrow and Ctrl+N when suggestions are showing', async () => {
+ mockedUseCompletion.mockReturnValue({
+ ...mockCompletion,
+ showSuggestions: true,
+ suggestions: [
+ { label: 'memory', value: 'memory' },
+ { label: 'memcache', value: 'memcache' },
+ ],
+ });
+ props.buffer.setText('/mem');
+
+ const { stdin, unmount } = render();
+ await wait();
+
+ // Test down arrow
+ stdin.write('\u001B[B'); // Down arrow
+ await wait();
+
+ stdin.write('\u000E'); // Ctrl+N
+ await wait();
+ expect(mockCompletion.navigateDown).toHaveBeenCalledTimes(2);
+ expect(mockCompletion.navigateUp).not.toHaveBeenCalled();
+
+ unmount();
+ });
+
+ it('should NOT call completion navigation when suggestions are not showing', async () => {
+ mockedUseCompletion.mockReturnValue({
+ ...mockCompletion,
+ showSuggestions: false,
+ });
+ props.buffer.setText('some text');
+
+ const { stdin, unmount } = render();
+ await wait();
+
+ stdin.write('\u001B[A'); // Up arrow
+ await wait();
+ stdin.write('\u001B[B'); // Down arrow
+ await wait();
+ stdin.write('\u0010'); // Ctrl+P
+ await wait();
+ stdin.write('\u000E'); // Ctrl+N
+ await wait();
+
+ expect(mockCompletion.navigateUp).not.toHaveBeenCalled();
+ expect(mockCompletion.navigateDown).not.toHaveBeenCalled();
+ unmount();
+ });
+
describe('clipboard image paste', () => {
beforeEach(() => {
vi.mocked(clipboardUtils.clipboardHasImage).mockResolvedValue(false);
diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx
index b7c53196..a713c889 100644
--- a/packages/cli/src/ui/components/InputPrompt.tsx
+++ b/packages/cli/src/ui/components/InputPrompt.tsx
@@ -320,11 +320,11 @@ export const InputPrompt: React.FC = ({
if (completion.showSuggestions) {
if (completion.suggestions.length > 1) {
- if (key.name === 'up') {
+ if (key.name === 'up' || (key.ctrl && key.name === 'p')) {
completion.navigateUp();
return;
}
- if (key.name === 'down') {
+ if (key.name === 'down' || (key.ctrl && key.name === 'n')) {
completion.navigateDown();
return;
}