Skip to content

Commit 58f5cd5

Browse files
committed
feat(amazonq): add button to accept code changes in diff view
1 parent 791ae55 commit 58f5cd5

File tree

13 files changed

+233
-40
lines changed

13 files changed

+233
-40
lines changed

packages/core/src/amazonq/commons/controllers/contentController.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
*/
55

66
import * as vscode from 'vscode'
7-
import { Position, TextEditor, window } from 'vscode'
7+
import path from 'path'
8+
import { commands, Position, TextEditor, Uri, window, workspace } from 'vscode'
89
import { getLogger } from '../../../shared/logger'
10+
import { getNonexistentFilename } from '../../../shared'
911

1012
export class EditorContentController {
1113
/* *
@@ -52,4 +54,35 @@ export class EditorContentController {
5254
)
5355
}
5456
}
57+
58+
public async acceptDiff(message: any) {
59+
const { filePath } = message?.context?.activeFileContext || {}
60+
if (filePath && message?.code?.trim().length > 0) {
61+
const left = Uri.file(filePath) // Existing File to Write
62+
const fileNameWithExtension = path.basename(left.path)
63+
const fileName = path.parse(fileNameWithExtension).name
64+
const fileExtension = path.extname(fileNameWithExtension)
65+
66+
// Create a new file with the proposed changes
67+
const rightFile = await getNonexistentFilename(
68+
path.dirname(left.path),
69+
`${fileName}_proposed`,
70+
fileExtension,
71+
99
72+
)
73+
74+
const diffScheme = 'amazon-q-accept-diff'
75+
const right = Uri.parse(`${diffScheme}:${rightFile}`)
76+
77+
class LeftContentProvider {
78+
provideTextDocumentContent(_uri: Uri) {
79+
return message.code
80+
}
81+
}
82+
const leftContentProvider = new LeftContentProvider()
83+
void workspace.registerTextDocumentContentProvider(diffScheme, leftContentProvider)
84+
85+
await commands.executeCommand('vscode.diff', left, right, `${fileName} (Generated by Amazon Q)`)
86+
}
87+
}
5588
}

packages/core/src/amazonq/webview/ui/apps/cwChatConnector.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ interface ChatPayload {
1717
export interface ConnectorProps {
1818
sendMessageToExtension: (message: ExtensionMessage) => void
1919
onMessageReceived?: (tabID: string, messageData: any, needToShowAPIDocsTab: boolean) => void
20-
onChatAnswerReceived?: (tabID: string, message: ChatItem) => void
20+
onChatAnswerReceived?: (tabID: string, message: ChatItem, messageData: any) => void
2121
onCWCContextCommandMessage: (message: ChatItem, command?: string) => string | undefined
2222
onError: (tabID: string, message: string, title: string) => void
2323
onWarning: (tabID: string, message: string, title: string) => void
@@ -278,7 +278,7 @@ export class Connector {
278278
content: messageData.relatedSuggestions,
279279
}
280280
}
281-
this.onChatAnswerReceived(messageData.tabID, answer)
281+
this.onChatAnswerReceived(messageData.tabID, answer, messageData)
282282

283283
// Exit the function if we received an answer from AI
284284
if (
@@ -305,7 +305,7 @@ export class Connector {
305305
}
306306
: undefined,
307307
}
308-
this.onChatAnswerReceived(messageData.tabID, answer)
308+
this.onChatAnswerReceived(messageData.tabID, answer, messageData)
309309

310310
return
311311
}
@@ -316,13 +316,17 @@ export class Connector {
316316
return
317317
}
318318

319-
this.onChatAnswerReceived(messageData.tabID, {
320-
type: ChatItemType.ANSWER,
321-
messageId: messageData.triggerID,
322-
body: messageData.message,
323-
followUp: this.followUpGenerator.generateAuthFollowUps('cwc', messageData.authType),
324-
canBeVoted: false,
325-
})
319+
this.onChatAnswerReceived(
320+
messageData.tabID,
321+
{
322+
type: ChatItemType.ANSWER,
323+
messageId: messageData.triggerID,
324+
body: messageData.message,
325+
followUp: this.followUpGenerator.generateAuthFollowUps('cwc', messageData.authType),
326+
canBeVoted: false,
327+
},
328+
messageData
329+
)
326330

327331
return
328332
}

packages/core/src/amazonq/webview/ui/apps/featureDevChatConnector.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export interface ConnectorProps {
1919
sendMessageToExtension: (message: ExtensionMessage) => void
2020
onMessageReceived?: (tabID: string, messageData: any, needToShowAPIDocsTab: boolean) => void
2121
onAsyncEventProgress: (tabID: string, inProgress: boolean, message: string) => void
22-
onChatAnswerReceived?: (tabID: string, message: ChatItem) => void
22+
onChatAnswerReceived?: (tabID: string, message: ChatItem, messageData: any) => void
2323
sendFeedback?: (tabId: string, feedbackPayload: FeedbackPayload) => void | undefined
2424
onError: (tabID: string, message: string, title: string) => void
2525
onWarning: (tabID: string, message: string, title: string) => void
@@ -153,7 +153,7 @@ export class Connector {
153153
}
154154
: undefined,
155155
}
156-
this.onChatAnswerReceived(messageData.tabID, answer)
156+
this.onChatAnswerReceived(messageData.tabID, answer, messageData)
157157
}
158158
}
159159

@@ -176,7 +176,7 @@ export class Connector {
176176
},
177177
body: '',
178178
}
179-
this.onChatAnswerReceived(messageData.tabID, answer)
179+
this.onChatAnswerReceived(messageData.tabID, answer, messageData)
180180
}
181181
}
182182

@@ -185,19 +185,27 @@ export class Connector {
185185
return
186186
}
187187

188-
this.onChatAnswerReceived(messageData.tabID, {
189-
type: ChatItemType.ANSWER,
190-
body: messageData.message,
191-
followUp: undefined,
192-
canBeVoted: false,
193-
})
194-
195-
this.onChatAnswerReceived(messageData.tabID, {
196-
type: ChatItemType.SYSTEM_PROMPT,
197-
body: undefined,
198-
followUp: this.followUpGenerator.generateAuthFollowUps('featuredev', messageData.authType),
199-
canBeVoted: false,
200-
})
188+
this.onChatAnswerReceived(
189+
messageData.tabID,
190+
{
191+
type: ChatItemType.ANSWER,
192+
body: messageData.message,
193+
followUp: undefined,
194+
canBeVoted: false,
195+
},
196+
messageData
197+
)
198+
199+
this.onChatAnswerReceived(
200+
messageData.tabID,
201+
{
202+
type: ChatItemType.SYSTEM_PROMPT,
203+
body: undefined,
204+
followUp: this.followUpGenerator.generateAuthFollowUps('featuredev', messageData.authType),
205+
canBeVoted: false,
206+
},
207+
messageData
208+
)
201209

202210
return
203211
}

packages/core/src/amazonq/webview/ui/apps/gumbyChatConnector.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export interface ConnectorProps {
1717
sendMessageToExtension: (message: ExtensionMessage) => void
1818
onMessageReceived?: (tabID: string, messageData: any, needToShowAPIDocsTab: boolean) => void
1919
onAsyncEventProgress: (tabID: string, inProgress: boolean, message: string, messageId: string) => void
20-
onChatAnswerReceived?: (tabID: string, message: ChatItem) => void
20+
onChatAnswerReceived?: (tabID: string, message: ChatItem, messageData: any) => void
2121
onChatAnswerUpdated?: (tabID: string, message: ChatItem) => void
2222
onQuickHandlerCommand: (tabID: string, command: string, eventId?: string) => void
2323
onError: (tabID: string, message: string, title: string) => void
@@ -90,7 +90,7 @@ export class Connector {
9090
canBeVoted: false,
9191
}
9292

93-
this.onChatAnswerReceived(tabID, answer)
93+
this.onChatAnswerReceived(tabID, answer, messageData)
9494

9595
return
9696
}
@@ -114,7 +114,7 @@ export class Connector {
114114
return
115115
}
116116

117-
this.onChatAnswerReceived(messageData.tabID, answer)
117+
this.onChatAnswerReceived(messageData.tabID, answer, messageData)
118118
}
119119
}
120120

@@ -143,10 +143,14 @@ export class Connector {
143143
return
144144
}
145145

146-
this.onChatAnswerReceived(messageData.tabID, {
147-
type: ChatItemType.SYSTEM_PROMPT,
148-
body: messageData.message,
149-
})
146+
this.onChatAnswerReceived(
147+
messageData.tabID,
148+
{
149+
type: ChatItemType.SYSTEM_PROMPT,
150+
body: messageData.message,
151+
},
152+
messageData
153+
)
150154
}
151155

152156
onCustomFormAction(

packages/core/src/amazonq/webview/ui/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type MessageCommand =
1616
| 'open-diff'
1717
| 'code_was_copied_to_clipboard'
1818
| 'insert_code_at_cursor_position'
19+
| 'accept_diff'
1920
| 'stop-response'
2021
| 'trigger-tabID-received'
2122
| 'clear'

packages/core/src/amazonq/webview/ui/connector.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { ChatItem, FeedbackPayload, Engagement, ChatItemAction } from '@aws/mynah-ui'
6+
import {
7+
ChatItem,
8+
FeedbackPayload,
9+
Engagement,
10+
ChatItemAction,
11+
CodeSelectionType,
12+
ReferenceTrackerInformation,
13+
} from '@aws/mynah-ui'
714
import { Connector as CWChatConnector } from './apps/cwChatConnector'
815
import { Connector as FeatureDevChatConnector } from './apps/featureDevChatConnector'
916
import { Connector as AmazonQCommonsConnector } from './apps/amazonqCommonsConnector'
@@ -33,7 +40,7 @@ export interface ConnectorProps {
3340
sendMessageToExtension: (message: ExtensionMessage) => void
3441
onMessageReceived?: (tabID: string, messageData: any, needToShowAPIDocsTab: boolean) => void
3542
onChatAnswerUpdated?: (tabID: string, message: ChatItem) => void
36-
onChatAnswerReceived?: (tabID: string, message: ChatItem) => void
43+
onChatAnswerReceived?: (tabID: string, message: ChatItem, messageData: any) => void
3744
onWelcomeFollowUpClicked: (tabID: string, welcomeFollowUpType: WelcomeFollowupType) => void
3845
onAsyncEventProgress: (tabID: string, inProgress: boolean, message: string | undefined) => void
3946
onQuickHandlerCommand: (tabID: string, command?: string, eventId?: string) => void
@@ -235,6 +242,35 @@ export class Connector {
235242
}
236243
}
237244

245+
onAcceptDiff = (
246+
tabId: string,
247+
messageId: string,
248+
actionId: string,
249+
data?: string,
250+
code?: string,
251+
type?: CodeSelectionType,
252+
referenceTrackerInformation?: ReferenceTrackerInformation[],
253+
eventId?: string,
254+
codeBlockIndex?: number,
255+
totalCodeBlocks?: number
256+
) => {
257+
const tabType = this.tabsStorage.getTab(tabId)?.type
258+
this.sendMessageToExtension({
259+
tabType,
260+
tabID: tabId,
261+
command: 'accept_diff',
262+
messageId,
263+
actionId,
264+
data,
265+
code,
266+
type,
267+
referenceTrackerInformation,
268+
eventId,
269+
codeBlockIndex,
270+
totalCodeBlocks,
271+
})
272+
}
273+
238274
onCopyCodeToClipboard = (
239275
tabID: string,
240276
messageId: string,

packages/core/src/amazonq/webview/ui/main.ts

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,16 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55
import { Connector } from './connector'
6-
import { ChatItem, ChatItemType, MynahIcons, MynahUI, MynahUIDataModel, NotificationType } from '@aws/mynah-ui'
6+
import {
7+
ChatItem,
8+
ChatItemType,
9+
CodeSelectionType,
10+
MynahIcons,
11+
MynahUI,
12+
MynahUIDataModel,
13+
NotificationType,
14+
ReferenceTrackerInformation,
15+
} from '@aws/mynah-ui'
716
import { ChatPrompt } from '@aws/mynah-ui/dist/static'
817
import { TabsStorage, TabType } from './storages/tabsStorage'
918
import { WelcomeFollowupType } from './apps/amazonqCommonsConnector'
@@ -189,7 +198,7 @@ export const createMynahUI = (ideApi: any, amazonQEnabled: boolean) => {
189198
} as ChatItem)
190199
}
191200
},
192-
onChatAnswerReceived: (tabID: string, item: ChatItem) => {
201+
onChatAnswerReceived: (tabID: string, item: ChatItem, messageData: any) => {
193202
if (item.type === ChatItemType.ANSWER_PART || item.type === ChatItemType.CODE_RESULT) {
194203
mynahUI.updateLastChatAnswer(tabID, {
195204
...(item.messageId !== undefined ? { messageId: item.messageId } : {}),
@@ -211,7 +220,18 @@ export const createMynahUI = (ideApi: any, amazonQEnabled: boolean) => {
211220
item.formItems !== undefined ||
212221
item.buttons !== undefined
213222
) {
214-
mynahUI.addChatItem(tabID, item)
223+
mynahUI.addChatItem(tabID, {
224+
...item,
225+
messageId: item.messageId,
226+
codeBlockActions: {
227+
'accept-diff': {
228+
id: 'accept-diff',
229+
label: 'Open Diff',
230+
icon: MynahIcons.OK_CIRCLED,
231+
data: messageData,
232+
},
233+
},
234+
})
215235
}
216236

217237
if (
@@ -400,6 +420,33 @@ export const createMynahUI = (ideApi: any, amazonQEnabled: boolean) => {
400420
content: 'Thanks for your feedback.',
401421
})
402422
},
423+
onCodeBlockActionClicked: (
424+
tabId: string,
425+
messageId: string,
426+
actionId: string,
427+
data?: string,
428+
code?: string,
429+
type?: CodeSelectionType,
430+
referenceTrackerInformation?: ReferenceTrackerInformation[],
431+
eventId?: string,
432+
codeBlockIndex?: number,
433+
totalCodeBlocks?: number
434+
) => {
435+
if (actionId === 'accept-diff') {
436+
connector.onAcceptDiff(
437+
tabId,
438+
messageId,
439+
actionId,
440+
data,
441+
code,
442+
type,
443+
referenceTrackerInformation,
444+
eventId,
445+
codeBlockIndex,
446+
totalCodeBlocks
447+
)
448+
}
449+
},
403450
onCodeInsertToCursorPosition: connector.onCodeInsertToCursorPosition,
404451
onCopyCodeToClipboard: (
405452
tabId,

packages/core/src/codewhispererChat/app.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { AmazonQAppInitContext } from '../amazonq/apps/initContext'
1010
import { MessageListener } from '../amazonq/messages/messageListener'
1111
import { MessagePublisher } from '../amazonq/messages/messagePublisher'
1212
import {
13+
AcceptDiff,
1314
ChatItemFeedbackMessage,
1415
ChatItemVotedMessage,
1516
CopyCodeToClipboard,
@@ -34,6 +35,7 @@ export function init(appContext: AmazonQAppInitContext) {
3435
processTabClosedMessage: new EventEmitter<TabClosedMessage>(),
3536
processTabChangedMessage: new EventEmitter<TabChangedMessage>(),
3637
processInsertCodeAtCursorPosition: new EventEmitter<InsertCodeAtCursorPosition>(),
38+
processAcceptDiff: new EventEmitter<AcceptDiff>(),
3739
processCopyCodeToClipboard: new EventEmitter<CopyCodeToClipboard>(),
3840
processContextMenuCommand: new EventEmitter<EditorContextCommand>(),
3941
processTriggerTabIDReceived: new EventEmitter<TriggerTabIDReceived>(),
@@ -62,6 +64,7 @@ export function init(appContext: AmazonQAppInitContext) {
6264
processInsertCodeAtCursorPosition: new MessageListener<InsertCodeAtCursorPosition>(
6365
cwChatControllerEventEmitters.processInsertCodeAtCursorPosition
6466
),
67+
processAcceptDiff: new MessageListener<AcceptDiff>(cwChatControllerEventEmitters.processAcceptDiff),
6568
processCopyCodeToClipboard: new MessageListener<CopyCodeToClipboard>(
6669
cwChatControllerEventEmitters.processCopyCodeToClipboard
6770
),
@@ -108,6 +111,7 @@ export function init(appContext: AmazonQAppInitContext) {
108111
processInsertCodeAtCursorPosition: new MessagePublisher<InsertCodeAtCursorPosition>(
109112
cwChatControllerEventEmitters.processInsertCodeAtCursorPosition
110113
),
114+
processAcceptDiff: new MessagePublisher<AcceptDiff>(cwChatControllerEventEmitters.processAcceptDiff),
111115
processCopyCodeToClipboard: new MessagePublisher<CopyCodeToClipboard>(
112116
cwChatControllerEventEmitters.processCopyCodeToClipboard
113117
),

0 commit comments

Comments
 (0)