public override async Task <object> HandleRequestAsync(LSP.ExecuteCommandParams request, RequestContext context, CancellationToken cancellationToken) { var document = context.Document; Contract.ThrowIfNull(document); var runRequest = ((JToken)request.Arguments.Single()).ToObject <CodeActionResolveData>(); Assumes.Present(runRequest); var codeActions = await CodeActionHelpers.GetCodeActionsAsync( _codeActionsCache, document, runRequest.Range, _codeFixService, _codeRefactoringService, cancellationToken).ConfigureAwait(false); var actionToRun = CodeActionHelpers.GetCodeActionToResolve(runRequest.UniqueIdentifier, codeActions); Contract.ThrowIfNull(actionToRun); var operations = await actionToRun.GetOperationsAsync(cancellationToken).ConfigureAwait(false); // TODO - This UI thread dependency should be removed. // https://github.com/dotnet/roslyn/projects/45#card-20619668 await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); foreach (var operation in operations) { operation.Apply(document.Project.Solution.Workspace, cancellationToken); } return(true); }
public override async Task <LSP.VSCodeAction> HandleRequestAsync(LSP.VSCodeAction codeAction, RequestContext context, CancellationToken cancellationToken) { var data = ((JToken)codeAction.Data).ToObject <CodeActionResolveData>(); var document = SolutionProvider.GetDocument(data.TextDocument, context.ClientName); Contract.ThrowIfNull(document); var codeActions = await CodeActionHelpers.GetCodeActionsAsync( document, _codeFixService, _codeRefactoringService, _threadingContext, data.Range, cancellationToken).ConfigureAwait(false); var codeActionToResolve = CodeActionHelpers.GetCodeActionToResolve( data.UniqueIdentifier, codeActions); Contract.ThrowIfNull(codeActionToResolve); var operations = await codeActionToResolve.GetOperationsAsync(cancellationToken).ConfigureAwait(false); if (operations.IsEmpty) { return(codeAction); } // If we have all non-ApplyChangesOperations, set up to run as command on the server // instead of using WorkspaceEdits. if (operations.All(operation => !(operation is ApplyChangesOperation))) { codeAction.Command = SetCommand(codeAction.Title, data); return(codeAction); } // TO-DO: We currently must execute code actions which add new documents on the server as commands, // since there is no LSP support for adding documents yet. In the future, we should move these actions // to execute on the client. // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/ // Add workspace edits var applyChangesOperations = operations.OfType <ApplyChangesOperation>(); if (applyChangesOperations.Any()) { using var _ = ArrayBuilder <TextDocumentEdit> .GetInstance(out var textDocumentEdits); foreach (var applyChangesOperation in applyChangesOperations) { var solution = document.Project.Solution; var changes = applyChangesOperation.ChangedSolution.GetChanges(solution); var projectChanges = changes.GetProjectChanges(); // TO-DO: If the change involves adding or removing a document, execute via command instead of WorkspaceEdit // until adding/removing documents is supported in LSP: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/ // After support is added, remove the below if-statement and add code to support adding/removing documents. var addedDocuments = projectChanges.SelectMany( pc => pc.GetAddedDocuments().Concat(pc.GetAddedAdditionalDocuments().Concat(pc.GetAddedAnalyzerConfigDocuments()))); var removedDocuments = projectChanges.SelectMany( pc => pc.GetRemovedDocuments().Concat(pc.GetRemovedAdditionalDocuments().Concat(pc.GetRemovedAnalyzerConfigDocuments()))); if (addedDocuments.Any() || removedDocuments.Any()) { codeAction.Command = SetCommand(codeAction.Title, data); return(codeAction); } // TO-DO: If the change involves adding or removing a project reference, execute via command instead of // WorkspaceEdit until adding/removing project references is supported in LSP: // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1166040 var projectReferences = projectChanges.SelectMany( pc => pc.GetAddedProjectReferences().Concat(pc.GetRemovedProjectReferences())); if (projectReferences.Any()) { codeAction.Command = SetCommand(codeAction.Title, data); return(codeAction); } var changedDocuments = projectChanges.SelectMany(pc => pc.GetChangedDocuments()); var changedAnalyzerConfigDocuments = projectChanges.SelectMany(pc => pc.GetChangedAnalyzerConfigDocuments()); var changedAdditionalDocuments = projectChanges.SelectMany(pc => pc.GetChangedAdditionalDocuments()); // Changed documents await AddTextDocumentEdits( textDocumentEdits, applyChangesOperation, solution, changedDocuments, applyChangesOperation.ChangedSolution.GetDocument, solution.GetDocument, cancellationToken).ConfigureAwait(false); // Changed analyzer config documents await AddTextDocumentEdits( textDocumentEdits, applyChangesOperation, solution, changedAnalyzerConfigDocuments, applyChangesOperation.ChangedSolution.GetAnalyzerConfigDocument, solution.GetAnalyzerConfigDocument, cancellationToken).ConfigureAwait(false); // Changed additional documents await AddTextDocumentEdits( textDocumentEdits, applyChangesOperation, solution, changedAdditionalDocuments, applyChangesOperation.ChangedSolution.GetAdditionalDocument, solution.GetAdditionalDocument, cancellationToken).ConfigureAwait(false); } codeAction.Edit = new LSP.WorkspaceEdit { DocumentChanges = textDocumentEdits.ToArray() }; } return(codeAction);