@@ -92,7 +92,7 @@ import { maxToolOutputCharacterLength, OutputKind } from '../../tools/toolShared
92
92
import { ToolUtils , Tool , ToolType } from '../../tools/toolUtils'
93
93
import { ChatStream } from '../../tools/chatStream'
94
94
import { ChatHistoryStorage } from '../../storages/chatHistoryStorage'
95
- import { FsWrite , FsWriteParams } from '../../tools/fsWrite'
95
+ import { FsWriteParams } from '../../tools/fsWrite'
96
96
import { tempDirPath } from '../../../shared/filesystemUtilities'
97
97
98
98
export interface ChatControllerMessagePublishers {
@@ -739,6 +739,10 @@ export class ChatController {
739
739
const chatStream = new ChatStream ( this . messenger , tabID , triggerID , toolUse , {
740
740
requiresAcceptance : false ,
741
741
} )
742
+ if ( tool . type === ToolType . FsWrite ) {
743
+ const backup = await tool . tool . getOldContent ( )
744
+ session . setFsWriteBackups ( toolUse . toolUseId , backup )
745
+ }
742
746
const output = await ToolUtils . invoke ( tool , chatStream )
743
747
if ( output . output . content . length > maxToolOutputCharacterLength ) {
744
748
throw Error (
@@ -818,22 +822,29 @@ export class ChatController {
818
822
case 'submit-create-prompt' :
819
823
await this . handleCreatePrompt ( message )
820
824
break
821
- case 'accept-code-diff' :
822
- await this . closeDiffView ( )
823
- break
824
825
case 'confirm-tool-use' :
825
826
case 'generic-tool-execution' :
826
827
await this . processToolUseMessage ( message )
827
828
break
828
- case 'reject-code-diff' :
829
- await this . closeDiffView ( )
830
- break
831
829
case 'tool-unavailable' :
832
830
await this . processUnavailableToolUseMessage ( message )
833
831
break
834
832
default :
835
833
getLogger ( ) . warn ( `Unhandled action: ${ message . action . id } ` )
836
834
}
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
+ }
837
848
}
838
849
839
850
private async processContextSelected ( message : ContextSelectedMessage ) {
@@ -855,8 +866,10 @@ export class ChatController {
855
866
856
867
private async processFileClickMessage ( message : FileClick ) {
857
868
const session = this . sessionStorage . getSession ( message . tabID )
869
+ const toolUseId = message . messageId
870
+ const backup = session . fsWriteBackups . get ( toolUseId )
858
871
// 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 ) {
860
873
try {
861
874
// Create a temporary file path to show the diff view
862
875
const pathToArchiveDir = path . join ( tempDirPath , 'q-chat' )
@@ -867,40 +880,13 @@ export class ChatController {
867
880
await fs . mkdir ( pathToArchiveDir )
868
881
const resultArtifactsDir = path . join ( pathToArchiveDir , 'resultArtifacts' )
869
882
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 ) } ` )
874
884
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 )
882
886
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 )
904
890
await vscode . commands . executeCommand (
905
891
'vscode.diff' ,
906
892
leftUri ,
0 commit comments