Files
gemini-cli/packages/cli/src/ui/components/DetailedMessagesDisplay.tsx

121 lines
3.4 KiB
TypeScript
Raw Normal View History

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
2025-11-04 16:21:00 -08:00
import { useRef, useCallback } from 'react';
import type React from 'react';
import { Box, Text } from 'ink';
import { theme } from '../semantic-colors.js';
import type { ConsoleMessageItem } from '../types.js';
2025-11-04 16:21:00 -08:00
import {
ScrollableList,
type ScrollableListRef,
} from './shared/ScrollableList.js';
interface DetailedMessagesDisplayProps {
messages: ConsoleMessageItem[];
maxHeight: number | undefined;
width: number;
2025-11-04 16:21:00 -08:00
hasFocus: boolean;
}
const iconBoxWidth = 3;
export const DetailedMessagesDisplay: React.FC<
DetailedMessagesDisplayProps
2025-11-04 16:21:00 -08:00
> = ({ messages, maxHeight, width, hasFocus }) => {
const scrollableListRef = useRef<ScrollableListRef<ConsoleMessageItem>>(null);
const borderAndPadding = 3;
2025-11-04 16:21:00 -08:00
const estimatedItemHeight = useCallback(
(index: number) => {
const msg = messages[index];
if (!msg) {
return 1;
}
const textWidth = width - borderAndPadding - iconBoxWidth;
2025-11-04 16:21:00 -08:00
if (textWidth <= 0) {
return 1;
}
const lines = Math.ceil((msg.content?.length || 1) / textWidth);
return Math.max(1, lines);
},
[width, messages],
);
if (messages.length === 0) {
2025-11-04 16:21:00 -08:00
return null;
}
return (
<Box
flexDirection="column"
marginTop={1}
borderStyle="round"
borderColor={theme.border.default}
2025-11-04 16:21:00 -08:00
paddingLeft={1}
width={width}
2025-11-04 16:21:00 -08:00
height={maxHeight}
flexShrink={0}
flexGrow={0}
overflow="hidden"
>
<Box marginBottom={1}>
<Text bold color={theme.text.primary}>
Debug Console <Text color={theme.text.secondary}>(F12 to close)</Text>
</Text>
</Box>
2025-11-04 16:21:00 -08:00
<Box height={maxHeight} width={width - borderAndPadding}>
<ScrollableList
ref={scrollableListRef}
data={messages}
renderItem={({ item: msg }: { item: ConsoleMessageItem }) => {
let textColor = theme.text.primary;
let icon = ''; // Information source ()
2025-11-04 16:21:00 -08:00
switch (msg.type) {
case 'warn':
textColor = theme.status.warning;
icon = '⚠'; // Warning sign (⚠)
break;
case 'error':
textColor = theme.status.error;
icon = '✖'; // Heavy multiplication x (✖)
break;
case 'debug':
textColor = theme.text.secondary; // Or theme.text.secondary
icon = '🔍'; // Left-pointing magnifying glass (🔍)
break;
case 'log':
default:
// Default textColor and icon are already set
break;
}
2025-11-04 16:21:00 -08:00
return (
<Box flexDirection="row">
<Box minWidth={iconBoxWidth} flexShrink={0}>
<Text color={textColor}>{icon}</Text>
</Box>
2025-11-04 16:21:00 -08:00
<Text color={textColor} wrap="wrap">
{msg.content}
{msg.count && msg.count > 1 && (
<Text color={theme.text.secondary}> (x{msg.count})</Text>
)}
</Text>
</Box>
);
}}
keyExtractor={(item, index) => `${item.content}-${index}`}
estimatedItemHeight={estimatedItemHeight}
hasFocus={hasFocus}
initialScrollIndex={Number.MAX_SAFE_INTEGER}
/>
</Box>
</Box>
);
};