Add emoji thought bubble with fallback

This commit is contained in:
Dmitry Lyalin
2026-01-31 11:35:59 -05:00
parent 4620d5bb15
commit a55d278905
2 changed files with 31 additions and 10 deletions

View File

@@ -9,7 +9,7 @@ import { render } from '../../../test-utils/render.js';
import { ThinkingMessage } from './ThinkingMessage.js';
describe('ThinkingMessage', () => {
it('renders thinking header', () => {
it('renders thinking subject', () => {
const { lastFrame } = render(
<ThinkingMessage
thought={{ subject: 'Planning', description: 'test' }}
@@ -17,7 +17,7 @@ describe('ThinkingMessage', () => {
/>,
);
expect(lastFrame()).toContain('Thinking');
expect(lastFrame()).toContain('Planning');
});
it('renders with thought subject', () => {
@@ -54,6 +54,6 @@ describe('ThinkingMessage', () => {
/>,
);
expect(lastFrame()).toContain('Thinking');
expect(lastFrame()).not.toContain('Planning');
});
});

View File

@@ -6,6 +6,7 @@
import type React from 'react';
import { Box, Text } from 'ink';
import process from 'node:process';
import type { ThoughtSummary } from '@google/gemini-cli-core';
import { MaxSizedBox, MINIMUM_MAX_HEIGHT } from '../shared/MaxSizedBox.js';
@@ -22,10 +23,13 @@ export const ThinkingMessage: React.FC<ThinkingMessageProps> = ({
}) => {
const subject = thought.subject.trim();
const description = thought.description.trim();
const headerText = subject || description;
const bodyText = subject ? description : '';
const contentMaxHeight =
availableTerminalHeight !== undefined
? Math.max(availableTerminalHeight - 4, MINIMUM_MAX_HEIGHT)
: undefined;
const bubbleIcon = shouldUseEmojiBubble() ? '💬' : '◆';
return (
<Box
@@ -41,17 +45,34 @@ export const ThinkingMessage: React.FC<ThinkingMessageProps> = ({
maxWidth={terminalWidth - 2}
overflowDirection="top"
>
{(subject || description) && (
{headerText && (
<Box flexDirection="column">
{subject && (
<Text bold color="magenta">
{subject}
</Text>
)}
{description && <Text>{description}</Text>}
<Text bold color="magenta">
{bubbleIcon} {headerText}
</Text>
{bodyText && <Text>{bodyText}</Text>}
</Box>
)}
</MaxSizedBox>
</Box>
);
};
function shouldUseEmojiBubble(): boolean {
const locale = (
process.env['LC_ALL'] ||
process.env['LC_CTYPE'] ||
process.env['LANG'] ||
''
).toLowerCase();
const supportsUtf8 = locale.includes('utf-8') || locale.includes('utf8');
if (!supportsUtf8) {
return false;
}
if (process.env['TERM'] === 'linux') {
return false;
}
return true;
}