From 9f20c5f95e43bccee21b1d89e33fbc3c61a70650 Mon Sep 17 00:00:00 2001
From: Allen Hutchison <adh@google.com>
Date: Wed, 30 Apr 2025 08:31:32 -0700
Subject: Add @ command suggestions in the UI. (#219)

---
 packages/cli/src/ui/App.tsx | 50 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 47 insertions(+), 3 deletions(-)

(limited to 'packages/cli/src/ui/App.tsx')

diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx
index 4bf7123e..8b219778 100644
--- a/packages/cli/src/ui/App.tsx
+++ b/packages/cli/src/ui/App.tsx
@@ -5,7 +5,7 @@
  */
 
 import React, { useState, useMemo, useCallback } from 'react';
-import { Box, Static, Text } from 'ink';
+import { Box, Static, Text, useStdout } from 'ink';
 import { StreamingState, type HistoryItem } from './types.js';
 import { useGeminiStream } from './hooks/useGeminiStream.js';
 import { useLoadingIndicator } from './hooks/useLoadingIndicator.js';
@@ -23,6 +23,9 @@ import { Intro } from './components/Intro.js';
 import { Tips } from './components/Tips.js';
 import { ConsoleOutput } from './components/ConsolePatcher.js';
 import { HistoryItemDisplay } from './components/HistoryItemDisplay.js';
+import { useCompletion } from './hooks/useCompletion.js';
+import { SuggestionsDisplay } from './components/SuggestionsDisplay.js';
+import { isAtCommand } from './utils/commandUtils.js';
 
 interface AppProps {
   config: Config;
@@ -78,17 +81,35 @@ export const App = ({ config, cliVersion }: AppProps) => {
 
   const isInputActive = streamingState === StreamingState.Idle && !initError;
 
-  const { query, handleSubmit: handleHistorySubmit } = useInputHistory({
+  const {
+    query,
+    setQuery,
+    handleSubmit: handleHistorySubmit,
+    inputKey,
+    setInputKey,
+  } = useInputHistory({
     userMessages,
     onSubmit: handleFinalSubmit,
     isActive: isInputActive,
   });
 
+  const completion = useCompletion(
+    query,
+    config.getTargetDir(),
+    isInputActive && isAtCommand(query),
+  );
+
   // --- Render Logic ---
 
   const { staticallyRenderedHistoryItems, updatableHistoryItems } =
     getHistoryRenderSlices(history);
 
+  // Get terminal width
+  const { stdout } = useStdout();
+  const terminalWidth = stdout?.columns ?? 80;
+  // Calculate width for suggestions, leave some padding
+  const suggestionsWidth = Math.max(60, Math.floor(terminalWidth * 0.8));
+
   return (
     <Box flexDirection="column" marginBottom={1} width="90%">
       {/*
@@ -174,7 +195,30 @@ export const App = ({ config, cliVersion }: AppProps) => {
                 </Text>
               </Box>
 
-              <InputPrompt onSubmit={handleHistorySubmit} />
+              <InputPrompt
+                query={query}
+                setQuery={setQuery}
+                inputKey={inputKey}
+                setInputKey={setInputKey}
+                onSubmit={handleHistorySubmit}
+                showSuggestions={completion.showSuggestions}
+                suggestions={completion.suggestions}
+                activeSuggestionIndex={completion.activeSuggestionIndex}
+                navigateUp={completion.navigateUp}
+                navigateDown={completion.navigateDown}
+                resetCompletion={completion.resetCompletionState}
+              />
+              {completion.showSuggestions && (
+                <Box marginTop={1}>
+                  <SuggestionsDisplay
+                    suggestions={completion.suggestions}
+                    activeIndex={completion.activeSuggestionIndex}
+                    isLoading={completion.isLoadingSuggestions}
+                    width={suggestionsWidth}
+                    scrollOffset={completion.visibleStartIndex}
+                  />
+                </Box>
+              )}
             </>
           )}
         </>
-- 
cgit v1.2.3

