private void ApplyChange_OnUIThread( Document formattedDocument, ITextBuffer textBuffer, IBackgroundWorkIndicatorContext waitContext) { _threadingContext.ThrowIfNotOnUIThread(); var cancellationToken = waitContext.UserCancellationToken; using var undoTransaction = _undoManager.GetTextBufferUndoManager(textBuffer).TextBufferUndoHistory.CreateTransaction("Extract Method"); // We're about to make an edit ourselves. so disable the cancellation that happens on editing. waitContext.CancelOnEdit = false; formattedDocument.Project.Solution.Workspace.ApplyDocumentChanges(formattedDocument, cancellationToken); // apply changes undoTransaction.Complete(); }
private async Task ExecuteWorkerAsync( ITextView view, ITextBuffer textBuffer, TextSpan span, IBackgroundWorkIndicatorContext waitContext) { _threadingContext.ThrowIfNotOnUIThread(); var cancellationToken = waitContext.UserCancellationToken; var document = await textBuffer.CurrentSnapshot.GetFullyLoadedOpenDocumentInCurrentContextWithChangesAsync(waitContext).ConfigureAwait(false); if (document is null) { return; } var options = await document.GetExtractMethodGenerationOptionsAsync(_globalOptions, cancellationToken).ConfigureAwait(false); var result = await ExtractMethodService.ExtractMethodAsync( document, span, localFunction : false, options, cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(result); if (!result.Succeeded && !result.SucceededWithSuggestion) { // if it failed due to out/ref parameter in async method, try it with different option var newResult = await TryWithoutMakingValueTypesRefAsync( document, span, result, options, cancellationToken).ConfigureAwait(false); if (newResult != null) { var notificationService = document.Project.Solution.Workspace.Services.GetService <INotificationService>(); if (notificationService != null) { // We are about to show a modal UI dialog so we should take over the command execution // wait context. That means the command system won't attempt to show its own wait dialog // and also will take it into consideration when measuring command handling duration. await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); if (!notificationService.ConfirmMessageBox( EditorFeaturesResources.Extract_method_encountered_the_following_issues + Environment.NewLine + Environment.NewLine + string.Join(Environment.NewLine, result.Reasons) + Environment.NewLine + Environment.NewLine + EditorFeaturesResources.We_can_fix_the_error_by_not_making_struct_out_ref_parameter_s_Do_you_want_to_proceed, title: EditorFeaturesResources.Extract_Method, severity: NotificationSeverity.Error)) { // We handled the command, displayed a notification and did not produce code. return; } await TaskScheduler.Default; } // reset result result = newResult; } else if (await TryNotifyFailureToUserAsync(document, result, cancellationToken).ConfigureAwait(false)) { // We handled the command, displayed a notification and did not produce code. return; } } var cleanupOptions = await document.GetCodeCleanupOptionsAsync(_globalOptions, cancellationToken).ConfigureAwait(false); var(formattedDocument, methodNameAtInvocation) = await result.GetFormattedDocumentAsync(cleanupOptions, cancellationToken).ConfigureAwait(false); await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); ApplyChange_OnUIThread(formattedDocument, textBuffer, waitContext); // start inline rename to allow the user to change the name if they want. var textSnapshot = textBuffer.CurrentSnapshot; document = textSnapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document != null) { _renameService.StartInlineSession(document, methodNameAtInvocation.Span, cancellationToken); } // select invocation span view.TryMoveCaretToAndEnsureVisible(new SnapshotPoint(textSnapshot, methodNameAtInvocation.Span.End)); view.SetSelection(methodNameAtInvocation.Span.ToSnapshotSpan(textSnapshot)); }