@@ -92,7 +92,7 @@ import { maxToolOutputCharacterLength, OutputKind } from '../../tools/toolShared
9292import { ToolUtils , Tool , ToolType } from '../../tools/toolUtils'
9393import { ChatStream } from '../../tools/chatStream'
9494import { ChatHistoryStorage } from '../../storages/chatHistoryStorage'
95- import { FsWrite , FsWriteParams } from '../../tools/fsWrite'
95+ import { FsWriteParams } from '../../tools/fsWrite'
9696import { tempDirPath } from '../../../shared/filesystemUtilities'
9797
9898export interface ChatControllerMessagePublishers {
@@ -739,6 +739,10 @@ export class ChatController {
739739 const chatStream = new ChatStream ( this . messenger , tabID , triggerID , toolUse , {
740740 requiresAcceptance : false ,
741741 } )
742+ if ( tool . type === ToolType . FsWrite ) {
743+ const backup = await tool . tool . getOldContent ( )
744+ session . setFsWriteBackups ( toolUse . toolUseId , backup )
745+ }
742746 const output = await ToolUtils . invoke ( tool , chatStream )
743747 if ( output . output . content . length > maxToolOutputCharacterLength ) {
744748 throw Error (
@@ -818,22 +822,29 @@ export class ChatController {
818822 case 'submit-create-prompt' :
819823 await this . handleCreatePrompt ( message )
820824 break
821- case 'accept-code-diff' :
822- await this . closeDiffView ( )
823- break
824825 case 'confirm-tool-use' :
825826 case 'generic-tool-execution' :
826827 await this . processToolUseMessage ( message )
827828 break
828- case 'reject-code-diff' :
829- await this . closeDiffView ( )
830- break
831829 case 'tool-unavailable' :
832830 await this . processUnavailableToolUseMessage ( message )
833831 break
834832 default :
835833 getLogger ( ) . warn ( `Unhandled action: ${ message . action . id } ` )
836834 }
835+
836+ if ( message . action . id . startsWith ( 'reject-code-diff' ) ) {
837+ // revert the changes
838+ const toolUseId = message . action . id . split ( '/' ) [ 1 ]
839+ const backups = this . sessionStorage . getSession ( message . tabID ! ) . fsWriteBackups
840+ const { filePath, content, isNew } = backups . get ( toolUseId ) ?? { }
841+ if ( filePath && isNew ) {
842+ await fs . delete ( filePath )
843+ } else if ( filePath && content !== undefined ) {
844+ await fs . writeFile ( filePath , content )
845+ }
846+ await this . closeDiffView ( )
847+ }
837848 }
838849
839850 private async processContextSelected ( message : ContextSelectedMessage ) {
@@ -855,8 +866,10 @@ export class ChatController {
855866
856867 private async processFileClickMessage ( message : FileClick ) {
857868 const session = this . sessionStorage . getSession ( message . tabID )
869+ const toolUseId = message . messageId
870+ const backup = session . fsWriteBackups . get ( toolUseId )
858871 // Check if user clicked on filePath in the contextList or in the fileListTree and perform the functionality accordingly.
859- if ( session . showDiffOnFileWrite ) {
872+ if ( session . showDiffOnFileWrite && backup ?. filePath ) {
860873 try {
861874 // Create a temporary file path to show the diff view
862875 const pathToArchiveDir = path . join ( tempDirPath , 'q-chat' )
@@ -867,40 +880,13 @@ export class ChatController {
867880 await fs . mkdir ( pathToArchiveDir )
868881 const resultArtifactsDir = path . join ( pathToArchiveDir , 'resultArtifacts' )
869882 await fs . mkdir ( resultArtifactsDir )
870- const tempFilePath = path . join (
871- resultArtifactsDir ,
872- `temp-${ path . basename ( ( session . toolUse ?. input as unknown as FsWriteParams ) . path ) } `
873- )
883+ const tempFilePath = path . join ( resultArtifactsDir , `temp-${ path . basename ( backup . filePath ) } ` )
874884
875- // If we have existing filePath copy file content from existing file to temporary file.
876- const filePath = ( session . toolUse ?. input as any ) . path ?? message . filePath
877- const fileExists = await fs . existsFile ( filePath )
878- if ( fileExists ) {
879- const fileContent = await fs . readFileText ( filePath )
880- await fs . writeFile ( tempFilePath , fileContent )
881- }
885+ await fs . writeFile ( tempFilePath , backup . content )
882886
883- // Create a deep clone of the toolUse object and pass this toolUse to FsWrite tool execution to get the modified temporary file.
884- const clonedToolUse = structuredClone ( session . toolUse )
885- if ( ! clonedToolUse ) {
886- return
887- }
888- const input = clonedToolUse . input as unknown as FsWriteParams
889- input . path = tempFilePath
890-
891- const fsWrite = new FsWrite ( input )
892- await fsWrite . invoke ( )
893-
894- // Check if fileExists=false, If yes, return instead of showing broken diff experience.
895- if ( ! tempFilePath ) {
896- void vscode . window . showInformationMessage (
897- 'Generated code changes have been reviewed and processed.'
898- )
899- return
900- }
901- const leftUri = fileExists ? vscode . Uri . file ( filePath ) : vscode . Uri . from ( { scheme : 'untitled' } )
902- const rightUri = vscode . Uri . file ( tempFilePath ?? filePath )
903- const fileName = path . basename ( filePath )
887+ const leftUri = vscode . Uri . file ( tempFilePath )
888+ const rightUri = vscode . Uri . file ( backup . filePath )
889+ const fileName = path . basename ( backup . filePath )
904890 await vscode . commands . executeCommand (
905891 'vscode.diff' ,
906892 leftUri ,
0 commit comments