mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-11 14:40:52 -07:00
fix(ui): Correct footer measurement and prevent negative terminal height (#8362)
This commit is contained in:
@@ -40,6 +40,14 @@ vi.mock('./App.js', () => ({
|
||||
App: TestContextConsumer,
|
||||
}));
|
||||
|
||||
vi.mock('ink', async (importOriginal) => {
|
||||
const original = await importOriginal<typeof import('ink')>();
|
||||
return {
|
||||
...original,
|
||||
measureElement: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('./hooks/useQuotaAndFallback.js');
|
||||
vi.mock('./hooks/useHistoryManager.js');
|
||||
vi.mock('./hooks/useThemeCommand.js');
|
||||
@@ -92,6 +100,9 @@ import { useSessionStats } from './contexts/SessionContext.js';
|
||||
import { useTextBuffer } from './components/shared/text-buffer.js';
|
||||
import { useLogger } from './hooks/useLogger.js';
|
||||
import { useLoadingIndicator } from './hooks/useLoadingIndicator.js';
|
||||
import { measureElement } from 'ink';
|
||||
import { useTerminalSize } from './hooks/useTerminalSize.js';
|
||||
import { ShellExecutionService } from '@google/gemini-cli-core';
|
||||
|
||||
describe('AppContainer State Management', () => {
|
||||
let mockConfig: Config;
|
||||
@@ -556,4 +567,42 @@ describe('AppContainer State Management', () => {
|
||||
expect(mockHandler).toHaveBeenCalledWith('auth');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Terminal Height Calculation', () => {
|
||||
const mockedMeasureElement = measureElement as Mock;
|
||||
const mockedUseTerminalSize = useTerminalSize as Mock;
|
||||
|
||||
it('should prevent terminal height from being less than 1', () => {
|
||||
const resizePtySpy = vi.spyOn(ShellExecutionService, 'resizePty');
|
||||
// Arrange: Simulate a small terminal and a large footer
|
||||
mockedUseTerminalSize.mockReturnValue({ columns: 80, rows: 5 });
|
||||
mockedMeasureElement.mockReturnValue({ width: 80, height: 10 }); // Footer is taller than the screen
|
||||
mockedUseGeminiStream.mockReturnValue({
|
||||
streamingState: 'idle',
|
||||
submitQuery: vi.fn(),
|
||||
initError: null,
|
||||
pendingHistoryItems: [],
|
||||
thought: null,
|
||||
cancelOngoingRequest: vi.fn(),
|
||||
activePtyId: 'some-id',
|
||||
});
|
||||
|
||||
render(
|
||||
<AppContainer
|
||||
config={mockConfig}
|
||||
settings={mockSettings}
|
||||
version="1.0.0"
|
||||
initializationResult={mockInitResult}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Assert: The shell should be resized to a minimum height of 1, not a negative number.
|
||||
// The old code would have tried to set a negative height.
|
||||
expect(resizePtySpy).toHaveBeenCalled();
|
||||
const lastCall =
|
||||
resizePtySpy.mock.calls[resizePtySpy.mock.calls.length - 1];
|
||||
// Check the height argument specifically
|
||||
expect(lastCall[2]).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,14 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { useMemo, useState, useCallback, useEffect, useRef } from 'react';
|
||||
import {
|
||||
useMemo,
|
||||
useState,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useLayoutEffect,
|
||||
} from 'react';
|
||||
import { type DOMElement, measureElement } from 'ink';
|
||||
import { App } from './App.js';
|
||||
import { AppContext } from './contexts/AppContext.js';
|
||||
@@ -622,18 +629,27 @@ Logging in with Google... Please restart Gemini CLI to continue.
|
||||
streamingState === StreamingState.Responding) &&
|
||||
!proQuotaRequest;
|
||||
|
||||
// Compute available terminal height based on controls measurement
|
||||
const availableTerminalHeight = useMemo(() => {
|
||||
const [controlsHeight, setControlsHeight] = useState(0);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (mainControlsRef.current) {
|
||||
const fullFooterMeasurement = measureElement(mainControlsRef.current);
|
||||
return terminalHeight - fullFooterMeasurement.height - staticExtraHeight;
|
||||
if (fullFooterMeasurement.height > 0) {
|
||||
setControlsHeight(fullFooterMeasurement.height);
|
||||
}
|
||||
}
|
||||
return terminalHeight - staticExtraHeight;
|
||||
}, [terminalHeight]);
|
||||
}, [buffer, terminalWidth, terminalHeight]);
|
||||
|
||||
// Compute available terminal height based on controls measurement
|
||||
const availableTerminalHeight =
|
||||
terminalHeight - controlsHeight - staticExtraHeight;
|
||||
|
||||
config.setShellExecutionConfig({
|
||||
terminalWidth: Math.floor(terminalWidth * SHELL_WIDTH_FRACTION),
|
||||
terminalHeight: Math.floor(availableTerminalHeight - SHELL_HEIGHT_PADDING),
|
||||
terminalHeight: Math.max(
|
||||
Math.floor(availableTerminalHeight - SHELL_HEIGHT_PADDING),
|
||||
1,
|
||||
),
|
||||
pager: settings.merged.tools?.shell?.pager,
|
||||
showColor: settings.merged.tools?.shell?.showColor,
|
||||
});
|
||||
@@ -660,16 +676,10 @@ Logging in with Google... Please restart Gemini CLI to continue.
|
||||
ShellExecutionService.resizePty(
|
||||
activePtyId,
|
||||
Math.floor(terminalWidth * SHELL_WIDTH_FRACTION),
|
||||
Math.floor(availableTerminalHeight - SHELL_HEIGHT_PADDING),
|
||||
Math.max(Math.floor(availableTerminalHeight - SHELL_HEIGHT_PADDING), 1),
|
||||
);
|
||||
}
|
||||
}, [
|
||||
terminalHeight,
|
||||
terminalWidth,
|
||||
availableTerminalHeight,
|
||||
activePtyId,
|
||||
geminiClient,
|
||||
]);
|
||||
}, [terminalWidth, availableTerminalHeight, activePtyId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user