diff --git a/src/renderer/src/components/right-sidebar/useFileSearchRunner.test.tsx b/src/renderer/src/components/right-sidebar/useFileSearchRunner.test.tsx index 8a334d0deac..2b120286f61 100644 --- a/src/renderer/src/components/right-sidebar/useFileSearchRunner.test.tsx +++ b/src/renderer/src/components/right-sidebar/useFileSearchRunner.test.tsx @@ -189,6 +189,63 @@ describe('useFileSearchRunner result ownership', () => { }) }) + it.each([ + ['local', 'local', null, false], + ['local regex', 'local', null, true], + ['SSH', 'ssh:ssh-target', 'ssh-target', false], + ['SSH regex', 'ssh:ssh-target', 'ssh-target', true], + ['paired host', 'runtime:search-runtime-a', null, false], + ['paired host regex', 'runtime:search-runtime-a', null, true] + ] as const)( + 'preserves significant whitespace for %s searches', + async (_name, hostId, connectionId, useRegex) => { + const worktreeId = 'folder-a::/repo' + const { hook } = renderSearchRunner( + { + settings: {}, + repos: [{ id: 'folder-a', kind: 'folder', connectionId }], + worktreesByRepo: { + 'folder-a': [{ id: worktreeId, repoId: 'folder-a', hostId }] + }, + fileSearchStateByWorktree: { [worktreeId]: { useRegex } } + }, + worktreeId + ) + mocks.getConnectionId.mockReturnValue(connectionId) + + for (const query of [' needle ', ' needle', 'needle ', '\tneedle\t']) { + await act(async () => { + hook.result.current.executeSearch(query) + await vi.advanceTimersByTimeAsync(300) + }) + expect(mocks.searchRuntimeFiles).toHaveBeenLastCalledWith( + expect.objectContaining({ + target: + hostId === 'runtime:search-runtime-a' + ? { kind: 'environment', environmentId: 'search-runtime-a' } + : { kind: 'local' }, + connectionId: connectionId ?? undefined + }), + expect.objectContaining({ query, useRegex, wholeWord: false }), + expect.any(AbortSignal) + ) + } + } + ) + + it.each(['', ' ', '\t \t'])('keeps a blank query %j from starting a search', async (query) => { + const { hook, updates } = renderSearchRunner( + { settings: {}, repos: [], worktreesByRepo: {}, fileSearchStateByWorktree: {} }, + 'folder:search-root' + ) + await act(async () => { + hook.result.current.executeSearch(query) + await vi.advanceTimersByTimeAsync(300) + }) + expect(mocks.searchRuntimeFiles).not.toHaveBeenCalled() + expect(updates).toContainEqual({ results: null, resultOwner: null, loading: false }) + }) + it('shows an active failure and clears it when the next search succeeds or is empty', async () => { const worktreeId = 'missing-repo::/repo' const { hook, updates } = renderSearchRunner( diff --git a/src/renderer/src/components/right-sidebar/useFileSearchRunner.ts b/src/renderer/src/components/right-sidebar/useFileSearchRunner.ts index 2b6b5afd558..3a12b44cd8a 100644 --- a/src/renderer/src/components/right-sidebar/useFileSearchRunner.ts +++ b/src/renderer/src/components/right-sidebar/useFileSearchRunner.ts @@ -150,7 +150,7 @@ export function useFileSearchRunner({ connectionId }, { - query: query.trim(), + query, rootPath: worktreePath, caseSensitive: activeSearchState?.caseSensitive ?? false, wholeWord: activeSearchState?.wholeWord ?? false,