Skip to content

Commit 7fe2749

Browse files
fix(chat): fix the slash-command Enter regression
- `src/components/Chat/CommandMenu.tsx` now uses the local `Suggestions` component instead of `SelectPrompt`. - This avoids `SelectPrompt`’s one-tick disabled state, so Enter is handled immediately and still respects arrow-focused command selection. - `src/components/Chat/CommandMenu.test.tsx` now tests real stdin Enter/Down behavior instead of mocking selection callbacks.
1 parent 8f0e854 commit 7fe2749

2 files changed

Lines changed: 25 additions & 49 deletions

File tree

src/components/Chat/CommandMenu.test.tsx

Lines changed: 20 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,18 @@
1-
import { Text } from 'ink';
21
import { render } from 'ink-testing-library';
32

4-
interface MockSelectPromptProps {
5-
highlightText: string;
6-
onChange: (value: string) => void;
7-
options: { label: string; value: string }[];
8-
}
9-
10-
const { mockSelectPrompt } = vi.hoisted(() => ({
11-
mockSelectPrompt: vi.fn<(props: MockSelectPromptProps) => void>(),
12-
}));
13-
14-
vi.mock('@/components/SelectPrompt', () => ({
15-
SelectPrompt: (props: MockSelectPromptProps) => {
16-
mockSelectPrompt(props);
17-
return (
18-
<>
19-
{props.options.map(({ label, value }) => (
20-
<Text key={value}>{label}</Text>
21-
))}
22-
</>
23-
);
24-
},
25-
}));
3+
import { KEY } from '@/constants';
4+
import { time } from '@/utils';
265

276
import { CommandMenu } from './CommandMenu';
287

298
describe('CommandMenu', () => {
30-
beforeEach(() => {
31-
mockSelectPrompt.mockReset();
32-
});
33-
349
it('returns null when input does not start with a slash', () => {
3510
const onSubmit = vi.fn();
3611
const { lastFrame } = render(
3712
<CommandMenu input="hello" onSubmit={onSubmit} />,
3813
);
3914

4015
expect(lastFrame()).toBe('');
41-
expect(mockSelectPrompt).not.toHaveBeenCalled();
4216
});
4317

4418
it('returns null when no commands match the slash input', () => {
@@ -48,34 +22,35 @@ describe('CommandMenu', () => {
4822
);
4923

5024
expect(lastFrame()).toBe('');
51-
expect(mockSelectPrompt).not.toHaveBeenCalled();
5225
});
5326

54-
it('renders matching commands and forwards selection', () => {
27+
it('renders matching commands and selects with Enter', async () => {
5528
const onSubmit = vi.fn();
56-
const { lastFrame } = render(
29+
const { lastFrame, stdin } = render(
5730
<CommandMenu input="/m" onSubmit={onSubmit} />,
5831
);
5932

6033
expect(lastFrame()).toContain('/model - manage Ollama models');
6134
expect(lastFrame()).not.toContain('/clear - clear the current session');
62-
expect(mockSelectPrompt).toHaveBeenCalledTimes(1);
63-
64-
const [firstCall] = mockSelectPrompt.mock.calls;
65-
expect(firstCall).toBeDefined();
66-
const [props] = firstCall;
67-
expect(props.highlightText).toBe('/m');
68-
expect(props.options).toEqual([
69-
{
70-
label: '/model - manage Ollama models',
71-
value: '/model',
72-
},
73-
]);
74-
const { onChange } = props;
75-
onChange('/model');
35+
36+
stdin.write(KEY.ENTER);
37+
await time.tick();
38+
7639
expect(onSubmit).toHaveBeenCalledWith('/model');
7740
});
7841

42+
it('moves focus through slash commands before selecting', async () => {
43+
const onSubmit = vi.fn();
44+
const { stdin } = render(<CommandMenu input="/" onSubmit={onSubmit} />);
45+
46+
stdin.write(KEY.DOWN);
47+
await time.tick();
48+
stdin.write(KEY.ENTER);
49+
await time.tick();
50+
51+
expect(onSubmit).toHaveBeenCalledWith('/session');
52+
});
53+
7954
it('includes /search in matching command results', () => {
8055
const onSubmit = vi.fn();
8156
const { lastFrame } = render(

src/components/Chat/CommandMenu.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useMemo } from 'react';
22

3-
import { SelectPrompt } from '@/components/SelectPrompt';
3+
import { Suggestions } from '@/components/Suggestions';
44
import { COMMAND } from '@/constants';
55

66
interface Props {
@@ -30,9 +30,10 @@ export function CommandMenu({ input, onSubmit }: Props) {
3030
}
3131

3232
return (
33-
<SelectPrompt
34-
highlightText={input}
35-
onChange={onSubmit}
33+
<Suggestions
34+
onSelect={(option) => {
35+
onSubmit(option.value);
36+
}}
3637
options={commandOptions}
3738
/>
3839
);

0 commit comments

Comments
 (0)