mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-20 02:00:40 -07:00
feat(cli): implement width-aware phrase selection for footer tips
- Update usePhraseCycler to filter phrase list based on available width - Move status length estimation logic to AppContainer - Ensure tips are only selected if they fit the remaining terminal width - Update snapshots for usePhraseCycler
This commit is contained in:
@@ -2,10 +2,10 @@
|
||||
|
||||
exports[`usePhraseCycler > should prioritize interactive shell waiting over normal waiting immediately 1`] = `"Waiting for user confirmation..."`;
|
||||
|
||||
exports[`usePhraseCycler > should prioritize interactive shell waiting over normal waiting immediately 2`] = `"Interactive shell awaiting input... press tab to focus shell"`;
|
||||
exports[`usePhraseCycler > should prioritize interactive shell waiting over normal waiting immediately 2`] = `"! Shell awaiting input (Tab to focus)"`;
|
||||
|
||||
exports[`usePhraseCycler > should reset phrase when transitioning from waiting to active 1`] = `"Waiting for user confirmation..."`;
|
||||
|
||||
exports[`usePhraseCycler > should show "Waiting for user confirmation..." when isWaiting is true 1`] = `"Waiting for user confirmation..."`;
|
||||
|
||||
exports[`usePhraseCycler > should show interactive shell waiting message immediately when isInteractiveShellWaiting is true 1`] = `"Interactive shell awaiting input... press tab to focus shell"`;
|
||||
exports[`usePhraseCycler > should show interactive shell waiting message immediately when isInteractiveShellWaiting is true 1`] = `"! Shell awaiting input (Tab to focus)"`;
|
||||
|
||||
@@ -23,6 +23,7 @@ export interface UseLoadingIndicatorProps {
|
||||
loadingPhrasesMode?: LoadingPhrasesMode;
|
||||
customWittyPhrases?: string[];
|
||||
errorVerbosity?: 'low' | 'full';
|
||||
maxLength?: number;
|
||||
}
|
||||
|
||||
export const useLoadingIndicator = ({
|
||||
@@ -32,6 +33,7 @@ export const useLoadingIndicator = ({
|
||||
loadingPhrasesMode,
|
||||
customWittyPhrases,
|
||||
errorVerbosity = 'full',
|
||||
maxLength,
|
||||
}: UseLoadingIndicatorProps) => {
|
||||
const [timerResetKey, setTimerResetKey] = useState(0);
|
||||
const isTimerActive = streamingState === StreamingState.Responding;
|
||||
@@ -46,6 +48,7 @@ export const useLoadingIndicator = ({
|
||||
shouldShowFocusHint,
|
||||
loadingPhrasesMode,
|
||||
customWittyPhrases,
|
||||
maxLength,
|
||||
);
|
||||
|
||||
const [retainedElapsedTime, setRetainedElapsedTime] = useState(0);
|
||||
|
||||
@@ -20,6 +20,7 @@ export const INTERACTIVE_SHELL_WAITING_PHRASE =
|
||||
* @param shouldShowFocusHint Whether to show the shell focus hint.
|
||||
* @param loadingPhrasesMode Which phrases to show: tips, witty, all, or off.
|
||||
* @param customPhrases Optional list of custom phrases to use instead of built-in witty phrases.
|
||||
* @param maxLength Optional maximum length for the selected phrase.
|
||||
* @returns The current loading phrase.
|
||||
*/
|
||||
export const usePhraseCycler = (
|
||||
@@ -28,6 +29,7 @@ export const usePhraseCycler = (
|
||||
shouldShowFocusHint: boolean,
|
||||
loadingPhrasesMode: LoadingPhrasesMode = 'tips',
|
||||
customPhrases?: string[],
|
||||
maxLength?: number,
|
||||
) => {
|
||||
const [currentLoadingPhrase, setCurrentLoadingPhrase] = useState<
|
||||
string | undefined
|
||||
@@ -65,31 +67,48 @@ export const usePhraseCycler = (
|
||||
|
||||
const setRandomPhrase = () => {
|
||||
let phraseList: readonly string[];
|
||||
let currentMode = loadingPhrasesMode;
|
||||
|
||||
switch (loadingPhrasesMode) {
|
||||
// In 'all' mode, we decide once per phrase cycle what to show
|
||||
if (loadingPhrasesMode === 'all') {
|
||||
if (!hasShownFirstRequestTipRef.current) {
|
||||
currentMode = 'tips';
|
||||
hasShownFirstRequestTipRef.current = true;
|
||||
} else {
|
||||
currentMode = Math.random() < 1 / 2 ? 'tips' : 'witty';
|
||||
}
|
||||
}
|
||||
|
||||
switch (currentMode) {
|
||||
case 'tips':
|
||||
phraseList = INFORMATIVE_TIPS;
|
||||
break;
|
||||
case 'witty':
|
||||
phraseList = wittyPhrases;
|
||||
break;
|
||||
case 'all':
|
||||
// Show a tip on the first request after startup, then continue with 1/2 chance
|
||||
if (!hasShownFirstRequestTipRef.current) {
|
||||
phraseList = INFORMATIVE_TIPS;
|
||||
hasShownFirstRequestTipRef.current = true;
|
||||
} else {
|
||||
const showTip = Math.random() < 1 / 2;
|
||||
phraseList = showTip ? INFORMATIVE_TIPS : wittyPhrases;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
phraseList = INFORMATIVE_TIPS;
|
||||
break;
|
||||
}
|
||||
|
||||
const randomIndex = Math.floor(Math.random() * phraseList.length);
|
||||
setCurrentLoadingPhrase(phraseList[randomIndex]);
|
||||
// If we have a maxLength, we need to account for potential prefixes.
|
||||
// Tips are prefixed with "Tip: " in the Composer UI.
|
||||
const prefixLength = currentMode === 'tips' ? 5 : 0;
|
||||
const adjustedMaxLength =
|
||||
maxLength !== undefined ? maxLength - prefixLength : undefined;
|
||||
|
||||
const filteredList =
|
||||
adjustedMaxLength !== undefined
|
||||
? phraseList.filter((p) => p.length <= adjustedMaxLength)
|
||||
: phraseList;
|
||||
|
||||
if (filteredList.length > 0) {
|
||||
const randomIndex = Math.floor(Math.random() * filteredList.length);
|
||||
setCurrentLoadingPhrase(filteredList[randomIndex]);
|
||||
} else {
|
||||
// If no phrases fit, try to fallback to a very short list or nothing
|
||||
setCurrentLoadingPhrase(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
// Select an initial random phrase
|
||||
@@ -112,6 +131,7 @@ export const usePhraseCycler = (
|
||||
shouldShowFocusHint,
|
||||
loadingPhrasesMode,
|
||||
customPhrases,
|
||||
maxLength,
|
||||
]);
|
||||
|
||||
return currentLoadingPhrase;
|
||||
|
||||
Reference in New Issue
Block a user