mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-04 10:21:02 -07:00
Revert reducing margin on narrow screens (#10375)
This commit is contained in:
@@ -11,21 +11,15 @@ import { tokenLimit } from '@google/gemini-cli-core';
|
||||
export const ContextUsageDisplay = ({
|
||||
promptTokenCount,
|
||||
model,
|
||||
terminalWidth,
|
||||
}: {
|
||||
promptTokenCount: number;
|
||||
model: string;
|
||||
terminalWidth: number;
|
||||
}) => {
|
||||
const percentage = promptTokenCount / tokenLimit(model);
|
||||
const percentageLeft = ((1 - percentage) * 100).toFixed(0);
|
||||
|
||||
const label = terminalWidth < 100 ? '%' : '% context left';
|
||||
|
||||
return (
|
||||
<Text color={theme.text.secondary}>
|
||||
({percentageLeft}
|
||||
{label})
|
||||
({((1 - percentage) * 100).toFixed(0)}% context left)
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ import { describe, it, expect, vi } from 'vitest';
|
||||
import { Footer } from './Footer.js';
|
||||
import * as useTerminalSize from '../hooks/useTerminalSize.js';
|
||||
import { tildeifyPath } from '@google/gemini-cli-core';
|
||||
import path from 'node:path';
|
||||
import { type UIState, UIStateContext } from '../contexts/UIStateContext.js';
|
||||
import { ConfigContext } from '../contexts/ConfigContext.js';
|
||||
import { SettingsContext } from '../contexts/SettingsContext.js';
|
||||
@@ -102,22 +103,34 @@ describe('<Footer />', () => {
|
||||
});
|
||||
|
||||
describe('path display', () => {
|
||||
it('should display a shortened path on a narrow terminal', () => {
|
||||
const { lastFrame } = renderWithWidth(79, createMockUIState());
|
||||
it('should display shortened path on a wide terminal', () => {
|
||||
const { lastFrame } = renderWithWidth(120, createMockUIState());
|
||||
const tildePath = tildeifyPath(defaultProps.targetDir);
|
||||
const pathLength = Math.max(20, Math.floor(79 * 0.25));
|
||||
const expectedPath =
|
||||
'...' + tildePath.slice(tildePath.length - pathLength + 3);
|
||||
const expectedPath = '...' + tildePath.slice(tildePath.length - 48 + 3);
|
||||
expect(lastFrame()).toContain(expectedPath);
|
||||
});
|
||||
|
||||
it('should display only the base directory name on a narrow terminal', () => {
|
||||
const { lastFrame } = renderWithWidth(79, createMockUIState());
|
||||
const expectedPath = path.basename(defaultProps.targetDir);
|
||||
expect(lastFrame()).toContain(expectedPath);
|
||||
});
|
||||
|
||||
it('should use wide layout at 80 columns', () => {
|
||||
const { lastFrame } = renderWithWidth(80, createMockUIState());
|
||||
const tildePath = tildeifyPath(defaultProps.targetDir);
|
||||
const expectedPath =
|
||||
'...' + tildePath.slice(tildePath.length - 80 * 0.25 + 3);
|
||||
const expectedPath = '...' + tildePath.slice(tildePath.length - 32 + 3);
|
||||
expect(lastFrame()).toContain(expectedPath);
|
||||
});
|
||||
|
||||
it('should use narrow layout at 79 columns', () => {
|
||||
const { lastFrame } = renderWithWidth(79, createMockUIState());
|
||||
const expectedPath = path.basename(defaultProps.targetDir);
|
||||
expect(lastFrame()).toContain(expectedPath);
|
||||
const tildePath = tildeifyPath(defaultProps.targetDir);
|
||||
const unexpectedPath = '...' + tildePath.slice(tildePath.length - 31 + 3);
|
||||
expect(lastFrame()).not.toContain(unexpectedPath);
|
||||
});
|
||||
});
|
||||
|
||||
it('displays the branch name when provided', () => {
|
||||
@@ -138,13 +151,7 @@ describe('<Footer />', () => {
|
||||
it('displays the model name and context percentage', () => {
|
||||
const { lastFrame } = renderWithWidth(120, createMockUIState());
|
||||
expect(lastFrame()).toContain(defaultProps.model);
|
||||
expect(lastFrame()).toMatch(/\(\d+% context left\)/);
|
||||
});
|
||||
|
||||
it('displays the model name and abbreviated context percentage', () => {
|
||||
const { lastFrame } = renderWithWidth(99, createMockUIState());
|
||||
expect(lastFrame()).toContain(defaultProps.model);
|
||||
expect(lastFrame()).toMatch(/\(\d+%\)/);
|
||||
expect(lastFrame()).toMatch(/\(\d+% context[\s\S]*left\)/);
|
||||
});
|
||||
|
||||
describe('sandbox and trust info', () => {
|
||||
|
||||
@@ -10,11 +10,14 @@ import { theme } from '../semantic-colors.js';
|
||||
import { shortenPath, tildeifyPath } from '@google/gemini-cli-core';
|
||||
import { ConsoleSummaryDisplay } from './ConsoleSummaryDisplay.js';
|
||||
import process from 'node:process';
|
||||
import path from 'node:path';
|
||||
import Gradient from 'ink-gradient';
|
||||
import { MemoryUsageDisplay } from './MemoryUsageDisplay.js';
|
||||
import { ContextUsageDisplay } from './ContextUsageDisplay.js';
|
||||
import { DebugProfiler } from './DebugProfiler.js';
|
||||
|
||||
import { useTerminalSize } from '../hooks/useTerminalSize.js';
|
||||
import { isNarrowWidth } from '../utils/isNarrowWidth.js';
|
||||
|
||||
import { useUIState } from '../contexts/UIStateContext.js';
|
||||
import { useConfig } from '../contexts/ConfigContext.js';
|
||||
@@ -62,8 +65,13 @@ export const Footer: React.FC = () => {
|
||||
|
||||
const { columns: terminalWidth } = useTerminalSize();
|
||||
|
||||
const pathLength = Math.max(20, Math.floor(terminalWidth * 0.25));
|
||||
const displayPath = shortenPath(tildeifyPath(targetDir), pathLength);
|
||||
const isNarrow = isNarrowWidth(terminalWidth);
|
||||
|
||||
// Adjust path length based on terminal width
|
||||
const pathLength = Math.max(20, Math.floor(terminalWidth * 0.4));
|
||||
const displayPath = isNarrow
|
||||
? path.basename(tildeifyPath(targetDir))
|
||||
: shortenPath(tildeifyPath(targetDir), pathLength);
|
||||
|
||||
const justifyContent = hideCWD && hideModelInfo ? 'center' : 'space-between';
|
||||
const displayVimMode = vimEnabled ? vimMode : undefined;
|
||||
@@ -72,8 +80,8 @@ export const Footer: React.FC = () => {
|
||||
<Box
|
||||
justifyContent={justifyContent}
|
||||
width="100%"
|
||||
flexDirection="row"
|
||||
alignItems="center"
|
||||
flexDirection={isNarrow ? 'column' : 'row'}
|
||||
alignItems={isNarrow ? 'flex-start' : 'center'}
|
||||
>
|
||||
{(debugMode || displayVimMode || !hideCWD) && (
|
||||
<Box>
|
||||
@@ -108,10 +116,12 @@ export const Footer: React.FC = () => {
|
||||
{/* Middle Section: Centered Trust/Sandbox Info */}
|
||||
{!hideSandboxStatus && (
|
||||
<Box
|
||||
flexGrow={1}
|
||||
flexGrow={isNarrow || hideCWD || hideModelInfo ? 0 : 1}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
justifyContent={isNarrow || hideCWD ? 'flex-start' : 'center'}
|
||||
display="flex"
|
||||
paddingX={isNarrow ? 0 : 1}
|
||||
paddingTop={isNarrow ? 1 : 0}
|
||||
>
|
||||
{isTrustedFolder === false ? (
|
||||
<Text color={theme.status.warning}>untrusted</Text>
|
||||
@@ -129,33 +139,35 @@ export const Footer: React.FC = () => {
|
||||
</Text>
|
||||
) : (
|
||||
<Text color={theme.status.error}>
|
||||
no sandbox
|
||||
{terminalWidth >= 100 && (
|
||||
<Text color={theme.text.secondary}> (see /docs)</Text>
|
||||
)}
|
||||
no sandbox <Text color={theme.text.secondary}>(see /docs)</Text>
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Right Section: Gemini Label and Console Summary */}
|
||||
{!hideModelInfo && (
|
||||
<Box alignItems="center" justifyContent="flex-end">
|
||||
<Box alignItems="center">
|
||||
<Text color={theme.text.accent}>
|
||||
{model}{' '}
|
||||
<ContextUsageDisplay
|
||||
promptTokenCount={promptTokenCount}
|
||||
model={model}
|
||||
terminalWidth={terminalWidth}
|
||||
/>
|
||||
</Text>
|
||||
{showMemoryUsage && <MemoryUsageDisplay />}
|
||||
</Box>
|
||||
{(!hideModelInfo ||
|
||||
showMemoryUsage ||
|
||||
corgiMode ||
|
||||
(!showErrorDetails && errorCount > 0)) && (
|
||||
<Box alignItems="center" paddingTop={isNarrow ? 1 : 0}>
|
||||
{!hideModelInfo && (
|
||||
<Box alignItems="center">
|
||||
<Text color={theme.text.accent}>
|
||||
{isNarrow ? '' : ' '}
|
||||
{model}{' '}
|
||||
<ContextUsageDisplay
|
||||
promptTokenCount={promptTokenCount}
|
||||
model={model}
|
||||
/>
|
||||
</Text>
|
||||
{showMemoryUsage && <MemoryUsageDisplay />}
|
||||
</Box>
|
||||
)}
|
||||
<Box alignItems="center" paddingLeft={2}>
|
||||
{corgiMode && (
|
||||
<Text>
|
||||
<Text color={theme.ui.symbol}>| </Text>
|
||||
{!hideModelInfo && <Text color={theme.ui.comment}>| </Text>}
|
||||
<Text color={theme.status.error}>▼</Text>
|
||||
<Text color={theme.text.primary}>(´</Text>
|
||||
<Text color={theme.status.error}>ᴥ</Text>
|
||||
@@ -165,7 +177,7 @@ export const Footer: React.FC = () => {
|
||||
)}
|
||||
{!showErrorDetails && errorCount > 0 && (
|
||||
<Box>
|
||||
<Text color={theme.ui.symbol}>| </Text>
|
||||
{!hideModelInfo && <Text color={theme.ui.comment}>| </Text>}
|
||||
<ConsoleSummaryDisplay errorCount={errorCount} />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders complete footer in narrow terminal (baseline narrow) > complete-footer-narrow 1`] = `"...s/to/make/it/long (main*) no sandbox gemini-pro (100%)"`;
|
||||
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders complete footer in narrow terminal (baseline narrow) > complete-footer-narrow 1`] = `
|
||||
"long (main*)
|
||||
|
||||
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders complete footer with all sections visible (baseline) > complete-footer-wide 1`] = `"...directories/to/make/it/long (main*) no sandbox (see /docs) gemini-pro (100% context left)"`;
|
||||
no sandbox (see /docs)
|
||||
|
||||
gemini-pro (100% context left)"
|
||||
`;
|
||||
|
||||
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders complete footer with all sections visible (baseline) > complete-footer-wide 1`] = `
|
||||
"...bar/and/some/more/directories/to/make/it/long no sandbox (see gemini-pro (100% context
|
||||
(main*) /docs) left)"
|
||||
`;
|
||||
|
||||
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders footer with CWD and model info hidden to test alignment (only sandbox visible) > footer-only-sandbox 1`] = `" no sandbox (see /docs)"`;
|
||||
|
||||
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders footer with all optional sections hidden (minimal footer) > footer-minimal 1`] = `""`;
|
||||
|
||||
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders footer with only model info hidden (partial filtering) > footer-no-model 1`] = `"...directories/to/make/it/long (main*) no sandbox (see /docs)"`;
|
||||
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders footer with only model info hidden (partial filtering) > footer-no-model 1`] = `"...bar/and/some/more/directories/to/make/it/long (main*) no sandbox (see /docs)"`;
|
||||
|
||||
Reference in New Issue
Block a user