From 7de790fbf236193191a33482793ee3ec5943d62d Mon Sep 17 00:00:00 2001
From: Marat Boshernitsan <maratb@nitsan.org>
Date: Tue, 3 Jun 2025 23:01:26 -0700
Subject: Fix several bugs in prompt history (#734)

Co-authored-by: Marat Boshernitsan <maratb@google.com>
---
 packages/cli/src/ui/components/InputPrompt.tsx | 36 +++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 6 deletions(-)

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

diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx
index c131f5e0..7e4c8c8b 100644
--- a/packages/cli/src/ui/components/InputPrompt.tsx
+++ b/packages/cli/src/ui/components/InputPrompt.tsx
@@ -4,7 +4,7 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-import React, { useCallback } from 'react';
+import React, { useCallback, useEffect, useState } from 'react';
 import { Text, Box, useInput, useStdin } from 'ink';
 import { Colors } from '../colors.js';
 import { SuggestionsDisplay } from './SuggestionsDisplay.js';
@@ -19,7 +19,7 @@ import { isAtCommand, isSlashCommand } from '../utils/commandUtils.js';
 import { SlashCommand } from '../hooks/slashCommandProcessor.js';
 import { Config } from '@gemini-code/core';
 
-interface InputPromptProps {
+export interface InputPromptProps {
   onSubmit: (value: string) => void;
   userMessages: readonly string[];
   onClearScreen: () => void;
@@ -54,6 +54,8 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
   );
   const suggestionsWidth = Math.max(60, Math.floor(terminalSize.columns * 0.8));
 
+  const [justNavigatedHistory, setJustNavigatedHistory] = useState(false);
+
   const { stdin, setRawMode } = useStdin();
 
   const buffer = useTextBuffer({
@@ -84,14 +86,35 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
     [onSubmit, buffer, resetCompletionState],
   );
 
+  const customSetTextAndResetCompletionSignal = useCallback(
+    (newText: string) => {
+      buffer.setText(newText);
+      setJustNavigatedHistory(true);
+    },
+    [buffer, setJustNavigatedHistory],
+  );
+
   const inputHistory = useInputHistory({
     userMessages,
     onSubmit: handleSubmitAndClear,
     isActive: !completion.showSuggestions,
     currentQuery: buffer.text,
-    onChange: buffer.setText,
+    onChange: customSetTextAndResetCompletionSignal,
   });
 
+  // Effect to reset completion if history navigation just occurred and set the text
+  useEffect(() => {
+    if (justNavigatedHistory) {
+      resetCompletionState();
+      setJustNavigatedHistory(false);
+    }
+  }, [
+    justNavigatedHistory,
+    buffer.text,
+    resetCompletionState,
+    setJustNavigatedHistory,
+  ]);
+
   const completionSuggestions = completion.suggestions;
   const handleAutocomplete = useCallback(
     (indexToUse: number) => {
@@ -276,8 +299,8 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
       // Standard arrow navigation within the buffer
       if (key.upArrow && !completion.showSuggestions) {
         if (
-          buffer.visualCursor[0] === 0 &&
-          buffer.visualScrollRow === 0 &&
+          (buffer.allVisualLines.length === 1 || // Always navigate for single line
+            (buffer.visualCursor[0] === 0 && buffer.visualScrollRow === 0)) &&
           inputHistory.navigateUp
         ) {
           inputHistory.navigateUp();
@@ -288,7 +311,8 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
       }
       if (key.downArrow && !completion.showSuggestions) {
         if (
-          buffer.visualCursor[0] === buffer.allVisualLines.length - 1 &&
+          (buffer.allVisualLines.length === 1 || // Always navigate for single line
+            buffer.visualCursor[0] === buffer.allVisualLines.length - 1) &&
           inputHistory.navigateDown
         ) {
           inputHistory.navigateDown();
-- 
cgit v1.2.3

