Skip to content

Commit bb60012

Browse files
committed
feat(amazonq): add button to accept code changes in diff view
1 parent 66f55b1 commit bb60012

File tree

13 files changed

+222
-41
lines changed

13 files changed

+222
-41
lines changed

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
5-
6-
import { Position, TextEditor, window } from 'vscode'
5+
import path from 'path'
6+
import { commands, Position, TextEditor, Uri, window, workspace } from 'vscode'
77
import { getLogger } from '../../../shared/logger'
8+
import { randomUUID } from '../../../common/crypto'
89

910
export class EditorContentController {
1011
public insertTextAtCursorPosition(
@@ -30,4 +31,24 @@ export class EditorContentController {
3031
)
3132
}
3233
}
34+
35+
public async acceptDiff(message: any) {
36+
const { filePath } = message?.context?.activeFileContext || {}
37+
if (filePath && message?.code?.trim().length > 0) {
38+
const right = Uri.file(filePath) // Existing File to Write
39+
const fileName = path.basename(right.path)
40+
41+
const diffScheme = 'amazon-q-accept-diff'
42+
const left = Uri.parse(`${diffScheme}:${fileName}-` + randomUUID())
43+
class LeftContentProvider {
44+
provideTextDocumentContent(_uri: Uri) {
45+
return message.code
46+
}
47+
}
48+
const leftContentProvider = new LeftContentProvider()
49+
void workspace.registerTextDocumentContentProvider(diffScheme, leftContentProvider)
50+
51+
await commands.executeCommand('vscode.diff', left, right, `${fileName} (Generated by Amazon Q)`)
52+
}
53+
}
3354
}

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'
@@ -179,7 +188,7 @@ export const createMynahUI = (ideApi: any, amazonQEnabled: boolean) => {
179188
} as ChatItem)
180189
}
181190
},
182-
onChatAnswerReceived: (tabID: string, item: ChatItem) => {
191+
onChatAnswerReceived: (tabID: string, item: ChatItem, messageData: any) => {
183192
if (item.type === ChatItemType.ANSWER_PART || item.type === ChatItemType.CODE_RESULT) {
184193
mynahUI.updateLastChatAnswer(tabID, {
185194
...(item.messageId !== undefined ? { messageId: item.messageId } : {}),
@@ -201,7 +210,18 @@ export const createMynahUI = (ideApi: any, amazonQEnabled: boolean) => {
201210
item.formItems !== undefined ||
202211
item.buttons !== undefined
203212
) {
204-
mynahUI.addChatItem(tabID, item)
213+
mynahUI.addChatItem(tabID, {
214+
...item,
215+
messageId: item.messageId,
216+
codeBlockActions: {
217+
'accept-diff': {
218+
id: 'accept-diff',
219+
label: 'Accept Diff',
220+
icon: MynahIcons.OK_CIRCLED,
221+
data: messageData,
222+
},
223+
},
224+
})
205225
}
206226

207227
if (
@@ -390,6 +410,33 @@ export const createMynahUI = (ideApi: any, amazonQEnabled: boolean) => {
390410
content: 'Thanks for your feedback.',
391411
})
392412
},
413+
onCodeBlockActionClicked: (
414+
tabId: string,
415+
messageId: string,
416+
actionId: string,
417+
data?: string,
418+
code?: string,
419+
type?: CodeSelectionType,
420+
referenceTrackerInformation?: ReferenceTrackerInformation[],
421+
eventId?: string,
422+
codeBlockIndex?: number,
423+
totalCodeBlocks?: number
424+
) => {
425+
if (actionId === 'accept-diff') {
426+
connector.onAcceptDiff(
427+
tabId,
428+
messageId,
429+
actionId,
430+
data,
431+
code,
432+
type,
433+
referenceTrackerInformation,
434+
eventId,
435+
codeBlockIndex,
436+
totalCodeBlocks
437+
)
438+
}
439+
},
393440
onCodeInsertToCursorPosition: connector.onCodeInsertToCursorPosition,
394441
onCopyCodeToClipboard: (
395442
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)