From 3e786aad1c0baeb71099ca825200eb445dcf6ed3 Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Fri, 6 Mar 2026 11:59:31 -0500 Subject: [PATCH 01/12] Changed max height --- .../cli/src/ui/components/MainContent.tsx | 19 +- .../__snapshots__/MainContent.test.tsx.snap | 35 ++- .../cli/src/ui/utils/toolLayoutUtils.test.ts | 213 ++++++++++++++++++ packages/cli/src/ui/utils/toolLayoutUtils.ts | 13 +- 4 files changed, 260 insertions(+), 20 deletions(-) create mode 100644 packages/cli/src/ui/utils/toolLayoutUtils.test.ts diff --git a/packages/cli/src/ui/components/MainContent.tsx b/packages/cli/src/ui/components/MainContent.tsx index 7386a246e7b..7d26f9f88e1 100644 --- a/packages/cli/src/ui/components/MainContent.tsx +++ b/packages/cli/src/ui/components/MainContent.tsx @@ -48,6 +48,7 @@ export const MainContent = () => { pendingHistoryItems, mainAreaWidth, staticAreaMaxItemHeight, + availableTerminalHeight, cleanUiDetailsVisible, } = uiState; const showHeaderDetails = cleanUiDetailsVisible; @@ -70,9 +71,11 @@ export const MainContent = () => { { uiState.history, mainAreaWidth, staticAreaMaxItemHeight, + availableTerminalHeight, uiState.slashCommands, uiState.constrainHeight, lastUserPromptIndex, @@ -110,7 +114,7 @@ export const MainContent = () => { { [ pendingHistoryItems, uiState.constrainHeight, - staticAreaMaxItemHeight, + availableTerminalHeight, mainAreaWidth, showConfirmationQueue, confirmingTool, @@ -161,9 +165,11 @@ export const MainContent = () => { { pendingItems, uiState.constrainHeight, staticAreaMaxItemHeight, + availableTerminalHeight, ], ); diff --git a/packages/cli/src/ui/components/__snapshots__/MainContent.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/MainContent.test.tsx.snap index d01043eee9c..35ed23e664f 100644 --- a/packages/cli/src/ui/components/__snapshots__/MainContent.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/MainContent.test.tsx.snap @@ -6,11 +6,15 @@ AppHeader(full) ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command Running a long command... │ │ │ -│ Line 10 │ -│ Line 11 │ -│ Line 12 │ -│ Line 13 │ -│ Line 14 │ +│ Line 6 │ +│ Line 7 │ +│ Line 8 │ +│ Line 9 ▄ │ +│ Line 10 █ │ +│ Line 11 █ │ +│ Line 12 █ │ +│ Line 13 █ │ +│ Line 14 █ │ │ Line 15 █ │ │ Line 16 █ │ │ Line 17 █ │ @@ -28,11 +32,15 @@ AppHeader(full) ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command Running a long command... │ │ │ -│ Line 10 │ -│ Line 11 │ -│ Line 12 │ -│ Line 13 │ -│ Line 14 │ +│ Line 6 │ +│ Line 7 │ +│ Line 8 │ +│ Line 9 ▄ │ +│ Line 10 █ │ +│ Line 11 █ │ +│ Line 12 █ │ +│ Line 13 █ │ +│ Line 14 █ │ │ Line 15 █ │ │ Line 16 █ │ │ Line 17 █ │ @@ -49,7 +57,12 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Con ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command Running a long command... │ │ │ -│ ... first 11 lines hidden (Ctrl+O to show) ... │ +│ ... first 6 lines hidden (Ctrl+O to show) ... │ +│ Line 7 │ +│ Line 8 │ +│ Line 9 │ +│ Line 10 │ +│ Line 11 │ │ Line 12 │ │ Line 13 │ │ Line 14 │ diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.test.ts b/packages/cli/src/ui/utils/toolLayoutUtils.test.ts new file mode 100644 index 00000000000..d8c74dd31ad --- /dev/null +++ b/packages/cli/src/ui/utils/toolLayoutUtils.test.ts @@ -0,0 +1,213 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { describe, it, expect } from 'vitest'; +import { + calculateToolContentMaxLines, + calculateShellMaxLines, + TOOL_RESULT_STATIC_HEIGHT, + TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT, +} from './toolLayoutUtils.js'; +import { CoreToolCallStatus } from '@google/gemini-cli-core'; +import { + ACTIVE_SHELL_MAX_LINES, + COMPLETED_SHELL_MAX_LINES, +} from '../constants.js'; + +describe('toolLayoutUtils', () => { + describe('calculateToolContentMaxLines', () => { + it('returns undefined if availableTerminalHeight is undefined', () => { + const result = calculateToolContentMaxLines({ + availableTerminalHeight: undefined, + isAlternateBuffer: false, + }); + expect(result).toBeUndefined(); + }); + + it('returns maxLinesLimit if maxLinesLimit applies but availableTerminalHeight is undefined', () => { + const result = calculateToolContentMaxLines({ + availableTerminalHeight: undefined, + isAlternateBuffer: false, + maxLinesLimit: 10, + }); + expect(result).toBe(10); + }); + + it('caps height to prevent overflow in constrained terminal (Standard mode)', () => { + const availableTerminalHeight = 2; // Very small + const result = calculateToolContentMaxLines({ + availableTerminalHeight, + isAlternateBuffer: false, + }); + + // Math.max(0, 2 - 1 - 2) = 0 + expect(result).toBe(0); + }); + + it('caps height to prevent overflow in constrained terminal (ASB mode)', () => { + const availableTerminalHeight = 4; // Very small + const result = calculateToolContentMaxLines({ + availableTerminalHeight, + isAlternateBuffer: true, + }); + + // Math.max(0, 4 - 1 - 6) = 0 + expect(result).toBe(0); + }); + + it('returns remaining space if sufficient space exists (Standard mode)', () => { + const availableTerminalHeight = 20; + const result = calculateToolContentMaxLines({ + availableTerminalHeight, + isAlternateBuffer: false, + }); + + // Space remaining is 20 - 1 - 2 = 17 + expect(result).toBe(17); + }); + + it('returns remaining space if sufficient space exists (ASB mode)', () => { + const availableTerminalHeight = 20; + const result = calculateToolContentMaxLines({ + availableTerminalHeight, + isAlternateBuffer: true, + }); + + // Space remaining is 20 - 1 - 6 = 13 + expect(result).toBe(13); + }); + + it('returns 0 if availableTerminalHeight is <= TOOL_RESULT_STATIC_HEIGHT + reservedLines', () => { + const result = calculateToolContentMaxLines({ + availableTerminalHeight: + TOOL_RESULT_STATIC_HEIGHT + TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT, + isAlternateBuffer: false, + }); + + // Cap at 3 - 1 - 2 = 0 + expect(result).toBe(0); + }); + }); + + describe('calculateShellMaxLines', () => { + it('returns undefined when not constrained and is expandable', () => { + const result = calculateShellMaxLines({ + status: CoreToolCallStatus.Executing, + isAlternateBuffer: false, + isThisShellFocused: false, + availableTerminalHeight: 20, + constrainHeight: false, + isExpandable: true, + }); + expect(result).toBeUndefined(); + }); + + it('returns ACTIVE_SHELL_MAX_LINES for ASB mode when availableTerminalHeight is undefined', () => { + const result = calculateShellMaxLines({ + status: CoreToolCallStatus.Executing, + isAlternateBuffer: true, + isThisShellFocused: false, + availableTerminalHeight: undefined, + constrainHeight: true, + isExpandable: false, + }); + expect(result).toBe(ACTIVE_SHELL_MAX_LINES); + }); + + it('returns undefined for Standard mode when availableTerminalHeight is undefined', () => { + const result = calculateShellMaxLines({ + status: CoreToolCallStatus.Executing, + isAlternateBuffer: false, + isThisShellFocused: false, + availableTerminalHeight: undefined, + constrainHeight: true, + isExpandable: false, + }); + expect(result).toBeUndefined(); + }); + + it('handles small availableTerminalHeight gracefully to prevent overflow in Standard mode', () => { + const result = calculateShellMaxLines({ + status: CoreToolCallStatus.Executing, + isAlternateBuffer: false, + isThisShellFocused: false, + availableTerminalHeight: 2, // Too small to subtract 1 + 2 + constrainHeight: true, + isExpandable: false, + }); + + // Math.max(0, 2 - 1 - 2) = 0 + expect(result).toBe(0); + }); + + it('handles small availableTerminalHeight gracefully to prevent overflow in ASB mode', () => { + const result = calculateShellMaxLines({ + status: CoreToolCallStatus.Executing, + isAlternateBuffer: true, + isThisShellFocused: false, + availableTerminalHeight: 6, // Too small to subtract 1 + 6 + constrainHeight: true, + isExpandable: false, + }); + + // Math.max(0, 6 - 1 - 6) = 0 + expect(result).toBe(0); + }); + + it('handles negative availableTerminalHeight gracefully', () => { + const result = calculateShellMaxLines({ + status: CoreToolCallStatus.Executing, + isAlternateBuffer: false, + isThisShellFocused: false, + availableTerminalHeight: -5, + constrainHeight: true, + isExpandable: false, + }); + + expect(result).toBe(0); + }); + + it('returns maxLinesBasedOnHeight for focused ASB shells', () => { + const result = calculateShellMaxLines({ + status: CoreToolCallStatus.Executing, + isAlternateBuffer: true, + isThisShellFocused: true, + availableTerminalHeight: 30, + constrainHeight: false, + isExpandable: false, + }); + + // 30 - 1 (static) - 6 (ASB reserved) = 23 + expect(result).toBe(23); + }); + + it('falls back to COMPLETED_SHELL_MAX_LINES for completed shells if space allows', () => { + const result = calculateShellMaxLines({ + status: CoreToolCallStatus.Success, + isAlternateBuffer: false, + isThisShellFocused: false, + availableTerminalHeight: 100, + constrainHeight: true, + isExpandable: false, + }); + + expect(result).toBe(COMPLETED_SHELL_MAX_LINES); + }); + + it('falls back to ACTIVE_SHELL_MAX_LINES for executing shells if space allows', () => { + const result = calculateShellMaxLines({ + status: CoreToolCallStatus.Executing, + isAlternateBuffer: false, + isThisShellFocused: false, + availableTerminalHeight: 100, + constrainHeight: true, + isExpandable: false, + }); + + expect(result).toBe(ACTIVE_SHELL_MAX_LINES); + }); + }); +}); diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.ts b/packages/cli/src/ui/utils/toolLayoutUtils.ts index 8f619901f69..7b35f1ccd5e 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.ts @@ -26,7 +26,7 @@ export const TOOL_RESULT_MIN_LINES_SHOWN = 2; * This accounts for: * 1. The static height of the tool message (name, status line). * 2. Reserved space for hints and padding (different in ASB vs Standard mode). - * 3. Enforcing a minimum number of lines shown. + * 3. Enforcing a physical minimum size based on terminal limits. */ export function calculateToolContentMaxLines(options: { availableTerminalHeight: number | undefined; @@ -41,8 +41,8 @@ export function calculateToolContentMaxLines(options: { let contentHeight = availableTerminalHeight ? Math.max( + 0, availableTerminalHeight - TOOL_RESULT_STATIC_HEIGHT - reservedLines, - TOOL_RESULT_MIN_LINES_SHOWN + 1, ) : undefined; @@ -91,7 +91,14 @@ export function calculateShellMaxLines(options: { return isAlternateBuffer ? ACTIVE_SHELL_MAX_LINES : undefined; } - const maxLinesBasedOnHeight = Math.max(1, availableTerminalHeight - 2); + const reservedLines = isAlternateBuffer + ? TOOL_RESULT_ASB_RESERVED_LINE_COUNT + : TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT; + + const maxLinesBasedOnHeight = Math.max( + 0, + availableTerminalHeight - TOOL_RESULT_STATIC_HEIGHT - reservedLines, + ); // 3. Handle ASB mode focus expansion. // We allow a focused shell in ASB mode to take up the full available height, From c6f29d3a2529a3d69833a22a1f46fa4e9fb16140 Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Fri, 6 Mar 2026 13:02:01 -0500 Subject: [PATCH 02/12] Updated tool heights to be compatible with changes --- .../components/messages/ToolGroupMessage.tsx | 2 +- .../components/messages/ToolResultDisplay.tsx | 20 +++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx index 5ec2a18e06e..752aed35c9f 100644 --- a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx @@ -191,7 +191,7 @@ export const ToolGroupMessage: React.FC = ({ maxLinesLimit: maxLines, }); - if (!contentMaxLines) return false; + if (contentMaxLines === undefined) return false; if (typeof tool.resultDisplay === 'string') { const text = tool.resultDisplay; diff --git a/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx b/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx index 1c29407e91a..09dee9cd316 100644 --- a/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx +++ b/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx @@ -23,7 +23,10 @@ import { Scrollable } from '../shared/Scrollable.js'; import { ScrollableList } from '../shared/ScrollableList.js'; import { SCROLL_TO_ITEM_END } from '../shared/VirtualizedList.js'; import { ACTIVE_SHELL_MAX_LINES } from '../../constants.js'; -import { calculateToolContentMaxLines } from '../../utils/toolLayoutUtils.js'; +import { + calculateToolContentMaxLines, + TOOL_RESULT_MIN_LINES_SHOWN, +} from '../../utils/toolLayoutUtils.js'; import { SubagentProgressDisplay } from './SubagentProgressDisplay.js'; // Large threshold to ensure we don't cause performance issues for very large @@ -61,6 +64,11 @@ export const ToolResultDisplay: React.FC = ({ maxLinesLimit: maxLines, }); + const effectiveMaxHeight = + availableHeight !== undefined + ? Math.max(TOOL_RESULT_MIN_LINES_SHOWN, availableHeight) + : undefined; + const combinedPaddingAndBorderWidth = 4; const childWidth = terminalWidth - combinedPaddingAndBorderWidth; @@ -132,7 +140,7 @@ export const ToolResultDisplay: React.FC = ({ if (isAlternateBuffer && Array.isArray(truncatedResultDisplay)) { // If availableHeight is undefined, fallback to a safe default to prevents infinite loop // where Container grows -> List renders more -> Container grows. - const limit = maxLines ?? availableHeight ?? ACTIVE_SHELL_MAX_LINES; + const limit = maxLines ?? effectiveMaxHeight ?? ACTIVE_SHELL_MAX_LINES; const listHeight = Math.min( // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion (truncatedResultDisplay as AnsiOutput).length, @@ -205,7 +213,7 @@ export const ToolResultDisplay: React.FC = ({ diffContent={(truncatedResultDisplay as FileDiffResult).fileDiff} // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion filename={(truncatedResultDisplay as FileDiffResult).fileName} - availableTerminalHeight={availableHeight} + availableTerminalHeight={effectiveMaxHeight} terminalWidth={childWidth} /> ); @@ -219,7 +227,7 @@ export const ToolResultDisplay: React.FC = ({ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion data={truncatedResultDisplay as AnsiOutput} availableTerminalHeight={ - isAlternateBuffer ? undefined : availableHeight + isAlternateBuffer ? undefined : effectiveMaxHeight } width={childWidth} maxLines={isAlternateBuffer ? undefined : maxLines} @@ -233,7 +241,7 @@ export const ToolResultDisplay: React.FC = ({ return ( @@ -245,7 +253,7 @@ export const ToolResultDisplay: React.FC = ({ return ( From 07522218491653962ec217bd5f6ca8f1d4fbbc02 Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Fri, 6 Mar 2026 13:26:08 -0500 Subject: [PATCH 03/12] Updated tests for ShellToolMessage --- .../messages/ShellToolMessage.test.tsx | 4 ++-- .../ShellToolMessage.test.tsx.snap | 24 ++++++------------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/packages/cli/src/ui/components/messages/ShellToolMessage.test.tsx b/packages/cli/src/ui/components/messages/ShellToolMessage.test.tsx index 233f9057603..8dc6dac738f 100644 --- a/packages/cli/src/ui/components/messages/ShellToolMessage.test.tsx +++ b/packages/cli/src/ui/components/messages/ShellToolMessage.test.tsx @@ -181,7 +181,7 @@ describe('', () => { [ 'respects availableTerminalHeight when it is smaller than ACTIVE_SHELL_MAX_LINES', 10, - 8, + 3, // 10 - 1 (static) - 6 (ASB reserved) = 3 false, ], [ @@ -193,7 +193,7 @@ describe('', () => { [ 'uses full availableTerminalHeight when focused in alternate buffer mode', 100, - 98, // 100 - 2 + 93, // 100 - 1 (static) - 6 (ASB reserved) = 93 true, ], [ diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ShellToolMessage.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ShellToolMessage.test.tsx.snap index b51d7c435b1..c4950b2c334 100644 --- a/packages/cli/src/ui/components/messages/__snapshots__/ShellToolMessage.test.tsx.snap +++ b/packages/cli/src/ui/components/messages/__snapshots__/ShellToolMessage.test.tsx.snap @@ -133,11 +133,6 @@ exports[` > Height Constraints > respects availableTerminalH "╭──────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command A shell command │ │ │ -│ Line 93 │ -│ Line 94 │ -│ Line 95 │ -│ Line 96 │ -│ Line 97 │ │ Line 98 │ │ Line 99 │ │ Line 100 █ │ @@ -192,18 +187,13 @@ exports[` > Height Constraints > uses full availableTerminal "╭──────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command A shell command (Shift+Tab to unfocus) │ │ │ -│ Line 3 │ -│ Line 4 │ -│ Line 5 █ │ -│ Line 6 █ │ -│ Line 7 █ │ -│ Line 8 █ │ -│ Line 9 █ │ -│ Line 10 █ │ -│ Line 11 █ │ -│ Line 12 █ │ -│ Line 13 █ │ -│ Line 14 █ │ +│ Line 8 │ +│ Line 9 │ +│ Line 10 │ +│ Line 11 │ +│ Line 12 │ +│ Line 13 │ +│ Line 14 ▄ │ │ Line 15 █ │ │ Line 16 █ │ │ Line 17 █ │ From 18b6482ea4918f464009e189d1e3be95ef429fd4 Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Fri, 6 Mar 2026 14:21:54 -0500 Subject: [PATCH 04/12] Revert changed comment --- packages/cli/src/ui/utils/toolLayoutUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.ts b/packages/cli/src/ui/utils/toolLayoutUtils.ts index 7b35f1ccd5e..26a10773d4f 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.ts @@ -26,7 +26,7 @@ export const TOOL_RESULT_MIN_LINES_SHOWN = 2; * This accounts for: * 1. The static height of the tool message (name, status line). * 2. Reserved space for hints and padding (different in ASB vs Standard mode). - * 3. Enforcing a physical minimum size based on terminal limits. + * 3. Enforcing a minimum number of lines shown. */ export function calculateToolContentMaxLines(options: { availableTerminalHeight: number | undefined; From d2e5ae77506b4a6f6c8164425d961b26e7e1affc Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Thu, 12 Mar 2026 13:05:56 -0500 Subject: [PATCH 05/12] Made tool calls take the entire terminal height --- .../messages/ShellToolMessage.test.tsx | 4 +- .../components/messages/ToolGroupMessage.tsx | 2 +- .../components/messages/ToolResultDisplay.tsx | 20 +- .../ShellToolMessage.test.tsx.snap | 188 ++++++++++-------- .../ToolResultDisplay.test.tsx.snap | 5 +- packages/cli/src/ui/utils/toolLayoutUtils.ts | 20 +- 6 files changed, 117 insertions(+), 122 deletions(-) diff --git a/packages/cli/src/ui/components/messages/ShellToolMessage.test.tsx b/packages/cli/src/ui/components/messages/ShellToolMessage.test.tsx index d124ebe929f..b9c076d6872 100644 --- a/packages/cli/src/ui/components/messages/ShellToolMessage.test.tsx +++ b/packages/cli/src/ui/components/messages/ShellToolMessage.test.tsx @@ -189,7 +189,7 @@ describe('', () => { [ 'respects availableTerminalHeight when it is smaller than ACTIVE_SHELL_MAX_LINES', 10, - 3, // 10 - 1 (static) - 6 (ASB reserved) = 3 + 10, false, ], [ @@ -201,7 +201,7 @@ describe('', () => { [ 'uses full availableTerminalHeight when focused in alternate buffer mode', 100, - 93, // 100 - 1 (static) - 6 (ASB reserved) = 93 + 100, true, ], [ diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx index 752aed35c9f..5ec2a18e06e 100644 --- a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx @@ -191,7 +191,7 @@ export const ToolGroupMessage: React.FC = ({ maxLinesLimit: maxLines, }); - if (contentMaxLines === undefined) return false; + if (!contentMaxLines) return false; if (typeof tool.resultDisplay === 'string') { const text = tool.resultDisplay; diff --git a/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx b/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx index 09dee9cd316..1c29407e91a 100644 --- a/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx +++ b/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx @@ -23,10 +23,7 @@ import { Scrollable } from '../shared/Scrollable.js'; import { ScrollableList } from '../shared/ScrollableList.js'; import { SCROLL_TO_ITEM_END } from '../shared/VirtualizedList.js'; import { ACTIVE_SHELL_MAX_LINES } from '../../constants.js'; -import { - calculateToolContentMaxLines, - TOOL_RESULT_MIN_LINES_SHOWN, -} from '../../utils/toolLayoutUtils.js'; +import { calculateToolContentMaxLines } from '../../utils/toolLayoutUtils.js'; import { SubagentProgressDisplay } from './SubagentProgressDisplay.js'; // Large threshold to ensure we don't cause performance issues for very large @@ -64,11 +61,6 @@ export const ToolResultDisplay: React.FC = ({ maxLinesLimit: maxLines, }); - const effectiveMaxHeight = - availableHeight !== undefined - ? Math.max(TOOL_RESULT_MIN_LINES_SHOWN, availableHeight) - : undefined; - const combinedPaddingAndBorderWidth = 4; const childWidth = terminalWidth - combinedPaddingAndBorderWidth; @@ -140,7 +132,7 @@ export const ToolResultDisplay: React.FC = ({ if (isAlternateBuffer && Array.isArray(truncatedResultDisplay)) { // If availableHeight is undefined, fallback to a safe default to prevents infinite loop // where Container grows -> List renders more -> Container grows. - const limit = maxLines ?? effectiveMaxHeight ?? ACTIVE_SHELL_MAX_LINES; + const limit = maxLines ?? availableHeight ?? ACTIVE_SHELL_MAX_LINES; const listHeight = Math.min( // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion (truncatedResultDisplay as AnsiOutput).length, @@ -213,7 +205,7 @@ export const ToolResultDisplay: React.FC = ({ diffContent={(truncatedResultDisplay as FileDiffResult).fileDiff} // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion filename={(truncatedResultDisplay as FileDiffResult).fileName} - availableTerminalHeight={effectiveMaxHeight} + availableTerminalHeight={availableHeight} terminalWidth={childWidth} /> ); @@ -227,7 +219,7 @@ export const ToolResultDisplay: React.FC = ({ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion data={truncatedResultDisplay as AnsiOutput} availableTerminalHeight={ - isAlternateBuffer ? undefined : effectiveMaxHeight + isAlternateBuffer ? undefined : availableHeight } width={childWidth} maxLines={isAlternateBuffer ? undefined : maxLines} @@ -241,7 +233,7 @@ export const ToolResultDisplay: React.FC = ({ return ( @@ -253,7 +245,7 @@ export const ToolResultDisplay: React.FC = ({ return ( diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ShellToolMessage.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ShellToolMessage.test.tsx.snap index 9d636ab1c4b..23aae9c40a5 100644 --- a/packages/cli/src/ui/components/messages/__snapshots__/ShellToolMessage.test.tsx.snap +++ b/packages/cli/src/ui/components/messages/__snapshots__/ShellToolMessage.test.tsx.snap @@ -133,6 +133,13 @@ exports[` > Height Constraints > respects availableTerminalH "╭──────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command A shell command │ │ │ +│ Line 91 │ +│ Line 92 │ +│ Line 93 │ +│ Line 94 │ +│ Line 95 │ +│ Line 96 │ +│ Line 97 │ │ Line 98 │ │ Line 99 │ │ Line 100 █ │ @@ -187,99 +194,106 @@ exports[` > Height Constraints > uses full availableTerminal "╭──────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command A shell command (Shift+Tab to unfocus) │ │ │ +│ Line 1 │ +│ Line 2 │ +│ Line 3 │ +│ Line 4 │ +│ Line 5 │ +│ Line 6 │ +│ Line 7 │ │ Line 8 │ │ Line 9 │ │ Line 10 │ │ Line 11 │ │ Line 12 │ │ Line 13 │ -│ Line 14 ▄ │ -│ Line 15 █ │ -│ Line 16 █ │ -│ Line 17 █ │ -│ Line 18 █ │ -│ Line 19 █ │ -│ Line 20 █ │ -│ Line 21 █ │ -│ Line 22 █ │ -│ Line 23 █ │ -│ Line 24 █ │ -│ Line 25 █ │ -│ Line 26 █ │ -│ Line 27 █ │ -│ Line 28 █ │ -│ Line 29 █ │ -│ Line 30 █ │ -│ Line 31 █ │ -│ Line 32 █ │ -│ Line 33 █ │ -│ Line 34 █ │ -│ Line 35 █ │ -│ Line 36 █ │ -│ Line 37 █ │ -│ Line 38 █ │ -│ Line 39 █ │ -│ Line 40 █ │ -│ Line 41 █ │ -│ Line 42 █ │ -│ Line 43 █ │ -│ Line 44 █ │ -│ Line 45 █ │ -│ Line 46 █ │ -│ Line 47 █ │ -│ Line 48 █ │ -│ Line 49 █ │ -│ Line 50 █ │ -│ Line 51 █ │ -│ Line 52 █ │ -│ Line 53 █ │ -│ Line 54 █ │ -│ Line 55 █ │ -│ Line 56 █ │ -│ Line 57 █ │ -│ Line 58 █ │ -│ Line 59 █ │ -│ Line 60 █ │ -│ Line 61 █ │ -│ Line 62 █ │ -│ Line 63 █ │ -│ Line 64 █ │ -│ Line 65 █ │ -│ Line 66 █ │ -│ Line 67 █ │ -│ Line 68 █ │ -│ Line 69 █ │ -│ Line 70 █ │ -│ Line 71 █ │ -│ Line 72 █ │ -│ Line 73 █ │ -│ Line 74 █ │ -│ Line 75 █ │ -│ Line 76 █ │ -│ Line 77 █ │ -│ Line 78 █ │ -│ Line 79 █ │ -│ Line 80 █ │ -│ Line 81 █ │ -│ Line 82 █ │ -│ Line 83 █ │ -│ Line 84 █ │ -│ Line 85 █ │ -│ Line 86 █ │ -│ Line 87 █ │ -│ Line 88 █ │ -│ Line 89 █ │ -│ Line 90 █ │ -│ Line 91 █ │ -│ Line 92 █ │ -│ Line 93 █ │ -│ Line 94 █ │ -│ Line 95 █ │ -│ Line 96 █ │ -│ Line 97 █ │ -│ Line 98 █ │ -│ Line 99 █ │ -│ Line 100 █ │ +│ Line 14 │ +│ Line 15 │ +│ Line 16 │ +│ Line 17 │ +│ Line 18 │ +│ Line 19 │ +│ Line 20 │ +│ Line 21 │ +│ Line 22 │ +│ Line 23 │ +│ Line 24 │ +│ Line 25 │ +│ Line 26 │ +│ Line 27 │ +│ Line 28 │ +│ Line 29 │ +│ Line 30 │ +│ Line 31 │ +│ Line 32 │ +│ Line 33 │ +│ Line 34 │ +│ Line 35 │ +│ Line 36 │ +│ Line 37 │ +│ Line 38 │ +│ Line 39 │ +│ Line 40 │ +│ Line 41 │ +│ Line 42 │ +│ Line 43 │ +│ Line 44 │ +│ Line 45 │ +│ Line 46 │ +│ Line 47 │ +│ Line 48 │ +│ Line 49 │ +│ Line 50 │ +│ Line 51 │ +│ Line 52 │ +│ Line 53 │ +│ Line 54 │ +│ Line 55 │ +│ Line 56 │ +│ Line 57 │ +│ Line 58 │ +│ Line 59 │ +│ Line 60 │ +│ Line 61 │ +│ Line 62 │ +│ Line 63 │ +│ Line 64 │ +│ Line 65 │ +│ Line 66 │ +│ Line 67 │ +│ Line 68 │ +│ Line 69 │ +│ Line 70 │ +│ Line 71 │ +│ Line 72 │ +│ Line 73 │ +│ Line 74 │ +│ Line 75 │ +│ Line 76 │ +│ Line 77 │ +│ Line 78 │ +│ Line 79 │ +│ Line 80 │ +│ Line 81 │ +│ Line 82 │ +│ Line 83 │ +│ Line 84 │ +│ Line 85 │ +│ Line 86 │ +│ Line 87 │ +│ Line 88 │ +│ Line 89 │ +│ Line 90 │ +│ Line 91 │ +│ Line 92 │ +│ Line 93 │ +│ Line 94 │ +│ Line 95 │ +│ Line 96 │ +│ Line 97 │ +│ Line 98 │ +│ Line 99 │ +│ Line 100 │ " `; diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap index 5e5c7ea2b06..292a0093b26 100644 --- a/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap +++ b/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap @@ -37,7 +37,10 @@ exports[`ToolResultDisplay > renders string result as plain text when renderOutp `; exports[`ToolResultDisplay > truncates very long string results 1`] = ` -"... 248 hidden (Ctrl+O) ... +"... 245 hidden (Ctrl+O) ... +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.ts b/packages/cli/src/ui/utils/toolLayoutUtils.ts index 26a10773d4f..a99bd8a7b0d 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.ts @@ -33,17 +33,10 @@ export function calculateToolContentMaxLines(options: { isAlternateBuffer: boolean; maxLinesLimit?: number; }): number | undefined { - const { availableTerminalHeight, isAlternateBuffer, maxLinesLimit } = options; - - const reservedLines = isAlternateBuffer - ? TOOL_RESULT_ASB_RESERVED_LINE_COUNT - : TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT; + const { availableTerminalHeight, maxLinesLimit } = options; let contentHeight = availableTerminalHeight - ? Math.max( - 0, - availableTerminalHeight - TOOL_RESULT_STATIC_HEIGHT - reservedLines, - ) + ? Math.max(TOOL_RESULT_STATIC_HEIGHT, availableTerminalHeight) : undefined; if (maxLinesLimit) { @@ -91,14 +84,7 @@ export function calculateShellMaxLines(options: { return isAlternateBuffer ? ACTIVE_SHELL_MAX_LINES : undefined; } - const reservedLines = isAlternateBuffer - ? TOOL_RESULT_ASB_RESERVED_LINE_COUNT - : TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT; - - const maxLinesBasedOnHeight = Math.max( - 0, - availableTerminalHeight - TOOL_RESULT_STATIC_HEIGHT - reservedLines, - ); + const maxLinesBasedOnHeight = Math.max(1, availableTerminalHeight); // 3. Handle ASB mode focus expansion. // We allow a focused shell in ASB mode to take up the full available height, From 558f1c96c7163a0f4d29cce5a76026f7cd7703eb Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Thu, 12 Mar 2026 14:27:32 -0500 Subject: [PATCH 06/12] Addressed case with 0 terminal height --- packages/cli/src/ui/components/AnsiOutput.tsx | 6 ++- .../components/messages/ToolResultDisplay.tsx | 8 ++- .../cli/src/ui/utils/toolLayoutUtils.test.ts | 53 +++++++------------ packages/cli/src/ui/utils/toolLayoutUtils.ts | 10 ++-- 4 files changed, 36 insertions(+), 41 deletions(-) diff --git a/packages/cli/src/ui/components/AnsiOutput.tsx b/packages/cli/src/ui/components/AnsiOutput.tsx index cc17b6b6b0c..a1b30b08569 100644 --- a/packages/cli/src/ui/components/AnsiOutput.tsx +++ b/packages/cli/src/ui/components/AnsiOutput.tsx @@ -35,7 +35,11 @@ export const AnsiOutputText: React.FC = ({ ? Math.min(availableHeightLimit, maxLines) : (availableHeightLimit ?? maxLines ?? DEFAULT_HEIGHT); - const lastLines = disableTruncation ? data : data.slice(-numLinesRetained); + const lastLines = disableTruncation + ? data + : numLinesRetained === 0 + ? [] + : data.slice(-numLinesRetained); return ( {lastLines.map((line: AnsiLine, lineIndex: number) => ( diff --git a/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx b/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx index 1c29407e91a..bc382471bae 100644 --- a/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx +++ b/packages/cli/src/ui/components/messages/ToolResultDisplay.tsx @@ -87,7 +87,7 @@ export const ToolResultDisplay: React.FC = ({ if (text.length > MAXIMUM_RESULT_DISPLAY_CHARACTERS) { text = '...' + text.slice(-MAXIMUM_RESULT_DISPLAY_CHARACTERS); } - if (maxLines) { + if (maxLines !== undefined) { const hasTrailingNewline = text.endsWith('\n'); const contentText = hasTrailingNewline ? text.slice(0, -1) : text; const lines = contentText.split('\n'); @@ -103,7 +103,11 @@ export const ToolResultDisplay: React.FC = ({ return { truncatedResultDisplay: text, hiddenLinesCount: hiddenLines }; } - if (Array.isArray(resultDisplay) && !isAlternateBuffer && maxLines) { + if ( + Array.isArray(resultDisplay) && + !isAlternateBuffer && + maxLines !== undefined + ) { if (resultDisplay.length > maxLines) { // We will have a label from MaxSizedBox. Reserve space for it. const targetLines = Math.max(1, maxLines - 1); diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.test.ts b/packages/cli/src/ui/utils/toolLayoutUtils.test.ts index d8c74dd31ad..b0c0a549160 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.test.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.test.ts @@ -8,8 +8,6 @@ import { describe, it, expect } from 'vitest'; import { calculateToolContentMaxLines, calculateShellMaxLines, - TOOL_RESULT_STATIC_HEIGHT, - TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT, } from './toolLayoutUtils.js'; import { CoreToolCallStatus } from '@google/gemini-cli-core'; import { @@ -36,26 +34,26 @@ describe('toolLayoutUtils', () => { expect(result).toBe(10); }); - it('caps height to prevent overflow in constrained terminal (Standard mode)', () => { + it('returns available space directly in constrained terminal (Standard mode)', () => { const availableTerminalHeight = 2; // Very small const result = calculateToolContentMaxLines({ availableTerminalHeight, isAlternateBuffer: false, }); - // Math.max(0, 2 - 1 - 2) = 0 - expect(result).toBe(0); + // Math.max(0, 2) = 2 + expect(result).toBe(2); }); - it('caps height to prevent overflow in constrained terminal (ASB mode)', () => { + it('returns available space directly in constrained terminal (ASB mode)', () => { const availableTerminalHeight = 4; // Very small const result = calculateToolContentMaxLines({ availableTerminalHeight, isAlternateBuffer: true, }); - // Math.max(0, 4 - 1 - 6) = 0 - expect(result).toBe(0); + // Math.max(0, 4) = 4 + expect(result).toBe(4); }); it('returns remaining space if sufficient space exists (Standard mode)', () => { @@ -65,8 +63,8 @@ describe('toolLayoutUtils', () => { isAlternateBuffer: false, }); - // Space remaining is 20 - 1 - 2 = 17 - expect(result).toBe(17); + // Math.max(0, 20) = 20 + expect(result).toBe(20); }); it('returns remaining space if sufficient space exists (ASB mode)', () => { @@ -76,19 +74,8 @@ describe('toolLayoutUtils', () => { isAlternateBuffer: true, }); - // Space remaining is 20 - 1 - 6 = 13 - expect(result).toBe(13); - }); - - it('returns 0 if availableTerminalHeight is <= TOOL_RESULT_STATIC_HEIGHT + reservedLines', () => { - const result = calculateToolContentMaxLines({ - availableTerminalHeight: - TOOL_RESULT_STATIC_HEIGHT + TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT, - isAlternateBuffer: false, - }); - - // Cap at 3 - 1 - 2 = 0 - expect(result).toBe(0); + // Math.max(0, 20) = 20 + expect(result).toBe(20); }); }); @@ -129,32 +116,32 @@ describe('toolLayoutUtils', () => { expect(result).toBeUndefined(); }); - it('handles small availableTerminalHeight gracefully to prevent overflow in Standard mode', () => { + it('handles small availableTerminalHeight gracefully without overflow in Standard mode', () => { const result = calculateShellMaxLines({ status: CoreToolCallStatus.Executing, isAlternateBuffer: false, isThisShellFocused: false, - availableTerminalHeight: 2, // Too small to subtract 1 + 2 + availableTerminalHeight: 2, constrainHeight: true, isExpandable: false, }); - // Math.max(0, 2 - 1 - 2) = 0 - expect(result).toBe(0); + // Math.max(0, 2) = 2 + expect(result).toBe(2); }); - it('handles small availableTerminalHeight gracefully to prevent overflow in ASB mode', () => { + it('handles small availableTerminalHeight gracefully without overflow in ASB mode', () => { const result = calculateShellMaxLines({ status: CoreToolCallStatus.Executing, isAlternateBuffer: true, isThisShellFocused: false, - availableTerminalHeight: 6, // Too small to subtract 1 + 6 + availableTerminalHeight: 6, constrainHeight: true, isExpandable: false, }); - // Math.max(0, 6 - 1 - 6) = 0 - expect(result).toBe(0); + // Math.max(0, 6) = 6 + expect(result).toBe(6); }); it('handles negative availableTerminalHeight gracefully', () => { @@ -180,8 +167,8 @@ describe('toolLayoutUtils', () => { isExpandable: false, }); - // 30 - 1 (static) - 6 (ASB reserved) = 23 - expect(result).toBe(23); + // 30 + expect(result).toBe(30); }); it('falls back to COMPLETED_SHELL_MAX_LINES for completed shells if space allows', () => { diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.ts b/packages/cli/src/ui/utils/toolLayoutUtils.ts index a99bd8a7b0d..c6498ba7f8e 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.ts @@ -15,7 +15,6 @@ import { CoreToolCallStatus } from '@google/gemini-cli-core'; * These MUST be kept in sync between ToolGroupMessage (for overflow detection) * and ToolResultDisplay (for actual truncation). */ -export const TOOL_RESULT_STATIC_HEIGHT = 1; export const TOOL_RESULT_ASB_RESERVED_LINE_COUNT = 6; export const TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT = 2; export const TOOL_RESULT_MIN_LINES_SHOWN = 2; @@ -35,9 +34,10 @@ export function calculateToolContentMaxLines(options: { }): number | undefined { const { availableTerminalHeight, maxLinesLimit } = options; - let contentHeight = availableTerminalHeight - ? Math.max(TOOL_RESULT_STATIC_HEIGHT, availableTerminalHeight) - : undefined; + let contentHeight = + availableTerminalHeight !== undefined + ? Math.max(0, availableTerminalHeight) + : undefined; if (maxLinesLimit) { contentHeight = @@ -84,7 +84,7 @@ export function calculateShellMaxLines(options: { return isAlternateBuffer ? ACTIVE_SHELL_MAX_LINES : undefined; } - const maxLinesBasedOnHeight = Math.max(1, availableTerminalHeight); + const maxLinesBasedOnHeight = Math.max(0, availableTerminalHeight); // 3. Handle ASB mode focus expansion. // We allow a focused shell in ASB mode to take up the full available height, From 4c09d08187285b8ed93e1720ef63338d5a958dae Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Thu, 12 Mar 2026 15:53:13 -0500 Subject: [PATCH 07/12] Addressed issues with toolLayoutUtils --- .../__snapshots__/MainContent.test.tsx.snap | 31 +-- .../messages/ShellToolMessage.test.tsx | 4 +- .../ShellToolMessage.test.tsx.snap | 196 +++++++++--------- .../ToolResultDisplay.test.tsx.snap | 4 +- .../cli/src/ui/utils/toolLayoutUtils.test.ts | 41 ++-- packages/cli/src/ui/utils/toolLayoutUtils.ts | 12 +- 6 files changed, 140 insertions(+), 148 deletions(-) diff --git a/packages/cli/src/ui/components/__snapshots__/MainContent.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/MainContent.test.tsx.snap index 6af974bb89f..785dc6b6f0e 100644 --- a/packages/cli/src/ui/components/__snapshots__/MainContent.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/MainContent.test.tsx.snap @@ -6,14 +6,11 @@ AppHeader(full) ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command Running a long command... │ │ │ -│ Line 6 │ -│ Line 7 │ -│ Line 8 │ -│ Line 9 ▄ │ -│ Line 10 █ │ -│ Line 11 █ │ -│ Line 12 █ │ -│ Line 13 █ │ +│ Line 9 │ +│ Line 10 │ +│ Line 11 │ +│ Line 12 │ +│ Line 13 │ │ Line 14 █ │ │ Line 15 █ │ │ Line 16 █ │ @@ -31,14 +28,11 @@ AppHeader(full) ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command Running a long command... │ │ │ -│ Line 6 │ -│ Line 7 │ -│ Line 8 │ -│ Line 9 ▄ │ -│ Line 10 █ │ -│ Line 11 █ │ -│ Line 12 █ │ -│ Line 13 █ │ +│ Line 9 │ +│ Line 10 │ +│ Line 11 │ +│ Line 12 │ +│ Line 13 │ │ Line 14 █ │ │ Line 15 █ │ │ Line 16 █ │ @@ -55,10 +49,7 @@ exports[`MainContent > MainContent Tool Output Height Logic > 'Normal mode - Con ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command Running a long command... │ │ │ -│ ... first 6 lines hidden (Ctrl+O to show) ... │ -│ Line 7 │ -│ Line 8 │ -│ Line 9 │ +│ ... first 9 lines hidden (Ctrl+O to show) ... │ │ Line 10 │ │ Line 11 │ │ Line 12 │ diff --git a/packages/cli/src/ui/components/messages/ShellToolMessage.test.tsx b/packages/cli/src/ui/components/messages/ShellToolMessage.test.tsx index 7607f9e4b11..061b8baeaf9 100644 --- a/packages/cli/src/ui/components/messages/ShellToolMessage.test.tsx +++ b/packages/cli/src/ui/components/messages/ShellToolMessage.test.tsx @@ -189,7 +189,7 @@ describe('', () => { [ 'respects availableTerminalHeight when it is smaller than ACTIVE_SHELL_MAX_LINES', 10, - 10, + 8, false, true, ], @@ -203,7 +203,7 @@ describe('', () => { [ 'uses full availableTerminalHeight when focused in alternate buffer mode', 100, - 100, + 98, true, false, ], diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ShellToolMessage.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ShellToolMessage.test.tsx.snap index b45753d6d0d..1847b8ce679 100644 --- a/packages/cli/src/ui/components/messages/__snapshots__/ShellToolMessage.test.tsx.snap +++ b/packages/cli/src/ui/components/messages/__snapshots__/ShellToolMessage.test.tsx.snap @@ -130,8 +130,6 @@ exports[` > Height Constraints > respects availableTerminalH "╭──────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command A shell command │ │ │ -│ Line 91 │ -│ Line 92 │ │ Line 93 │ │ Line 94 │ │ Line 95 │ @@ -185,106 +183,104 @@ exports[` > Height Constraints > uses full availableTerminal "╭──────────────────────────────────────────────────────────────────────────────╮ │ ⊶ Shell Command A shell command (Shift+Tab to unfocus) │ │ │ -│ Line 1 │ -│ Line 2 │ │ Line 3 │ │ Line 4 │ -│ Line 5 │ -│ Line 6 │ -│ Line 7 │ -│ Line 8 │ -│ Line 9 │ -│ Line 10 │ -│ Line 11 │ -│ Line 12 │ -│ Line 13 │ -│ Line 14 │ -│ Line 15 │ -│ Line 16 │ -│ Line 17 │ -│ Line 18 │ -│ Line 19 │ -│ Line 20 │ -│ Line 21 │ -│ Line 22 │ -│ Line 23 │ -│ Line 24 │ -│ Line 25 │ -│ Line 26 │ -│ Line 27 │ -│ Line 28 │ -│ Line 29 │ -│ Line 30 │ -│ Line 31 │ -│ Line 32 │ -│ Line 33 │ -│ Line 34 │ -│ Line 35 │ -│ Line 36 │ -│ Line 37 │ -│ Line 38 │ -│ Line 39 │ -│ Line 40 │ -│ Line 41 │ -│ Line 42 │ -│ Line 43 │ -│ Line 44 │ -│ Line 45 │ -│ Line 46 │ -│ Line 47 │ -│ Line 48 │ -│ Line 49 │ -│ Line 50 │ -│ Line 51 │ -│ Line 52 │ -│ Line 53 │ -│ Line 54 │ -│ Line 55 │ -│ Line 56 │ -│ Line 57 │ -│ Line 58 │ -│ Line 59 │ -│ Line 60 │ -│ Line 61 │ -│ Line 62 │ -│ Line 63 │ -│ Line 64 │ -│ Line 65 │ -│ Line 66 │ -│ Line 67 │ -│ Line 68 │ -│ Line 69 │ -│ Line 70 │ -│ Line 71 │ -│ Line 72 │ -│ Line 73 │ -│ Line 74 │ -│ Line 75 │ -│ Line 76 │ -│ Line 77 │ -│ Line 78 │ -│ Line 79 │ -│ Line 80 │ -│ Line 81 │ -│ Line 82 │ -│ Line 83 │ -│ Line 84 │ -│ Line 85 │ -│ Line 86 │ -│ Line 87 │ -│ Line 88 │ -│ Line 89 │ -│ Line 90 │ -│ Line 91 │ -│ Line 92 │ -│ Line 93 │ -│ Line 94 │ -│ Line 95 │ -│ Line 96 │ -│ Line 97 │ -│ Line 98 │ -│ Line 99 │ -│ Line 100 │ +│ Line 5 █ │ +│ Line 6 █ │ +│ Line 7 █ │ +│ Line 8 █ │ +│ Line 9 █ │ +│ Line 10 █ │ +│ Line 11 █ │ +│ Line 12 █ │ +│ Line 13 █ │ +│ Line 14 █ │ +│ Line 15 █ │ +│ Line 16 █ │ +│ Line 17 █ │ +│ Line 18 █ │ +│ Line 19 █ │ +│ Line 20 █ │ +│ Line 21 █ │ +│ Line 22 █ │ +│ Line 23 █ │ +│ Line 24 █ │ +│ Line 25 █ │ +│ Line 26 █ │ +│ Line 27 █ │ +│ Line 28 █ │ +│ Line 29 █ │ +│ Line 30 █ │ +│ Line 31 █ │ +│ Line 32 █ │ +│ Line 33 █ │ +│ Line 34 █ │ +│ Line 35 █ │ +│ Line 36 █ │ +│ Line 37 █ │ +│ Line 38 █ │ +│ Line 39 █ │ +│ Line 40 █ │ +│ Line 41 █ │ +│ Line 42 █ │ +│ Line 43 █ │ +│ Line 44 █ │ +│ Line 45 █ │ +│ Line 46 █ │ +│ Line 47 █ │ +│ Line 48 █ │ +│ Line 49 █ │ +│ Line 50 █ │ +│ Line 51 █ │ +│ Line 52 █ │ +│ Line 53 █ │ +│ Line 54 █ │ +│ Line 55 █ │ +│ Line 56 █ │ +│ Line 57 █ │ +│ Line 58 █ │ +│ Line 59 █ │ +│ Line 60 █ │ +│ Line 61 █ │ +│ Line 62 █ │ +│ Line 63 █ │ +│ Line 64 █ │ +│ Line 65 █ │ +│ Line 66 █ │ +│ Line 67 █ │ +│ Line 68 █ │ +│ Line 69 █ │ +│ Line 70 █ │ +│ Line 71 █ │ +│ Line 72 █ │ +│ Line 73 █ │ +│ Line 74 █ │ +│ Line 75 █ │ +│ Line 76 █ │ +│ Line 77 █ │ +│ Line 78 █ │ +│ Line 79 █ │ +│ Line 80 █ │ +│ Line 81 █ │ +│ Line 82 █ │ +│ Line 83 █ │ +│ Line 84 █ │ +│ Line 85 █ │ +│ Line 86 █ │ +│ Line 87 █ │ +│ Line 88 █ │ +│ Line 89 █ │ +│ Line 90 █ │ +│ Line 91 █ │ +│ Line 92 █ │ +│ Line 93 █ │ +│ Line 94 █ │ +│ Line 95 █ │ +│ Line 96 █ │ +│ Line 97 █ │ +│ Line 98 █ │ +│ Line 99 █ │ +│ Line 100 █ │ " `; diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap index 292a0093b26..311492591e2 100644 --- a/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap +++ b/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap @@ -37,9 +37,7 @@ exports[`ToolResultDisplay > renders string result as plain text when renderOutp `; exports[`ToolResultDisplay > truncates very long string results 1`] = ` -"... 245 hidden (Ctrl+O) ... -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"... 247 hidden (Ctrl+O) ... aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.test.ts b/packages/cli/src/ui/utils/toolLayoutUtils.test.ts index b0c0a549160..e93b5e56d01 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.test.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.test.ts @@ -8,6 +8,7 @@ import { describe, it, expect } from 'vitest'; import { calculateToolContentMaxLines, calculateShellMaxLines, + SHELL_CONTENT_OVERHEAD, } from './toolLayoutUtils.js'; import { CoreToolCallStatus } from '@google/gemini-cli-core'; import { @@ -41,8 +42,8 @@ describe('toolLayoutUtils', () => { isAlternateBuffer: false, }); - // Math.max(0, 2) = 2 - expect(result).toBe(2); + // Math.max(0, 2 - 2) = 0 + expect(result).toBe(0); }); it('returns available space directly in constrained terminal (ASB mode)', () => { @@ -52,8 +53,8 @@ describe('toolLayoutUtils', () => { isAlternateBuffer: true, }); - // Math.max(0, 4) = 4 - expect(result).toBe(4); + // Math.max(0, 4 - 2) = 2 + expect(result).toBe(2); }); it('returns remaining space if sufficient space exists (Standard mode)', () => { @@ -63,8 +64,8 @@ describe('toolLayoutUtils', () => { isAlternateBuffer: false, }); - // Math.max(0, 20) = 20 - expect(result).toBe(20); + // Math.max(0, 20 - 2) = 18 + expect(result).toBe(18); }); it('returns remaining space if sufficient space exists (ASB mode)', () => { @@ -74,8 +75,8 @@ describe('toolLayoutUtils', () => { isAlternateBuffer: true, }); - // Math.max(0, 20) = 20 - expect(result).toBe(20); + // Math.max(0, 20 - 2) = 18 + expect(result).toBe(18); }); }); @@ -92,7 +93,7 @@ describe('toolLayoutUtils', () => { expect(result).toBeUndefined(); }); - it('returns ACTIVE_SHELL_MAX_LINES for ASB mode when availableTerminalHeight is undefined', () => { + it('returns ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD for ASB mode when availableTerminalHeight is undefined', () => { const result = calculateShellMaxLines({ status: CoreToolCallStatus.Executing, isAlternateBuffer: true, @@ -101,7 +102,7 @@ describe('toolLayoutUtils', () => { constrainHeight: true, isExpandable: false, }); - expect(result).toBe(ACTIVE_SHELL_MAX_LINES); + expect(result).toBe(ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD); }); it('returns undefined for Standard mode when availableTerminalHeight is undefined', () => { @@ -126,8 +127,8 @@ describe('toolLayoutUtils', () => { isExpandable: false, }); - // Math.max(0, 2) = 2 - expect(result).toBe(2); + // Math.max(0, 2 - 2) = 0 + expect(result).toBe(0); }); it('handles small availableTerminalHeight gracefully without overflow in ASB mode', () => { @@ -140,8 +141,8 @@ describe('toolLayoutUtils', () => { isExpandable: false, }); - // Math.max(0, 6) = 6 - expect(result).toBe(6); + // Math.max(0, 6 - 2) = 4 + expect(result).toBe(4); }); it('handles negative availableTerminalHeight gracefully', () => { @@ -167,11 +168,11 @@ describe('toolLayoutUtils', () => { isExpandable: false, }); - // 30 - expect(result).toBe(30); + // 30 - 2 = 28 + expect(result).toBe(28); }); - it('falls back to COMPLETED_SHELL_MAX_LINES for completed shells if space allows', () => { + it('falls back to COMPLETED_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD for completed shells if space allows', () => { const result = calculateShellMaxLines({ status: CoreToolCallStatus.Success, isAlternateBuffer: false, @@ -181,10 +182,10 @@ describe('toolLayoutUtils', () => { isExpandable: false, }); - expect(result).toBe(COMPLETED_SHELL_MAX_LINES); + expect(result).toBe(COMPLETED_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD); }); - it('falls back to ACTIVE_SHELL_MAX_LINES for executing shells if space allows', () => { + it('falls back to ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD for executing shells if space allows', () => { const result = calculateShellMaxLines({ status: CoreToolCallStatus.Executing, isAlternateBuffer: false, @@ -194,7 +195,7 @@ describe('toolLayoutUtils', () => { isExpandable: false, }); - expect(result).toBe(ACTIVE_SHELL_MAX_LINES); + expect(result).toBe(ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD); }); }); }); diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.ts b/packages/cli/src/ui/utils/toolLayoutUtils.ts index c254734bdb8..398eca6f164 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.ts @@ -15,7 +15,7 @@ import { CoreToolCallStatus } from '@google/gemini-cli-core'; * These MUST be kept in sync between ToolGroupMessage (for overflow detection) * and ToolResultDisplay (for actual truncation). */ -export const TOOL_RESULT_ASB_RESERVED_LINE_COUNT = 6; +export const TOOL_RESULT_STATIC_HEIGHT = 1; export const TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT = 2; export const TOOL_RESULT_MIN_LINES_SHOWN = 2; @@ -43,7 +43,10 @@ export function calculateToolContentMaxLines(options: { let contentHeight = availableTerminalHeight !== undefined - ? Math.max(0, availableTerminalHeight) + ? Math.max( + 0, + availableTerminalHeight - TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT, + ) : undefined; if (maxLinesLimit !== undefined) { @@ -93,7 +96,10 @@ export function calculateShellMaxLines(options: { : undefined; } - const maxLinesBasedOnHeight = Math.max(0, availableTerminalHeight); + const maxLinesBasedOnHeight = Math.max( + 0, + availableTerminalHeight - TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT, + ); // 3. Handle ASB mode focus expansion. // We allow a focused shell in ASB mode to take up the full available height, From d21a6866400f79b8f655240117bf830d40d446cf Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Thu, 12 Mar 2026 16:53:41 -0500 Subject: [PATCH 08/12] Addressed nit improvements --- .../components/shared/SlicingMaxSizedBox.tsx | 4 +- .../cli/src/ui/utils/toolLayoutUtils.test.ts | 355 +++++++++--------- 2 files changed, 183 insertions(+), 176 deletions(-) diff --git a/packages/cli/src/ui/components/shared/SlicingMaxSizedBox.tsx b/packages/cli/src/ui/components/shared/SlicingMaxSizedBox.tsx index b756c40ee2b..f8f851aed36 100644 --- a/packages/cli/src/ui/components/shared/SlicingMaxSizedBox.tsx +++ b/packages/cli/src/ui/components/shared/SlicingMaxSizedBox.tsx @@ -46,7 +46,7 @@ export function SlicingMaxSizedBox({ text = '...' + text.slice(-MAXIMUM_RESULT_DISPLAY_CHARACTERS); } } - if (maxLines) { + if (maxLines !== undefined) { const hasTrailingNewline = text.endsWith('\n'); const contentText = hasTrailingNewline ? text.slice(0, -1) : text; const lines = contentText.split('\n'); @@ -71,7 +71,7 @@ export function SlicingMaxSizedBox({ }; } - if (Array.isArray(data) && !isAlternateBuffer && maxLines) { + if (Array.isArray(data) && !isAlternateBuffer && maxLines !== undefined) { if (data.length > maxLines) { // We will have a label from MaxSizedBox. Reserve space for it. const targetLines = Math.max(1, maxLines - 1); diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.test.ts b/packages/cli/src/ui/utils/toolLayoutUtils.test.ts index e93b5e56d01..35f5fb28e65 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.test.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.test.ts @@ -18,184 +18,191 @@ import { describe('toolLayoutUtils', () => { describe('calculateToolContentMaxLines', () => { - it('returns undefined if availableTerminalHeight is undefined', () => { - const result = calculateToolContentMaxLines({ - availableTerminalHeight: undefined, - isAlternateBuffer: false, - }); - expect(result).toBeUndefined(); - }); - - it('returns maxLinesLimit if maxLinesLimit applies but availableTerminalHeight is undefined', () => { - const result = calculateToolContentMaxLines({ - availableTerminalHeight: undefined, - isAlternateBuffer: false, - maxLinesLimit: 10, - }); - expect(result).toBe(10); - }); - - it('returns available space directly in constrained terminal (Standard mode)', () => { - const availableTerminalHeight = 2; // Very small - const result = calculateToolContentMaxLines({ - availableTerminalHeight, - isAlternateBuffer: false, - }); - - // Math.max(0, 2 - 2) = 0 - expect(result).toBe(0); - }); - - it('returns available space directly in constrained terminal (ASB mode)', () => { - const availableTerminalHeight = 4; // Very small - const result = calculateToolContentMaxLines({ - availableTerminalHeight, - isAlternateBuffer: true, - }); - - // Math.max(0, 4 - 2) = 2 - expect(result).toBe(2); - }); - - it('returns remaining space if sufficient space exists (Standard mode)', () => { - const availableTerminalHeight = 20; - const result = calculateToolContentMaxLines({ - availableTerminalHeight, - isAlternateBuffer: false, - }); - - // Math.max(0, 20 - 2) = 18 - expect(result).toBe(18); - }); - - it('returns remaining space if sufficient space exists (ASB mode)', () => { - const availableTerminalHeight = 20; - const result = calculateToolContentMaxLines({ - availableTerminalHeight, - isAlternateBuffer: true, - }); - - // Math.max(0, 20 - 2) = 18 - expect(result).toBe(18); + interface CalculateToolContentMaxLinesTestCase { + desc: string; + options: Parameters[0]; + expected: number | undefined; + } + + const testCases: CalculateToolContentMaxLinesTestCase[] = [ + { + desc: 'returns undefined if availableTerminalHeight is undefined', + options: { + availableTerminalHeight: undefined, + isAlternateBuffer: false, + }, + expected: undefined, + }, + { + desc: 'returns maxLinesLimit if maxLinesLimit applies but availableTerminalHeight is undefined', + options: { + availableTerminalHeight: undefined, + isAlternateBuffer: false, + maxLinesLimit: 10, + }, + expected: 10, + }, + { + desc: 'returns available space directly in constrained terminal (Standard mode)', + options: { + availableTerminalHeight: 2, + isAlternateBuffer: false, + }, + expected: 0, + }, + { + desc: 'returns available space directly in constrained terminal (ASB mode)', + options: { + availableTerminalHeight: 4, + isAlternateBuffer: true, + }, + expected: 2, + }, + { + desc: 'returns remaining space if sufficient space exists (Standard mode)', + options: { + availableTerminalHeight: 20, + isAlternateBuffer: false, + }, + expected: 18, + }, + { + desc: 'returns remaining space if sufficient space exists (ASB mode)', + options: { + availableTerminalHeight: 20, + isAlternateBuffer: true, + }, + expected: 18, + }, + ]; + + it.each(testCases)('$desc', ({ options, expected }) => { + const result = calculateToolContentMaxLines(options); + expect(result).toBe(expected); }); }); describe('calculateShellMaxLines', () => { - it('returns undefined when not constrained and is expandable', () => { - const result = calculateShellMaxLines({ - status: CoreToolCallStatus.Executing, - isAlternateBuffer: false, - isThisShellFocused: false, - availableTerminalHeight: 20, - constrainHeight: false, - isExpandable: true, - }); - expect(result).toBeUndefined(); - }); - - it('returns ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD for ASB mode when availableTerminalHeight is undefined', () => { - const result = calculateShellMaxLines({ - status: CoreToolCallStatus.Executing, - isAlternateBuffer: true, - isThisShellFocused: false, - availableTerminalHeight: undefined, - constrainHeight: true, - isExpandable: false, - }); - expect(result).toBe(ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD); - }); - - it('returns undefined for Standard mode when availableTerminalHeight is undefined', () => { - const result = calculateShellMaxLines({ - status: CoreToolCallStatus.Executing, - isAlternateBuffer: false, - isThisShellFocused: false, - availableTerminalHeight: undefined, - constrainHeight: true, - isExpandable: false, - }); - expect(result).toBeUndefined(); - }); - - it('handles small availableTerminalHeight gracefully without overflow in Standard mode', () => { - const result = calculateShellMaxLines({ - status: CoreToolCallStatus.Executing, - isAlternateBuffer: false, - isThisShellFocused: false, - availableTerminalHeight: 2, - constrainHeight: true, - isExpandable: false, - }); - - // Math.max(0, 2 - 2) = 0 - expect(result).toBe(0); - }); - - it('handles small availableTerminalHeight gracefully without overflow in ASB mode', () => { - const result = calculateShellMaxLines({ - status: CoreToolCallStatus.Executing, - isAlternateBuffer: true, - isThisShellFocused: false, - availableTerminalHeight: 6, - constrainHeight: true, - isExpandable: false, - }); - - // Math.max(0, 6 - 2) = 4 - expect(result).toBe(4); - }); - - it('handles negative availableTerminalHeight gracefully', () => { - const result = calculateShellMaxLines({ - status: CoreToolCallStatus.Executing, - isAlternateBuffer: false, - isThisShellFocused: false, - availableTerminalHeight: -5, - constrainHeight: true, - isExpandable: false, - }); - - expect(result).toBe(0); - }); - - it('returns maxLinesBasedOnHeight for focused ASB shells', () => { - const result = calculateShellMaxLines({ - status: CoreToolCallStatus.Executing, - isAlternateBuffer: true, - isThisShellFocused: true, - availableTerminalHeight: 30, - constrainHeight: false, - isExpandable: false, - }); - - // 30 - 2 = 28 - expect(result).toBe(28); - }); - - it('falls back to COMPLETED_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD for completed shells if space allows', () => { - const result = calculateShellMaxLines({ - status: CoreToolCallStatus.Success, - isAlternateBuffer: false, - isThisShellFocused: false, - availableTerminalHeight: 100, - constrainHeight: true, - isExpandable: false, - }); - - expect(result).toBe(COMPLETED_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD); - }); - - it('falls back to ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD for executing shells if space allows', () => { - const result = calculateShellMaxLines({ - status: CoreToolCallStatus.Executing, - isAlternateBuffer: false, - isThisShellFocused: false, - availableTerminalHeight: 100, - constrainHeight: true, - isExpandable: false, - }); - - expect(result).toBe(ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD); + interface CalculateShellMaxLinesTestCase { + desc: string; + options: Parameters[0]; + expected: number | undefined; + } + + const testCases: CalculateShellMaxLinesTestCase[] = [ + { + desc: 'returns undefined when not constrained and is expandable', + options: { + status: CoreToolCallStatus.Executing, + isAlternateBuffer: false, + isThisShellFocused: false, + availableTerminalHeight: 20, + constrainHeight: false, + isExpandable: true, + }, + expected: undefined, + }, + { + desc: 'returns ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD for ASB mode when availableTerminalHeight is undefined', + options: { + status: CoreToolCallStatus.Executing, + isAlternateBuffer: true, + isThisShellFocused: false, + availableTerminalHeight: undefined, + constrainHeight: true, + isExpandable: false, + }, + expected: ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD, + }, + { + desc: 'returns undefined for Standard mode when availableTerminalHeight is undefined', + options: { + status: CoreToolCallStatus.Executing, + isAlternateBuffer: false, + isThisShellFocused: false, + availableTerminalHeight: undefined, + constrainHeight: true, + isExpandable: false, + }, + expected: undefined, + }, + { + desc: 'handles small availableTerminalHeight gracefully without overflow in Standard mode', + options: { + status: CoreToolCallStatus.Executing, + isAlternateBuffer: false, + isThisShellFocused: false, + availableTerminalHeight: 2, + constrainHeight: true, + isExpandable: false, + }, + expected: 0, + }, + { + desc: 'handles small availableTerminalHeight gracefully without overflow in ASB mode', + options: { + status: CoreToolCallStatus.Executing, + isAlternateBuffer: true, + isThisShellFocused: false, + availableTerminalHeight: 6, + constrainHeight: true, + isExpandable: false, + }, + expected: 4, + }, + { + desc: 'handles negative availableTerminalHeight gracefully', + options: { + status: CoreToolCallStatus.Executing, + isAlternateBuffer: false, + isThisShellFocused: false, + availableTerminalHeight: -5, + constrainHeight: true, + isExpandable: false, + }, + expected: 0, + }, + { + desc: 'returns maxLinesBasedOnHeight for focused ASB shells', + options: { + status: CoreToolCallStatus.Executing, + isAlternateBuffer: true, + isThisShellFocused: true, + availableTerminalHeight: 30, + constrainHeight: false, + isExpandable: false, + }, + expected: 28, + }, + { + desc: 'falls back to COMPLETED_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD for completed shells if space allows', + options: { + status: CoreToolCallStatus.Success, + isAlternateBuffer: false, + isThisShellFocused: false, + availableTerminalHeight: 100, + constrainHeight: true, + isExpandable: false, + }, + expected: COMPLETED_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD, + }, + { + desc: 'falls back to ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD for executing shells if space allows', + options: { + status: CoreToolCallStatus.Executing, + isAlternateBuffer: false, + isThisShellFocused: false, + availableTerminalHeight: 100, + constrainHeight: true, + isExpandable: false, + }, + expected: ACTIVE_SHELL_MAX_LINES - SHELL_CONTENT_OVERHEAD, + }, + ]; + + it.each(testCases)('$desc', ({ options, expected }) => { + const result = calculateShellMaxLines(options); + expect(result).toBe(expected); }); }); }); From cb06803afefc2f32d899b9920789b77ce5ffafa6 Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Thu, 12 Mar 2026 23:59:16 -0500 Subject: [PATCH 09/12] Undid shell height changes --- packages/cli/src/ui/utils/toolLayoutUtils.test.ts | 8 ++++---- packages/cli/src/ui/utils/toolLayoutUtils.ts | 11 ++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.test.ts b/packages/cli/src/ui/utils/toolLayoutUtils.test.ts index 35f5fb28e65..18796b7f589 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.test.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.test.ts @@ -48,7 +48,7 @@ describe('toolLayoutUtils', () => { availableTerminalHeight: 2, isAlternateBuffer: false, }, - expected: 0, + expected: 3, }, { desc: 'returns available space directly in constrained terminal (ASB mode)', @@ -56,7 +56,7 @@ describe('toolLayoutUtils', () => { availableTerminalHeight: 4, isAlternateBuffer: true, }, - expected: 2, + expected: 3, }, { desc: 'returns remaining space if sufficient space exists (Standard mode)', @@ -64,7 +64,7 @@ describe('toolLayoutUtils', () => { availableTerminalHeight: 20, isAlternateBuffer: false, }, - expected: 18, + expected: 17, }, { desc: 'returns remaining space if sufficient space exists (ASB mode)', @@ -72,7 +72,7 @@ describe('toolLayoutUtils', () => { availableTerminalHeight: 20, isAlternateBuffer: true, }, - expected: 18, + expected: 13, }, ]; diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.ts b/packages/cli/src/ui/utils/toolLayoutUtils.ts index 398eca6f164..ce8e3f2cba9 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.ts @@ -16,6 +16,7 @@ import { CoreToolCallStatus } from '@google/gemini-cli-core'; * and ToolResultDisplay (for actual truncation). */ export const TOOL_RESULT_STATIC_HEIGHT = 1; +export const TOOL_RESULT_ASB_RESERVED_LINE_COUNT = 6; export const TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT = 2; export const TOOL_RESULT_MIN_LINES_SHOWN = 2; @@ -39,13 +40,17 @@ export function calculateToolContentMaxLines(options: { isAlternateBuffer: boolean; maxLinesLimit?: number; }): number | undefined { - const { availableTerminalHeight, maxLinesLimit } = options; + const { availableTerminalHeight, isAlternateBuffer, maxLinesLimit } = options; + + const reservedLines = isAlternateBuffer + ? TOOL_RESULT_ASB_RESERVED_LINE_COUNT + : TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT; let contentHeight = availableTerminalHeight !== undefined ? Math.max( - 0, - availableTerminalHeight - TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT, + availableTerminalHeight - TOOL_RESULT_STATIC_HEIGHT - reservedLines, + TOOL_RESULT_MIN_LINES_SHOWN + 1, ) : undefined; From 52f7dabec40f6b73ccc4acdbd1c1aa47e4935bc3 Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Fri, 13 Mar 2026 00:10:20 -0500 Subject: [PATCH 10/12] Updated snapshot for one of the tests --- .../messages/__snapshots__/ToolResultDisplay.test.tsx.snap | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap b/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap index 311492591e2..5e5c7ea2b06 100644 --- a/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap +++ b/packages/cli/src/ui/components/messages/__snapshots__/ToolResultDisplay.test.tsx.snap @@ -37,8 +37,7 @@ exports[`ToolResultDisplay > renders string result as plain text when renderOutp `; exports[`ToolResultDisplay > truncates very long string results 1`] = ` -"... 247 hidden (Ctrl+O) ... -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"... 248 hidden (Ctrl+O) ... aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa From 4e1ac4e70851b2f4a4af09db8b7d70b16cdd187d Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Wed, 18 Mar 2026 16:36:28 -0400 Subject: [PATCH 11/12] Reverted changes to MainContent --- packages/cli/src/ui/components/MainContent.tsx | 14 ++++---------- packages/cli/src/ui/utils/toolLayoutUtils.ts | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/packages/cli/src/ui/components/MainContent.tsx b/packages/cli/src/ui/components/MainContent.tsx index 98384f768f6..0530e171b8e 100644 --- a/packages/cli/src/ui/components/MainContent.tsx +++ b/packages/cli/src/ui/components/MainContent.tsx @@ -91,11 +91,9 @@ export const MainContent = () => { { augmentedHistory, mainAreaWidth, staticAreaMaxItemHeight, - availableTerminalHeight, uiState.slashCommands, uiState.constrainHeight, ], @@ -204,11 +201,9 @@ export const MainContent = () => { { pendingItems, uiState.constrainHeight, staticAreaMaxItemHeight, - availableTerminalHeight, ], ); diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.ts b/packages/cli/src/ui/utils/toolLayoutUtils.ts index ce8e3f2cba9..9f391dca4e1 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.ts @@ -102,7 +102,7 @@ export function calculateShellMaxLines(options: { } const maxLinesBasedOnHeight = Math.max( - 0, + 1, availableTerminalHeight - TOOL_RESULT_STANDARD_RESERVED_LINE_COUNT, ); From f9bd3fb50387ba35cda9055d72d1890e7d77ce56 Mon Sep 17 00:00:00 2001 From: Dev Randalpura Date: Wed, 18 Mar 2026 17:12:52 -0400 Subject: [PATCH 12/12] Fixed failing tests --- packages/cli/src/ui/utils/toolLayoutUtils.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/ui/utils/toolLayoutUtils.test.ts b/packages/cli/src/ui/utils/toolLayoutUtils.test.ts index 18796b7f589..57e1e3f1902 100644 --- a/packages/cli/src/ui/utils/toolLayoutUtils.test.ts +++ b/packages/cli/src/ui/utils/toolLayoutUtils.test.ts @@ -136,7 +136,7 @@ describe('toolLayoutUtils', () => { constrainHeight: true, isExpandable: false, }, - expected: 0, + expected: 1, }, { desc: 'handles small availableTerminalHeight gracefully without overflow in ASB mode', @@ -160,7 +160,7 @@ describe('toolLayoutUtils', () => { constrainHeight: true, isExpandable: false, }, - expected: 0, + expected: 1, }, { desc: 'returns maxLinesBasedOnHeight for focused ASB shells',