FileWriteToolDiff.tsx
1 import * as React from 'react' 2 import { existsSync, readFileSync } from 'fs' 3 import { useMemo } from 'react' 4 import { StructuredDiff } from '../../StructuredDiff.js' 5 import { Box, Text } from 'ink' 6 import { getTheme } from '../../../utils/theme.js' 7 import { intersperse } from '../../../utils/array.js' 8 import { getCwd } from '../../../utils/state.js' 9 import { extname, relative } from 'path' 10 import { detectFileEncoding } from '../../../utils/file.js' 11 import { HighlightedCode } from '../../HighlightedCode.js' 12 import { getPatch } from '../../../utils/diff.js' 13 14 type Props = { 15 file_path: string 16 content: string 17 verbose: boolean 18 width: number 19 } 20 21 export function FileWriteToolDiff({ 22 file_path, 23 content, 24 verbose, 25 width, 26 }: Props): React.ReactNode { 27 const fileExists = useMemo(() => existsSync(file_path), [file_path]) 28 const oldContent = useMemo(() => { 29 if (!fileExists) { 30 return '' 31 } 32 const enc = detectFileEncoding(file_path) 33 return readFileSync(file_path, enc) 34 }, [file_path, fileExists]) 35 const hunks = useMemo(() => { 36 if (!fileExists) { 37 return null 38 } 39 return getPatch({ 40 filePath: file_path, 41 fileContents: oldContent, 42 oldStr: oldContent, 43 newStr: content, 44 }) 45 }, [fileExists, file_path, oldContent, content]) 46 47 return ( 48 <Box 49 borderColor={getTheme().secondaryBorder} 50 borderStyle="round" 51 flexDirection="column" 52 paddingX={1} 53 > 54 <Box paddingBottom={1}> 55 <Text bold>{verbose ? file_path : relative(getCwd(), file_path)}</Text> 56 </Box> 57 {hunks ? ( 58 intersperse( 59 hunks.map(_ => ( 60 <StructuredDiff 61 key={_.newStart} 62 patch={_} 63 dim={false} 64 width={width} 65 /> 66 )), 67 i => ( 68 <Text color={getTheme().secondaryText} key={`ellipsis-${i}`}> 69 ... 70 </Text> 71 ), 72 ) 73 ) : ( 74 <HighlightedCode 75 code={content || '(No content)'} 76 language={extname(file_path).slice(1)} 77 /> 78 )} 79 </Box> 80 ) 81 }