Skip to content

Commit 64f196c

Browse files
committed
feat(lsp): add handler for openFileDiff notification
1 parent e1242e8 commit 64f196c

File tree

4 files changed

+87
-13
lines changed

4 files changed

+87
-13
lines changed

packages/amazonq/src/lsp/chat/messages.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,25 @@ import {
3939
ShowDocumentRequest,
4040
contextCommandsNotificationType,
4141
ContextCommandParams,
42+
openFileDiffNotificationType,
43+
OpenFileDiffParams,
4244
} from '@aws/language-server-runtimes/protocol'
4345
import { v4 as uuidv4 } from 'uuid'
4446
import * as vscode from 'vscode'
4547
import { Disposable, LanguageClient, Position, TextDocumentIdentifier } from 'vscode-languageclient'
4648
import * as jose from 'jose'
4749
import { AmazonQChatViewProvider } from './webviewProvider'
4850
import { AuthUtil } from 'aws-core-vscode/codewhisperer'
49-
import { AmazonQPromptSettings, messages } from 'aws-core-vscode/shared'
50-
import { DefaultAmazonQAppInitContext, messageDispatcher } from 'aws-core-vscode/amazonq'
51+
import {
52+
amazonQDiffScheme,
53+
AmazonQPromptSettings,
54+
messages,
55+
textDocumentUtil,
56+
amazonQTabSuffix,
57+
disposeOnEditorClose,
58+
} from 'aws-core-vscode/shared'
59+
import { ContentProvider, DefaultAmazonQAppInitContext, messageDispatcher } from 'aws-core-vscode/amazonq'
60+
import path from 'path'
5161

5262
export function registerLanguageServerEventListener(languageClient: LanguageClient, provider: AmazonQChatViewProvider) {
5363
languageClient.info(
@@ -353,6 +363,24 @@ export function registerMessageListeners(
353363
params: params,
354364
})
355365
})
366+
367+
languageClient.onNotification(openFileDiffNotificationType.method, async (params: OpenFileDiffParams) => {
368+
const uri = vscode.Uri.parse(params.originalFileUri)
369+
const tempFileUri = await textDocumentUtil.createTempFileForDiffWithContent(
370+
uri,
371+
params.fileContent ?? '',
372+
amazonQDiffScheme
373+
)
374+
const contentProvider = new ContentProvider(tempFileUri)
375+
const disposable = vscode.workspace.registerTextDocumentContentProvider(amazonQDiffScheme, contentProvider)
376+
await vscode.commands.executeCommand(
377+
'vscode.diff',
378+
uri,
379+
tempFileUri,
380+
`${path.basename(params.originalFileUri)} ${amazonQTabSuffix}`
381+
)
382+
disposeOnEditorClose(uri, disposable)
383+
})
356384
}
357385

