summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/hooks/useReverseSearchCompletion.tsx
diff options
context:
space:
mode:
authorAyesha Shafique <[email protected]>2025-08-04 00:53:24 +0500
committerGitHub <[email protected]>2025-08-03 19:53:24 +0000
commit072d8ba2899f2601dad6d4b0333fdcb80555a7dd (patch)
treea8333f75184889929b844c115c5fb93555abdf62 /packages/cli/src/ui/hooks/useReverseSearchCompletion.tsx
parent03ed37d0dc2b5e2077b53073517abaab3d24d9c2 (diff)
feat: Add reverse search capability for shell commands (#4793)
Diffstat (limited to 'packages/cli/src/ui/hooks/useReverseSearchCompletion.tsx')
-rw-r--r--packages/cli/src/ui/hooks/useReverseSearchCompletion.tsx91
1 files changed, 91 insertions, 0 deletions
diff --git a/packages/cli/src/ui/hooks/useReverseSearchCompletion.tsx b/packages/cli/src/ui/hooks/useReverseSearchCompletion.tsx
new file mode 100644
index 00000000..1cc7e602
--- /dev/null
+++ b/packages/cli/src/ui/hooks/useReverseSearchCompletion.tsx
@@ -0,0 +1,91 @@
+/**
+ * @license
+ * Copyright 2025 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { useEffect, useCallback } from 'react';
+import { useCompletion } from './useCompletion.js';
+import { TextBuffer } from '../components/shared/text-buffer.js';
+import { Suggestion } from '../components/SuggestionsDisplay.js';
+
+export interface UseReverseSearchCompletionReturn {
+ suggestions: Suggestion[];
+ activeSuggestionIndex: number;
+ visibleStartIndex: number;
+ showSuggestions: boolean;
+ isLoadingSuggestions: boolean;
+ navigateUp: () => void;
+ navigateDown: () => void;
+ handleAutocomplete: (i: number) => void;
+ resetCompletionState: () => void;
+}
+
+export function useReverseSearchCompletion(
+ buffer: TextBuffer,
+ shellHistory: readonly string[],
+ reverseSearchActive: boolean,
+): UseReverseSearchCompletionReturn {
+ const {
+ suggestions,
+ activeSuggestionIndex,
+ visibleStartIndex,
+ showSuggestions,
+ isLoadingSuggestions,
+
+ setSuggestions,
+ setShowSuggestions,
+ setActiveSuggestionIndex,
+ resetCompletionState,
+ navigateUp,
+ navigateDown,
+ } = useCompletion();
+
+ // whenever reverseSearchActive is on, filter history
+ useEffect(() => {
+ if (!reverseSearchActive) {
+ resetCompletionState();
+ return;
+ }
+ const q = buffer.text.toLowerCase();
+ const matches = shellHistory.reduce<Suggestion[]>((acc, cmd) => {
+ const idx = cmd.toLowerCase().indexOf(q);
+ if (idx !== -1) {
+ acc.push({ label: cmd, value: cmd, matchedIndex: idx });
+ }
+ return acc;
+ }, []);
+ setSuggestions(matches);
+ setShowSuggestions(matches.length > 0);
+ setActiveSuggestionIndex(matches.length > 0 ? 0 : -1);
+ }, [
+ buffer.text,
+ shellHistory,
+ reverseSearchActive,
+ resetCompletionState,
+ setActiveSuggestionIndex,
+ setShowSuggestions,
+ setSuggestions,
+ ]);
+
+ const handleAutocomplete = useCallback(
+ (i: number) => {
+ if (i < 0 || i >= suggestions.length) return;
+ buffer.setText(suggestions[i].value);
+ resetCompletionState();
+ },
+ [buffer, suggestions, resetCompletionState],
+ );
+
+ return {
+ suggestions,
+ activeSuggestionIndex,
+ visibleStartIndex,
+ showSuggestions,
+ isLoadingSuggestions,
+ navigateUp,
+ navigateDown,
+ handleAutocomplete,
+ resetCompletionState,
+ };
+}