@@ -13,20 +13,29 @@ import { CodeWhispererSession } from '../sessionManager'
1313import type { AmazonQInlineCompletionItemProvider } from '../completion'
1414import { vsCodeState } from 'aws-core-vscode/codewhisperer'
1515import { applyPatch , createPatch } from 'diff'
16+ import { EditSuggestionState } from '../editSuggestionState'
1617
1718function logSuggestionFailure ( type : 'DISCARD' | 'REJECT' , reason : string , suggestionContent : string ) {
1819 getLogger ( 'nextEditPrediction' ) . debug (
1920 `Auto ${ type } edit suggestion with reason=${ reason } , suggetion: ${ suggestionContent } `
2021 )
2122}
2223
24+ const autoRejectEditCursorDistance = 25
25+ const maxPrefixRetryCount = 5
26+
27+ enum RejectReason {
28+ DocumentChange = 'Invalid patch due to document change' ,
29+ NotApplicableToOriginal = 'ApplyPatch fail for original code' ,
30+ MaxRetry = 'Already retry 10 times' ,
31+ }
32+
2333export class EditsSuggestionSvg {
2434 private readonly logger = getLogger ( 'nextEditPrediction' )
2535 private readonly documentChangedListener : vscode . Disposable
26- // TODO:
27- // private readonly cursorChangedListener: vscode.Disposable
28-
36+ private readonly cursorChangedListener : vscode . Disposable
2937 private readonly updatedSuggestions : InlineCompletionItemWithReferences [ ] = [ ]
38+ private startLine = 0
3039
3140 constructor (
3241 private suggestion : InlineCompletionItemWithReferences ,
@@ -38,6 +47,10 @@ export class EditsSuggestionSvg {
3847 this . documentChangedListener = vscode . workspace . onDidChangeTextDocument ( async ( e ) => {
3948 await this . onDocChange ( e )
4049 } )
50+
51+ this . cursorChangedListener = vscode . window . onDidChangeTextEditorSelection ( ( e ) => {
52+ this . onCursorChange ( e )
53+ } )
4154 }
4255
4356 async show ( ) {
@@ -57,6 +70,9 @@ export class EditsSuggestionSvg {
5770 const { svgImage, startLine, newCode, originalCodeHighlightRange } =
5871 await svgGenerationService . generateDiffSvg ( currentFile , this . suggestion . insertText as string )
5972
73+ // For cursorChangeListener to access
74+ this . startLine = startLine
75+
6076 // TODO: To investigate why it fails and patch [generateDiffSvg]
6177 if ( newCode . length === 0 ) {
6278 this . logger . warn ( 'not able to apply provided edit suggestion, skip rendering' )
@@ -74,7 +90,7 @@ export class EditsSuggestionSvg {
7490 this . session ,
7591 this . languageClient ,
7692 item ,
77- this . documentChangedListener ,
93+ [ this . documentChangedListener , this . cursorChangedListener ] ,
7894 this . inlineCompletionProvider
7995 )
8096 } else {
@@ -85,6 +101,25 @@ export class EditsSuggestionSvg {
85101 }
86102 }
87103
104+ private onCursorChange ( e : vscode . TextEditorSelectionChangeEvent ) {
105+ if ( ! EditSuggestionState . isEditSuggestionActive ( ) ) {
106+ return
107+ }
108+ if ( e . textEditor !== this . editor ) {
109+ return
110+ }
111+ const currentPosition = e . selections [ 0 ] . active
112+ const distance = Math . abs ( currentPosition . line - this . startLine )
113+ if ( distance > autoRejectEditCursorDistance ) {
114+ logSuggestionFailure (
115+ 'REJECT' ,
116+ `cursor position move too far away off ${ autoRejectEditCursorDistance } lines` ,
117+ this . suggestion . insertText as string
118+ )
119+ void vscode . commands . executeCommand ( 'aws.amazonq.inline.rejectEdit' )
120+ }
121+ }
122+
88123 private async onDocChange ( e : vscode . TextDocumentChangeEvent ) {
89124 if ( e . contentChanges . length <= 0 ) {
90125 return
@@ -104,40 +139,44 @@ export class EditsSuggestionSvg {
104139 * 2. Do a diff between the above code and what's currently in the editor
105140 * 3. Show this second diff to the user as the edit suggestion
106141 */
107-
142+ // Users' file content when the request fires (best guess because the actual process happens in language server)
108143 const originalCode = this . session . fileContent
109144 const appliedToOriginal = applyPatch ( originalCode , this . suggestion . insertText as string )
110145 try {
111146 if ( appliedToOriginal ) {
112- const updatedPatch = createPatch (
113- this . editor . document . fileName ,
114- this . editor . document . getText ( ) ,
115- appliedToOriginal
116- )
117- // show updatedPatch
118- this . updateSuggestion ( updatedPatch )
147+ const updatedPatch = this . patchSuggestion ( appliedToOriginal )
119148
120- if ( this . updatedSuggestions . length > 5 ) {
121- this . autoReject ( )
149+ if ( this . updatedSuggestions . length > maxPrefixRetryCount ) {
150+ this . autoReject ( RejectReason . MaxRetry )
151+ } else if ( applyPatch ( this . editor . document . getText ( ) , updatedPatch ) === false ) {
152+ this . autoReject ( RejectReason . DocumentChange )
122153 }
123154
124155 await this . show ( )
125156 } else {
126- this . autoReject ( )
157+ this . autoReject ( RejectReason . NotApplicableToOriginal )
127158 }
128159 } catch ( e ) {
129- this . logger . info ( '123' )
160+ // TODO: format
161+ this . logger . error ( `${ e } ` )
130162 }
131163 }
132164
133- private autoReject ( ) {
134- logSuggestionFailure ( 'REJECT' , 'Invalid patch due to document change' , this . suggestion . insertText as string )
165+ private autoReject ( reason : string ) {
166+ logSuggestionFailure ( 'REJECT' , reason , this . suggestion . insertText as string )
135167 void vscode . commands . executeCommand ( 'aws.amazonq.inline.rejectEdit' )
136168 }
137169
138- private updateSuggestion ( content : string ) {
139- this . logger . info ( `update edit suggestion\n ${ content } ` )
140- const updated : InlineCompletionItemWithReferences = { ...this . suggestion , insertText : content }
170+ private patchSuggestion ( appliedToOriginal : string ) : string {
171+ const updatedPatch = createPatch (
172+ this . editor . document . fileName ,
173+ this . editor . document . getText ( ) ,
174+ appliedToOriginal
175+ )
176+
177+ this . logger . info ( `Update edit suggestion\n ${ updatedPatch } ` )
178+ const updated : InlineCompletionItemWithReferences = { ...this . suggestion , insertText : updatedPatch }
141179 this . updatedSuggestions . push ( updated )
180+ return updatedPatch
142181 }
143182}
0 commit comments