358386
function isServerEvent(command: string) {

packages/core/src/amazonq/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export * as authConnection from '../auth/connection'
4747
export * as featureConfig from './webview/generators/featureConfig'
4848
export * as messageDispatcher from './webview/messages/messageDispatcher'
4949
import { FeatureContext } from '../shared/featureConfig'
50+
export { ContentProvider } from './commons/controllers/contentController'
5051

5152
/**
5253
* main from createMynahUI is a purely browser dependency. Due to this

packages/core/src/shared/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export * as funcUtil from './utilities/functionUtils'
5656
export { fs } from './fs/fs'
5757
export * from './handleUninstall'
5858
export { CrashMonitoring } from './crashMonitoring'
59-
export { amazonQDiffScheme } from './constants'
59+
export { amazonQDiffScheme, amazonQTabSuffix } from './constants'
6060
export * from './featureConfig'
6161
export { i18n } from './i18n-helper'
6262
export * from './icons'
@@ -74,3 +74,4 @@ export * as BaseLspInstaller from './lsp/baseLspInstaller'
7474
export * as collectionUtil from './utilities/collectionUtils'
7575
export * from './datetime'
7676
export * from './performance/marks'
77+
export { disposeOnEditorClose } from './utilities/editorUtilities'

packages/core/src/shared/utilities/textDocumentUtilities.ts

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -119,20 +119,17 @@ export async function applyChanges(doc: vscode.TextDocument, range: vscode.Range
119119
}
120120

121121
/**
122-
* Creates a temporary file for diff comparison by cloning the original file
123-
* and applying the proposed changes within the selected range.
122+
* Creates a temporary file for diff comparison by cloning the original file.
123+
* This is the base implementation used by other diff-related functions.
124124
*
125125
* @param {vscode.Uri} originalFileUri - The URI of the original file.
126-
* @param {any} message - The message object containing the proposed code changes.
127-
* @param {vscode.Selection} selection - The selection range in the document where the changes are applied.
128-
* @returns {Promise<vscode.Uri>} - A promise that resolves to the URI of the temporary file.
126+
* @param {string} scheme - The URI scheme to use for the temporary file.
127+
* @returns {Promise<{tempFileUri: vscode.Uri, doc: vscode.TextDocument}>} - A promise that resolves to the URI of the temporary file and the document.
129128
*/
130-
export async function createTempFileForDiff(
129+
async function createTempFileForDiffBase(
131130
originalFileUri: vscode.Uri,
132-
message: any,
133-
selection: vscode.Selection,
134131
scheme: string
135-
): Promise<vscode.Uri> {
132+
): Promise<{ tempFileUri: vscode.Uri; doc: vscode.TextDocument }> {
136133
const errorCode = 'createTempFile'
137134
const id = Date.now()
138135
const languageId = (await vscode.workspace.openTextDocument(originalFileUri)).languageId
@@ -152,7 +149,7 @@ export async function createTempFileForDiff(
152149
throw ToolkitError.chain(error, 'Failed to write to temp file', { code: errorCode })
153150
}
154151

155-
// Apply the proposed changes to the temp file
152+
// Open the temp file as a document
156153
const doc = await vscode.workspace.openTextDocument(tempFileUri.path)
157154
const languageIdStatus = await vscode.languages.setTextDocumentLanguage(doc, languageId)
158155
if (languageIdStatus) {
@@ -161,13 +158,60 @@ export async function createTempFileForDiff(
161158
getLogger().error('Diff: Unable to set languageId for %s to: %s', tempFileUri.fsPath, languageId)
162159
}
163160

161+
return { tempFileUri, doc }
162+
}
163+
164+
/**
165+
* Creates a temporary file for diff comparison by cloning the original file
166+
* and applying the proposed changes within the selected range.
167+
*
168+
* @param {vscode.Uri} originalFileUri - The URI of the original file.
169+
* @param {any} message - The message object containing the proposed code changes.
170+
* @param {vscode.Selection} selection - The selection range in the document where the changes are applied.
171+
* @param {string} scheme - The URI scheme to use for the temporary file.
172+
* @returns {Promise<vscode.Uri>} - A promise that resolves to the URI of the temporary file.
173+
*/
174+
export async function createTempFileForDiff(
175+
originalFileUri: vscode.Uri,
176+
message: any,
177+
selection: vscode.Selection,
178+
scheme: string
179+
): Promise<vscode.Uri> {
180+
const { tempFileUri, doc } = await createTempFileForDiffBase(originalFileUri, scheme)
181+
164182
const code = getIndentedCode(message, doc, selection)
165183
const range = getSelectionFromRange(doc, selection)
166184

167185
await applyChanges(doc, range, code)
168186
return tempFileUri
169187
}
170188

189+
/**
190+
* Creates a temporary file for diff comparison by cloning the original file
191+
* and replacing the entire content with the provided content.
192+
*
193+
* @param {vscode.Uri} originalFileUri - The URI of the original file.
194+
* @param {string} content - The content to replace the entire document with.
195+
* @param {string} scheme - The URI scheme to use for the temporary file.
196+
* @returns {Promise<vscode.Uri>} - A promise that resolves to the URI of the temporary file.
197+
*/
198+
export async function createTempFileForDiffWithContent(
199+
originalFileUri: vscode.Uri,
200+
content: string,
201+
scheme: string
202+
): Promise<vscode.Uri> {
203+
const { tempFileUri, doc } = await createTempFileForDiffBase(originalFileUri, scheme)
204+
205+
// Create a range that covers the entire document
206+
const entireDocumentRange = new vscode.Range(
207+
new vscode.Position(0, 0),
208+
new vscode.Position(doc.lineCount - 1, doc.lineAt(doc.lineCount - 1).text.length)
209+
)
210+
211+
await applyChanges(doc, entireDocumentRange, content)
212+
return tempFileUri
213+
}
214+
171215
/**
172216
* Indents the given code based on the current document's indentation at the selection start.
173217
*

0 commit comments

Comments
 (0)