Skip to content

Commit ef76a80

Browse files
authored
Revert reducing margin on narrow screens (google-gemini#10375)
1 parent 6eca199 commit ef76a80

7 files changed

Lines changed: 74 additions & 92 deletions

File tree

packages/cli/src/ui/App.tsx

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,23 @@
55
*/
66

77
import { useIsScreenReaderEnabled } from 'ink';
8-
import { useTerminalSize } from './hooks/useTerminalSize.js';
9-
import { lerp } from '../utils/math.js';
108
import { useUIState } from './contexts/UIStateContext.js';
119
import { StreamingContext } from './contexts/StreamingContext.js';
1210
import { QuittingDisplay } from './components/QuittingDisplay.js';
1311
import { ScreenReaderAppLayout } from './layouts/ScreenReaderAppLayout.js';
1412
import { DefaultAppLayout } from './layouts/DefaultAppLayout.js';
1513

16-
const getContainerWidth = (terminalWidth: number): string => {
17-
if (terminalWidth <= 80) {
18-
return '98%';
19-
}
20-
if (terminalWidth >= 132) {
21-
return '90%';
22-
}
23-
24-
// Linearly interpolate between 80 columns (98%) and 132 columns (90%).
25-
const t = (terminalWidth - 80) / (132 - 80);
26-
const percentage = lerp(98, 90, t);
27-
28-
return `${Math.round(percentage)}%`;
29-
};
30-
3114
export const App = () => {
3215
const uiState = useUIState();
3316
const isScreenReaderEnabled = useIsScreenReaderEnabled();
34-
const { columns } = useTerminalSize();
35-
const containerWidth = getContainerWidth(columns);
3617

3718
if (uiState.quittingMessages) {
3819
return <QuittingDisplay />;
3920
}
4021

4122
return (
4223
<StreamingContext.Provider value={uiState.streamingState}>
43-
{isScreenReaderEnabled ? (
44-
<ScreenReaderAppLayout />
45-
) : (
46-
<DefaultAppLayout width={containerWidth} />
47-
)}
24+
{isScreenReaderEnabled ? <ScreenReaderAppLayout /> : <DefaultAppLayout />}
4825
</StreamingContext.Provider>
4926
);
5027
};

packages/cli/src/ui/components/ContextUsageDisplay.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,15 @@ import { tokenLimit } from '@google/gemini-cli-core';
1111
export const ContextUsageDisplay = ({
1212
promptTokenCount,
1313
model,
14-
terminalWidth,
1514
}: {
1615
promptTokenCount: number;
1716
model: string;
18-
terminalWidth: number;
1917
}) => {
2018
const percentage = promptTokenCount / tokenLimit(model);
21-
const percentageLeft = ((1 - percentage) * 100).toFixed(0);
22-
23-
const label = terminalWidth < 100 ? '%' : '% context left';
2419

2520
return (
2621
<Text color={theme.text.secondary}>
27-
({percentageLeft}
28-
{label})
22+
({((1 - percentage) * 100).toFixed(0)}% context left)
2923
</Text>
3024
);
3125
};

packages/cli/src/ui/components/Footer.test.tsx

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { describe, it, expect, vi } from 'vitest';
99
import { Footer } from './Footer.js';
1010
import * as useTerminalSize from '../hooks/useTerminalSize.js';
1111
import { tildeifyPath } from '@google/gemini-cli-core';
12+
import path from 'node:path';
1213
import { type UIState, UIStateContext } from '../contexts/UIStateContext.js';
1314
import { ConfigContext } from '../contexts/ConfigContext.js';
1415
import { SettingsContext } from '../contexts/SettingsContext.js';
@@ -102,21 +103,33 @@ describe('<Footer />', () => {
102103
});
103104

104105
describe('path display', () => {
105-
it('should display a shortened path on a narrow terminal', () => {
106-
const { lastFrame } = renderWithWidth(79, createMockUIState());
106+
it('should display shortened path on a wide terminal', () => {
107+
const { lastFrame } = renderWithWidth(120, createMockUIState());
107108
const tildePath = tildeifyPath(defaultProps.targetDir);
108-
const pathLength = Math.max(20, Math.floor(79 * 0.25));
109-
const expectedPath =
110-
'...' + tildePath.slice(tildePath.length - pathLength + 3);
109+
const expectedPath = '...' + tildePath.slice(tildePath.length - 48 + 3);
110+
expect(lastFrame()).toContain(expectedPath);
111+
});
112+
113+
it('should display only the base directory name on a narrow terminal', () => {
114+
const { lastFrame } = renderWithWidth(79, createMockUIState());
115+
const expectedPath = path.basename(defaultProps.targetDir);
111116
expect(lastFrame()).toContain(expectedPath);
112117
});
113118

114119
it('should use wide layout at 80 columns', () => {
115120
const { lastFrame } = renderWithWidth(80, createMockUIState());
116121
const tildePath = tildeifyPath(defaultProps.targetDir);
117-
const expectedPath =
118-
'...' + tildePath.slice(tildePath.length - 80 * 0.25 + 3);
122+
const expectedPath = '...' + tildePath.slice(tildePath.length - 32 + 3);
123+
expect(lastFrame()).toContain(expectedPath);
124+
});
125+
126+
it('should use narrow layout at 79 columns', () => {
127+
const { lastFrame } = renderWithWidth(79, createMockUIState());
128+
const expectedPath = path.basename(defaultProps.targetDir);
119129
expect(lastFrame()).toContain(expectedPath);
130+
const tildePath = tildeifyPath(defaultProps.targetDir);
131+
const unexpectedPath = '...' + tildePath.slice(tildePath.length - 31 + 3);
132+
expect(lastFrame()).not.toContain(unexpectedPath);
120133
});
121134
});
122135

@@ -138,13 +151,7 @@ describe('<Footer />', () => {
138151
it('displays the model name and context percentage', () => {
139152
const { lastFrame } = renderWithWidth(120, createMockUIState());
140153
expect(lastFrame()).toContain(defaultProps.model);
141-
expect(lastFrame()).toMatch(/\(\d+% context left\)/);
142-
});
143-
144-
it('displays the model name and abbreviated context percentage', () => {
145-
const { lastFrame } = renderWithWidth(99, createMockUIState());
146-
expect(lastFrame()).toContain(defaultProps.model);
147-
expect(lastFrame()).toMatch(/\(\d+%\)/);
154+
expect(lastFrame()).toMatch(/\(\d+% context[\s\S]*left\)/);
148155
});
149156

150157
describe('sandbox and trust info', () => {

packages/cli/src/ui/components/Footer.tsx

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import { theme } from '../semantic-colors.js';
1010
import { shortenPath, tildeifyPath } from '@google/gemini-cli-core';
1111
import { ConsoleSummaryDisplay } from './ConsoleSummaryDisplay.js';
1212
import process from 'node:process';
13+
import path from 'node:path';
1314
import Gradient from 'ink-gradient';
1415
import { MemoryUsageDisplay } from './MemoryUsageDisplay.js';
1516
import { ContextUsageDisplay } from './ContextUsageDisplay.js';
1617
import { DebugProfiler } from './DebugProfiler.js';
18+
1719
import { useTerminalSize } from '../hooks/useTerminalSize.js';
20+
import { isNarrowWidth } from '../utils/isNarrowWidth.js';
1821

1922
import { useUIState } from '../contexts/UIStateContext.js';
2023
import { useConfig } from '../contexts/ConfigContext.js';
@@ -62,8 +65,13 @@ export const Footer: React.FC = () => {
6265

6366
const { columns: terminalWidth } = useTerminalSize();
6467

65-
const pathLength = Math.max(20, Math.floor(terminalWidth * 0.25));
66-
const displayPath = shortenPath(tildeifyPath(targetDir), pathLength);
68+
const isNarrow = isNarrowWidth(terminalWidth);
69+
70+
// Adjust path length based on terminal width
71+
const pathLength = Math.max(20, Math.floor(terminalWidth * 0.4));
72+
const displayPath = isNarrow
73+
? path.basename(tildeifyPath(targetDir))
74+
: shortenPath(tildeifyPath(targetDir), pathLength);
6775

6876
const justifyContent = hideCWD && hideModelInfo ? 'center' : 'space-between';
6977
const displayVimMode = vimEnabled ? vimMode : undefined;
@@ -72,8 +80,8 @@ export const Footer: React.FC = () => {
7280
<Box
7381
justifyContent={justifyContent}
7482
width="100%"
75-
flexDirection="row"
76-
alignItems="center"
83+
flexDirection={isNarrow ? 'column' : 'row'}
84+
alignItems={isNarrow ? 'flex-start' : 'center'}
7785
>
7886
{(debugMode || displayVimMode || !hideCWD) && (
7987
<Box>
@@ -108,10 +116,12 @@ export const Footer: React.FC = () => {
108116
{/* Middle Section: Centered Trust/Sandbox Info */}
109117
{!hideSandboxStatus && (
110118
<Box
111-
flexGrow={1}
119+
flexGrow={isNarrow || hideCWD || hideModelInfo ? 0 : 1}
112120
alignItems="center"
113-
justifyContent="center"
121+
justifyContent={isNarrow || hideCWD ? 'flex-start' : 'center'}
114122
display="flex"
123+
paddingX={isNarrow ? 0 : 1}
124+
paddingTop={isNarrow ? 1 : 0}
115125
>
116126
{isTrustedFolder === false ? (
117127
<Text color={theme.status.warning}>untrusted</Text>
@@ -129,33 +139,35 @@ export const Footer: React.FC = () => {
129139
</Text>
130140
) : (
131141
<Text color={theme.status.error}>
132-
no sandbox
133-
{terminalWidth >= 100 && (
134-
<Text color={theme.text.secondary}> (see /docs)</Text>
135-
)}
142+
no sandbox <Text color={theme.text.secondary}>(see /docs)</Text>
136143
</Text>
137144
)}
138145
</Box>
139146
)}
140147

141148
{/* Right Section: Gemini Label and Console Summary */}
142-
{!hideModelInfo && (
143-
<Box alignItems="center" justifyContent="flex-end">
144-
<Box alignItems="center">
145-
<Text color={theme.text.accent}>
146-
{model}{' '}
147-
<ContextUsageDisplay
148-
promptTokenCount={promptTokenCount}
149-
model={model}
150-
terminalWidth={terminalWidth}
151-
/>
152-
</Text>
153-
{showMemoryUsage && <MemoryUsageDisplay />}
154-
</Box>
149+
{(!hideModelInfo ||
150+
showMemoryUsage ||
151+
corgiMode ||
152+
(!showErrorDetails && errorCount > 0)) && (
153+
<Box alignItems="center" paddingTop={isNarrow ? 1 : 0}>
154+
{!hideModelInfo && (
155+
<Box alignItems="center">
156+
<Text color={theme.text.accent}>
157+
{isNarrow ? '' : ' '}
158+
{model}{' '}
159+
<ContextUsageDisplay
160+
promptTokenCount={promptTokenCount}
161+
model={model}
162+
/>
163+
</Text>
164+
{showMemoryUsage && <MemoryUsageDisplay />}
165+
</Box>
166+
)}
155167
<Box alignItems="center" paddingLeft={2}>
156168
{corgiMode && (
157169
<Text>
158-
<Text color={theme.ui.symbol}>| </Text>
170+
{!hideModelInfo && <Text color={theme.ui.comment}>| </Text>}
159171
<Text color={theme.status.error}></Text>
160172
<Text color={theme.text.primary}></Text>
161173
<Text color={theme.status.error}></Text>
@@ -165,7 +177,7 @@ export const Footer: React.FC = () => {
165177
)}
166178
{!showErrorDetails && errorCount > 0 && (
167179
<Box>
168-
<Text color={theme.ui.symbol}>| </Text>
180+
{!hideModelInfo && <Text color={theme.ui.comment}>| </Text>}
169181
<ConsoleSummaryDisplay errorCount={errorCount} />
170182
</Box>
171183
)}
Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
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%)"`;
3+
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders complete footer in narrow terminal (baseline narrow) > complete-footer-narrow 1`] = `
4+
"long (main*)
45
5-
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)"`;
6+
no sandbox (see /docs)
7+
8+
gemini-pro (100% context left)"
9+
`;
10+
11+
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders complete footer with all sections visible (baseline) > complete-footer-wide 1`] = `
12+
"...bar/and/some/more/directories/to/make/it/long no sandbox (see gemini-pro (100% context
13+
(main*) /docs) left)"
14+
`;
615

716
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)"`;
817

918
exports[`<Footer /> > footer configuration filtering (golden snapshots) > renders footer with all optional sections hidden (minimal footer) > footer-minimal 1`] = `""`;
1019

11-
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)"`;
20+
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)"`;

packages/cli/src/ui/layouts/DefaultAppLayout.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@ import { Composer } from '../components/Composer.js';
1313
import { ExitWarning } from '../components/ExitWarning.js';
1414
import { useUIState } from '../contexts/UIStateContext.js';
1515

16-
export const DefaultAppLayout: React.FC<{ width?: string }> = ({
17-
width = '90%',
18-
}) => {
16+
export const DefaultAppLayout: React.FC = () => {
1917
const uiState = useUIState();
2018

2119
return (
22-
<Box flexDirection="column" width={width}>
20+
<Box flexDirection="column" width="90%">
2321
<MainContent />
2422

2523
<Box flexDirection="column" ref={uiState.mainControlsRef}>

packages/cli/src/utils/math.ts

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)