11/**
22 * @license
3- * Copyright 2025 Google LLC
3+ * Copyright 2026 Google LLC
44 * SPDX-License-Identifier: Apache-2.0
55 */
66
@@ -18,7 +18,11 @@ import {
1818 isListResult ,
1919 isReadManyFilesResult ,
2020} from '@google/gemini-cli-core' ;
21- import { type IndividualToolCallDisplay , isTodoList } from '../../types.js' ;
21+ import {
22+ type IndividualToolCallDisplay ,
23+ type ToolResultDisplay ,
24+ isTodoList ,
25+ } from '../../types.js' ;
2226import { useAlternateBuffer } from '../../hooks/useAlternateBuffer.js' ;
2327import { ToolStatusIndicator } from './ToolShared.js' ;
2428import { theme } from '../../semantic-colors.js' ;
@@ -36,8 +40,13 @@ import { colorizeCode } from '../../utils/CodeColorizer.js';
3640import { useToolActions } from '../../contexts/ToolActionsContext.js' ;
3741import { getFileExtension } from '../../utils/fileUtils.js' ;
3842
43+ const PAYLOAD_MARGIN_LEFT = 6 ;
44+ const PAYLOAD_BORDER_CHROME_WIDTH = 4 ; // paddingX=1 (2 cols) + borders (2 cols)
45+ const PAYLOAD_SCROLL_GUTTER = 4 ;
46+ const PAYLOAD_MAX_WIDTH = 120 + PAYLOAD_SCROLL_GUTTER ;
47+
3948interface DenseToolMessageProps extends IndividualToolCallDisplay {
40- terminalWidth ? : number ;
49+ terminalWidth : number ;
4150 availableTerminalHeight ?: number ;
4251}
4352
@@ -63,10 +72,6 @@ const hasPayload = (res: unknown): res is PayloadResult => {
6372 return typeof value === 'string' ;
6473} ;
6574
66- /**
67- * --- RENDER HELPERS ---
68- */
69-
7075const RenderItemsList : React . FC < {
7176 items ?: string [ ] ;
7277 maxVisible ?: number ;
@@ -88,17 +93,13 @@ const RenderItemsList: React.FC<{
8893 ) ;
8994} ;
9095
91- /**
92- * --- SCENARIO LOGIC (Pure Functions) ---
93- */
94-
9596function getFileOpData (
9697 diff : FileDiff ,
9798 status : CoreToolCallStatus ,
98- resultDisplay : unknown ,
99- terminalWidth ? : number ,
100- availableTerminalHeight ? : number ,
101- isClickable ? : boolean ,
99+ resultDisplay : ToolResultDisplay | undefined ,
100+ terminalWidth : number ,
101+ availableTerminalHeight : number | undefined ,
102+ isClickable : boolean ,
102103) : ViewParts {
103104 const added =
104105 ( diff . diffStat ?. model_added_lines ?? 0 ) +
@@ -177,7 +178,7 @@ function getFileOpData(
177178 < DiffRenderer
178179 diffContent = { diff . fileDiff }
179180 filename = { diff . fileName }
180- terminalWidth = { terminalWidth ? terminalWidth - 6 : 80 }
181+ terminalWidth = { terminalWidth - PAYLOAD_MARGIN_LEFT }
181182 availableTerminalHeight = { availableTerminalHeight }
182183 disableColor = { status === CoreToolCallStatus . Cancelled }
183184 />
@@ -201,26 +202,12 @@ function getReadManyFilesData(result: ReadManyFilesResult): ViewParts {
201202 skippedCount > 0 ? ` (${ skippedCount } ignored)` : ''
202203 } `;
203204 const summary = < Text color = { theme . text . accent } > → { summaryStr } </ Text > ;
204-
205- const excludedText =
206- result . excludes && result . excludes . length > 0
207- ? `Excluded patterns: ${ result . excludes . slice ( 0 , 3 ) . join ( ', ' ) } ${
208- result . excludes . length > 3 ? '...' : ''
209- } `
210- : undefined ;
211-
212205 const hasItems = items . length > 0 ;
213- const payload =
214- hasItems || excludedText ? (
215- < Box flexDirection = "column" marginLeft = { 2 } >
216- { hasItems && < RenderItemsList items = { items } maxVisible = { maxVisible } /> }
217- { excludedText && (
218- < Text color = { theme . text . secondary } dimColor >
219- { excludedText }
220- </ Text >
221- ) }
222- </ Box >
223- ) : undefined ;
206+ const payload = hasItems ? (
207+ < Box flexDirection = "column" marginLeft = { 2 } >
208+ { hasItems && < RenderItemsList items = { items } maxVisible = { maxVisible } /> }
209+ </ Box >
210+ ) : undefined ;
224211
225212 return { description, summary, payload } ;
226213}
@@ -309,10 +296,6 @@ function getGenericSuccessData(
309296 return { description, summary, payload } ;
310297}
311298
312- /**
313- * --- MAIN COMPONENT ---
314- */
315-
316299export const DenseToolMessage : React . FC < DenseToolMessageProps > = ( props ) => {
317300 const {
318301 callId,
@@ -339,7 +322,7 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
339322 const [ isFocused , setIsFocused ] = useState ( false ) ;
340323 const toggleRef = useRef < DOMElement > ( null ) ;
341324
342- // 1. Unified File Data Extraction (Safely bridge resultDisplay and confirmationDetails)
325+ // Unified File Data Extraction (Safely bridge resultDisplay and confirmationDetails)
343326 const diff = useMemo ( ( ) : FileDiff | undefined => {
344327 if ( isFileDiff ( resultDisplay ) ) return resultDisplay ;
345328 if ( confirmationDetails ?. type === 'edit' ) {
@@ -375,7 +358,7 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
375358 isActive : isAlternateBuffer && ! ! diff ,
376359 } ) ;
377360
378- // 2. State-to-View Coordination
361+ // State-to-View Coordination
379362 const viewParts = useMemo ( ( ) : ViewParts => {
380363 if ( diff ) {
381364 return getFileOpData (
@@ -459,7 +442,7 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
459442 return colorizeCode ( {
460443 code : addedContent ,
461444 language : fileExtension ,
462- maxWidth : terminalWidth ? terminalWidth - 6 : 80 ,
445+ maxWidth : terminalWidth - PAYLOAD_MARGIN_LEFT ,
463446 settings,
464447 disableColor : status === CoreToolCallStatus . Cancelled ,
465448 returnLines : true ,
@@ -468,7 +451,7 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
468451 return renderDiffLines ( {
469452 parsedLines,
470453 filename : diff . fileName ,
471- terminalWidth : terminalWidth ? terminalWidth - 6 : 80 ,
454+ terminalWidth : terminalWidth - PAYLOAD_MARGIN_LEFT ,
472455 disableColor : status === CoreToolCallStatus . Cancelled ,
473456 } ) ;
474457 }
@@ -502,7 +485,6 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
502485 < Box minHeight = { 1 } > { item } </ Box >
503486 ) ;
504487
505- // 3. Final Layout
506488 return (
507489 < Box flexDirection = "column" >
508490 < Box marginLeft = { 2 } flexDirection = "row" flexWrap = "wrap" >
@@ -529,7 +511,7 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
529511
530512 { showPayload && isAlternateBuffer && diffLines . length > 0 && (
531513 < Box
532- marginLeft = { 6 }
514+ marginLeft = { PAYLOAD_MARGIN_LEFT }
533515 marginTop = { 1 }
534516 marginBottom = { 1 }
535517 paddingX = { 1 }
@@ -541,30 +523,36 @@ export const DenseToolMessage: React.FC<DenseToolMessageProps> = (props) => {
541523 borderStyle = "round"
542524 borderColor = { theme . border . default }
543525 borderDimColor = { true }
544- maxWidth = { terminalWidth ? Math . min ( 124 , terminalWidth - 6 ) : 124 }
526+ maxWidth = { Math . min (
527+ PAYLOAD_MAX_WIDTH ,
528+ terminalWidth - PAYLOAD_MARGIN_LEFT ,
529+ ) }
545530 >
546531 < ScrollableList
547532 data = { diffLines }
548533 renderItem = { renderItem }
549534 keyExtractor = { keyExtractor }
550535 estimatedItemHeight = { ( ) => 1 }
551536 hasFocus = { isFocused }
552- width = {
553- // adjustment: 6 margin - 4 padding/border - 4 right-scroll-gutter
554- terminalWidth ? Math . min ( 120 , terminalWidth - 6 - 4 - 4 ) : 70
555- }
537+ width = { Math . min (
538+ PAYLOAD_MAX_WIDTH ,
539+ terminalWidth -
540+ PAYLOAD_MARGIN_LEFT -
541+ PAYLOAD_BORDER_CHROME_WIDTH -
542+ PAYLOAD_SCROLL_GUTTER ,
543+ ) }
556544 />
557545 </ Box >
558546 ) }
559547
560548 { showPayload && ( ! isAlternateBuffer || ! diff ) && viewParts . payload && (
561- < Box marginLeft = { 6 } marginTop = { 1 } marginBottom = { 1 } >
549+ < Box marginLeft = { PAYLOAD_MARGIN_LEFT } marginTop = { 1 } marginBottom = { 1 } >
562550 { viewParts . payload }
563551 </ Box >
564552 ) }
565553
566554 { showPayload && outputFile && (
567- < Box marginLeft = { 6 } marginTop = { 1 } marginBottom = { 1 } >
555+ < Box marginLeft = { PAYLOAD_MARGIN_LEFT } marginTop = { 1 } marginBottom = { 1 } >
568556 < Text color = { theme . text . secondary } >
569557 (Output saved to: { outputFile } )
570558 </ Text >
0 commit comments