From 2216856e3ca1024beaeae1edcb922cedb4acb276 Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Sat, 20 Sep 2025 09:13:58 -0700 Subject: [PATCH] fix(ui): prevent useSlashCompletion effects from running during @ completion (#8986) --- .../src/ui/hooks/useSlashCompletion.test.ts | 43 +++++++++++++++++++ .../cli/src/ui/hooks/useSlashCompletion.ts | 10 ++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/ui/hooks/useSlashCompletion.test.ts b/packages/cli/src/ui/hooks/useSlashCompletion.test.ts index afebbc92db..371af516e7 100644 --- a/packages/cli/src/ui/hooks/useSlashCompletion.test.ts +++ b/packages/cli/src/ui/hooks/useSlashCompletion.test.ts @@ -807,4 +807,47 @@ describe('useSlashCompletion', () => { }); }); }); + + it('should not call shared callbacks when disabled', () => { + const mockSetSuggestions = vi.fn(); + const mockSetIsLoadingSuggestions = vi.fn(); + const mockSetIsPerfectMatch = vi.fn(); + + const slashCommands = [ + createTestCommand({ + name: 'help', + description: 'Show help', + }), + ]; + + const { rerender } = renderHook( + ({ enabled, query }) => + useSlashCompletion({ + enabled, + query, + slashCommands, + commandContext: mockCommandContext, + setSuggestions: mockSetSuggestions, + setIsLoadingSuggestions: mockSetIsLoadingSuggestions, + setIsPerfectMatch: mockSetIsPerfectMatch, + }), + { + initialProps: { enabled: false, query: '@src/file' }, + }, + ); + + // Clear any initial calls + mockSetSuggestions.mockClear(); + mockSetIsLoadingSuggestions.mockClear(); + mockSetIsPerfectMatch.mockClear(); + + // Change query while disabled (simulating @ completion typing) + rerender({ enabled: false, query: '@src/file.ts' }); + rerender({ enabled: false, query: '@src/file.tsx' }); + + // Should not have called shared callbacks during @ completion typing + expect(mockSetSuggestions).not.toHaveBeenCalled(); + expect(mockSetIsLoadingSuggestions).not.toHaveBeenCalled(); + expect(mockSetIsPerfectMatch).not.toHaveBeenCalled(); + }); }); diff --git a/packages/cli/src/ui/hooks/useSlashCompletion.ts b/packages/cli/src/ui/hooks/useSlashCompletion.ts index bee4677ffa..ba639d01bd 100644 --- a/packages/cli/src/ui/hooks/useSlashCompletion.ts +++ b/packages/cli/src/ui/hooks/useSlashCompletion.ts @@ -485,14 +485,20 @@ export function useSlashCompletion(props: UseSlashCompletionProps): { ); const { isPerfectMatch } = usePerfectMatch(parserResult); - // Update external state - this is now much simpler and focused + // Clear internal state when disabled useEffect(() => { - if (!enabled || query === null) { + if (!enabled) { setSuggestions([]); setIsLoadingSuggestions(false); setIsPerfectMatch(false); setCompletionStart(-1); setCompletionEnd(-1); + } + }, [enabled, setSuggestions, setIsLoadingSuggestions, setIsPerfectMatch]); + + // Update external state only when enabled + useEffect(() => { + if (!enabled || query === null) { return; }