Skip to content
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

Code Actions - Add fix all support #6310

Merged
merged 10 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions l10n/bundle.l10n.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
"Choose and set default": "Choose and set default",
"Do not load any": "Do not load any",
"C# configuration has changed. Would you like to reload the window to apply your changes?": "C# configuration has changed. Would you like to reload the window to apply your changes?",
"Pick a fix all scope": "Pick a fix all scope",
"pipeArgs must be a string or a string array type": "pipeArgs must be a string or a string array type",
"Name not defined in current configuration.": "Name not defined in current configuration.",
"Configuration \"{0}\" in launch.json does not have a {1} argument with {2} for remote process listing.": "Configuration \"{0}\" in launch.json does not have a {1} argument with {2} for remote process listing.",
Expand Down
67 changes: 67 additions & 0 deletions src/lsptoolshost/fixAllCodeAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import * as RoslynProtocol from './roslynProtocol';
import { LSPAny } from 'vscode-languageserver-protocol';
import { RoslynLanguageServer } from './roslynLanguageServer';
import { URIConverter, createConverter } from 'vscode-languageclient/lib/common/protocolConverter';
import { UriConverter } from './uriConverter';

export function registerCodeActionFixAllCommands(
context: vscode.ExtensionContext,
languageServer: RoslynLanguageServer
) {
context.subscriptions.push(
vscode.commands.registerCommand(
'roslyn.client.fixAllCodeAction',
async (request): Promise<void> => registerFixAllResolveCodeAction(languageServer, request)
)
);
}

async function registerFixAllResolveCodeAction(languageServer: RoslynLanguageServer, codeActionData: any) {
if (codeActionData) {
const data = <LSPAny>codeActionData;
const result = await vscode.window.showQuickPick(data.FixAllFlavors, {
placeHolder: vscode.l10n.t('Pick a fix all scope'),
});

let fixAllEdit = new vscode.WorkspaceEdit();
await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: 'Fix All Code Action',
cancellable: true,
},
async (_, token) => {
if (result) {
const fixAllCodeAction: RoslynProtocol.RoslynFixAllCodeAction = {
title: data.UniqueIdentifier,
data: data,
scope: result,
};

const response = await languageServer.sendRequest(
RoslynProtocol.CodeActionFixAllResolveRequest.type,
fixAllCodeAction,
token
);

if (response.edit) {
const uriConverter: URIConverter = (value: string): vscode.Uri =>
UriConverter.deserialize(value);
const protocolConverter = createConverter(uriConverter, true, true);
fixAllEdit = await protocolConverter.asWorkspaceEdit(response.edit);
}
}
}
);

if (!(await vscode.workspace.applyEdit(fixAllEdit))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the apply edit should go inside the progress as well. I think it won't be cancellable because you don't pass in the cancellation token

throw new Error('Tried to insert multiple code action edits, but an error occurred.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test this to make sure the error is visible (hopefully in the C# output window). If not you may need to manually write it there via passing in the output channel

}
}
}
43 changes: 42 additions & 1 deletion src/lsptoolshost/roslynLanguageServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { RoslynLanguageServerEvents } from './languageServerEvents';
import { registerShowToastNotification } from './showToastNotification';
import { registerRazorCommands } from './razorCommands';
import { registerOnAutoInsert } from './onAutoInsert';
import { registerCodeActionFixAllCommands } from './fixAllCodeAction';

let _channel: vscode.OutputChannel;
let _traceChannel: vscode.OutputChannel;
Expand Down Expand Up @@ -202,6 +203,46 @@ export class RoslynLanguageServer {
workspace: {
configuration: (params) => readConfigurations(params),
},
// resolveCodeAction: async (codeAction, token, next) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should remove

// const lspCodeAction = <CodeAction>codeAction;
// const data = lspCodeAction.data;
// if (data.FixAllFlavors) {
// const result = await vscode.window.showQuickPick(data.FixAllFlavors, {
// placeHolder: 'Pick a fix all scope',
// });

// if (result) {
// const fixAllCodeAction: RoslynProtocol.RoslynFixAllCodeAction = {
// title: lspCodeAction.title,
// edit: lspCodeAction.edit,
// data: data,
// scope: result,
// };

// const response = await _languageServer.sendRequest(
// RoslynProtocol.CodeActionFixAllResolveRequest.type,
// fixAllCodeAction,
// token
// );

// if (response.edit) {
// const uriConverter: URIConverter = (value: string): vscode.Uri =>
// UriConverter.deserialize(value);
// const protocolConverter = createConverter(uriConverter, true, true);
// const result = await protocolConverter.asWorkspaceEdit(response.edit);

// if (!(await vscode.workspace.applyEdit(result))) {
// throw new Error(
// 'Tried to insert multiple code action edits, but an error occurred.'
// );
// }
// }
// console.log(response);
// }
// } else {
// return await next(codeAction, token);
// }
// },
},
};

Expand Down Expand Up @@ -745,7 +786,7 @@ export async function activateRoslynLanguageServer(

// Register any commands that need to be handled by the extension.
registerCommands(context, languageServer, optionProvider, hostExecutableResolver, _channel);

registerCodeActionFixAllCommands(context, languageServer);
registerRazorCommands(context, languageServer);

registerUnitTestingCommands(context, languageServer, dotnetTestChannel);
Expand Down
11 changes: 11 additions & 0 deletions src/lsptoolshost/roslynProtocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { Command } from 'vscode';
import * as lsp from 'vscode-languageserver-protocol';
import { CodeAction } from 'vscode-languageserver-protocol';
import { ProjectConfigurationMessage } from '../shared/projectConfiguration';

export interface WorkspaceDebugConfigurationParams {
Expand Down Expand Up @@ -136,6 +137,10 @@ export interface BuildOnlyDiagnosticIdsResult {
ids: string[];
}

export interface RoslynFixAllCodeAction extends CodeAction {
scope: string;
}

export namespace WorkspaceDebugConfigurationRequest {
export const method = 'workspace/debugConfiguration';
export const messageDirection: lsp.MessageDirection = lsp.MessageDirection.clientToServer;
Expand Down Expand Up @@ -209,3 +214,9 @@ export namespace BuildOnlyDiagnosticIdsRequest {
export const messageDirection: lsp.MessageDirection = lsp.MessageDirection.clientToServer;
export const type = new lsp.RequestType0<BuildOnlyDiagnosticIdsResult, void>(method);
}

export namespace CodeActionFixAllResolveRequest {
export const method = 'codeAction/resolveFixAll';
export const messageDirection: lsp.MessageDirection = lsp.MessageDirection.clientToServer;
export const type = new lsp.RequestType<RoslynFixAllCodeAction, RoslynFixAllCodeAction, void>(method);
}