-
Notifications
You must be signed in to change notification settings - Fork 734
feat(amazonq): add button to view diff in IDE #5338
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| const fileName = path.basename(right.path) | ||
|
|
||
| const diffScheme = 'amazon-q-accept-diff' | ||
| const left = Uri.parse(`${diffScheme}:${fileName}-` + randomUUID()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getNonexistentFilename may be useful
| export async function getNonexistentFilename( |
justinmk3
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
which Q team needs to review this?
bb60012 to
58f5cd5
Compare
|
This pull request modifies code in src/ but no tests were added/updated. Confirm whether tests should be added or ensure the PR description explains why tests are not required. |
58f5cd5 to
ccec026
Compare
0374d02 to
80ac383
Compare
| * @param {vscode.Selection} selection - The selection range in the document. | ||
| * @returns {vscode.Range} - The VSCode range object representing the start and end of the selection. | ||
| */ | ||
| export function getSelectionFromRange(doc: vscode.TextDocument, selection: vscode.Selection) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
packages/core/src/shared/utilities/textDocumentUtilities.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for better or worse, the "commons" concept is named shared/ in this codebase. can we avoid introducing a different name?
q-specific common modules should live in packages/core/src/shared/amazonq/ if they are truly Q-only and can't live in the more specific packages/amazonq/src/shared/
| cwsprChatHasProjectContext: this.responseWithProjectContext.get(message.messageId), | ||
| } | ||
| break | ||
| case 'view_diff': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: seems strange that this uses snake_case, acceptDiff is camelCase and the others are hyphen-words
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed thats very true. Even during development its weird.
| export const amazonQVscodeMarketplace = | ||
| 'https://marketplace.visualstudio.com/items?itemName=AmazonWebServices.amazon-q-vscode' | ||
|
|
||
| export const amazonQDiffScheme = 'amazon-q-view-diff' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we probably need a single schemes.fs file somewhere, but until we decide that, this can at least live next to the existing ones:
aws-toolkit-vscode/packages/core/src/shared/constants.ts
Lines 111 to 114 in 80ac383
| * URI scheme for CloudWatch Logs Virtual Documents | |
| */ | |
| export const CLOUDWATCH_LOGS_SCHEME = 'aws-cwl' // eslint-disable-line @typescript-eslint/naming-convention | |
| export const AWS_SCHEME = 'aws' // eslint-disable-line @typescript-eslint/naming-convention |
ae5a75d to
051dd09
Compare
59d5a71 to
a40bcb9
Compare
| */ | ||
| export const CLOUDWATCH_LOGS_SCHEME = 'aws-cwl' // eslint-disable-line @typescript-eslint/naming-convention | ||
| export const AWS_SCHEME = 'aws' // eslint-disable-line @typescript-eslint/naming-convention | ||
| export const AMAZON_Q_DIFF_SCHEME = 'amazon-q-view-diff' // eslint-disable-line @typescript-eslint/naming-convention |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eslint-disable-line was a compromise to avoid code churn, not intended to be continued for new symobls
is "view" an imporant thing to mention in the scheme name?
| export const AMAZON_Q_DIFF_SCHEME = 'amazon-q-view-diff' // eslint-disable-line @typescript-eslint/naming-convention | |
| export const amazonQDiffScheme = 'amazon-q-diff' |
| const languageId = (await vscode.workspace.openTextDocument(originalFileUri)).languageId | ||
| const tempFile = _path.parse(originalFileUri.path) | ||
| const tempFilePath = _path.join(tempDirPath, `${tempFile.name}_proposed-${id}${tempFile.ext}`) | ||
| const tempFileUri = vscode.Uri.parse(`${AMAZON_Q_DIFF_SCHEME}:${tempFilePath}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scheme should probably be a parameter, but maybe that can be revisited later.
| try { | ||
| await FeatureConfigProvider.instance.fetchFeatureConfigs() | ||
| featureConfigs = FeatureConfigProvider.getFeatureConfigs() | ||
| } catch (error) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should it not at least log a warning?
| * const map = deserializeArrayToMap(array); | ||
| * // map is now a Map object with entries: { 'key1' => 'value1', 'key2' => 'value2' } | ||
| */ | ||
| export function deserializeArrayToMap(arr: [unknown, unknown][]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very long name, and docstring. If someone is trying to understand this function, does this docstring tell them something useful that the implementation (new Map()) does not?
| export function deserializeArrayToMap(arr: [unknown, unknown][]) { | |
| export function tryNewMap(arr: [unknown, unknown][]) { |
| constructor(private uri: vscode.Uri) {} | ||
|
|
||
| provideTextDocumentContent(_uri: vscode.Uri) { | ||
| return fs.readFileSync(this.uri.fsPath, 'utf-8') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless this needs to be synchronous, do not use fs-extra. The correct fs module is in our shared folder
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the api, this method can be async. The type eventually resolves to a possible "Thenable". So you can use our built in fs module
|
|
||
| import * as _path from 'path' | ||
| import * as vscode from 'vscode' | ||
| import fs from 'fs-extra' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoid fs-extra if possible. Info in previous comment
b58d1f7 to
e0d7464
Compare
| }) | ||
| ) | ||
| } catch (error) { | ||
| getLogger().error(`Diff: Unable to open the document:`, (error as Error).message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the behavior if we were to throw instead? If this code is initially triggered in a Command, then the error will be swallowed upstream, and logged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed offline.
Display an error Notification for the user. Update the logic to throw everywhere and catch at high level and display a generic error notification.
|
|
||
| import * as _path from 'path' | ||
| import * as vscode from 'vscode' | ||
| import * as fs from 'fs' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't the shared 'fs'. Use src/shared/fs/fs.ts
| fs.mkdirSync(tempDirPath, { recursive: true }) | ||
| } | ||
| } catch (error) { | ||
| getLogger().error('Diff: Unable to create directory %s: %s', tempDirPath, (error as Error).message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the reason for swallowing the errors? Especially in a utils function we shouldn't be swallowing, unless there is a good reason to. One reason is in telemetry when we fail and record the reason for the failure, we parse the entire error object for the chain of errors and then record it there. So if we only log then all that information is lost and requires the user to report it.
Instead you could make a function like this that wraps the error with context about the specific FS call that failed: https://github.com/aws/aws-toolkit-vscode/blob/master/packages/core/src/shared/crashMonitoring.ts#L589
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking back at the I think that you should remove the try/catch and just call fs.mkdir() since its behavior is mkdirp() where it creates missing subfolders if necessary and does not throw if it already exists.
| const tempFile = _path.parse(originalFileUri.path) | ||
| const tempFilePath = _path.join(tempDirPath, `${tempFile.name}_proposed-${id}${tempFile.ext}`) | ||
| try { | ||
| if (!fs.existsSync(tempDirPath)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid sync calls since they are blocking. See the shared fs mentioned above
615332d to
bf8f4dd
Compare
| ) | ||
| } catch (error) { | ||
| void vscode.window.showInformationMessage(errorNotification) | ||
| ChatDiffError.chain(error, `Failed to Accept Diff`, { code: chatDiffCode }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to add throw
| } | ||
| } catch (error) { | ||
| void vscode.window.showInformationMessage(errorNotification) | ||
| ChatDiffError.chain(error, `Failed to Open Diff View`, { code: chatDiffCode }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to add throw
| if (!(error instanceof Error)) { | ||
| throw error | ||
| } | ||
| getLogger().error('Diff: Unable to write to file %s: %s', tempFilePath, (error as Error).message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dont need to log the error since below we will throw the error and it will be logged upstream
| throw error | ||
| } | ||
| getLogger().error('Diff: Unable to write to file %s: %s', tempFilePath, (error as Error).message) | ||
| ToolkitError.chain(error, 'Unable to write to file', { code: errorCode }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add 'throw'. Also we want this error message to give context to why the FS call failed. So in this case it should be "Failed to write to temp file"
| * const map = tryNewMap(array); | ||
| * // map is now a Map object with entries: { 'key1' => 'value1', 'key2' => 'value2' } | ||
| */ | ||
| export function tryNewMap(arr: [unknown, unknown][]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like it should live in core and since this is map related would probably make sense in core/src/shared/utilities/map
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
amazon/util doesn't look like the place for this. And, the docstring is still way too long and over-explains what could be stated as "tries to create map from x, else returns an empty map".
Also that pattern is easily generalized as tryCall<T>(...), so I don't see why we need a dedicated function for this.
155042e to
c669d06
Compare
| import { extractFileAndCodeSelectionFromMessage, fs, getErrorMsg, getIndentedCode, ToolkitError } from '../../../shared' | ||
|
|
||
| class ContentProvider implements vscode.TextDocumentContentProvider { | ||
| constructor(private uri: vscode.Uri) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: private readonly uri: ... is typically preferred. But dont bother changing in this PR
c669d06 to
63b2ed8
Compare
| "downvote", | ||
| "clickBodyLink" | ||
| "clickBodyLink", | ||
| "viewDiff" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * @param {vscode.Selection} selection - The selection range in the document. | ||
| * @returns {string} - The processed code to be applied to the document. | ||
| */ | ||
| export function getIndentedCode(message: any, doc: vscode.TextDocument, selection: vscode.Selection) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this live in packages/core/src/shared/utilities/textDocumentUtilities.ts
Add
Accept Diff&View Diffbutton to Amazon Q for auto generated code.Screen.Recording.2024-10-02.at.9.10.45.AM.mov
License
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.